From 8b0ddcd8ff228de2feb6398da3df9b0415171da9 Mon Sep 17 00:00:00 2001 From: Vignesh Raghunathan Date: Mon, 11 Aug 2025 17:05:45 +0200 Subject: [PATCH 01/43] Clip share constraints in 0,1 --- message_ix_models/model/water/data/demands.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/message_ix_models/model/water/data/demands.py b/message_ix_models/model/water/data/demands.py index aab331e615..55e6a5cd81 100644 --- a/message_ix_models/model/water/data/demands.py +++ b/message_ix_models/model/water/data/demands.py @@ -940,9 +940,8 @@ def add_water_availability(context: "Context") -> dict[str, pd.DataFrame]: * 0.95, # 0.95 buffer factor to avoid numerical error unit="-", ) - df_share["value"] = df_share["value"].fillna(0) - + df_share["value"] = np.clip(df_share["value"], 0, 1) results["share_commodity_lo"] = df_share return results From c7842c3d680c5dca795bcc03d0f580fed7f5de16 Mon Sep 17 00:00:00 2001 From: Vignesh Raghunathan Date: Mon, 11 Aug 2025 17:20:26 +0200 Subject: [PATCH 02/43] Add tests to document bugs --- .../model/water/data/test_infrastructure.py | 430 +++++++++++++----- 1 file changed, 305 insertions(+), 125 deletions(-) diff --git a/message_ix_models/tests/model/water/data/test_infrastructure.py b/message_ix_models/tests/model/water/data/test_infrastructure.py index c1665e1c85..dbb4478298 100644 --- a/message_ix_models/tests/model/water/data/test_infrastructure.py +++ b/message_ix_models/tests/model/water/data/test_infrastructure.py @@ -9,20 +9,26 @@ ) -# NB: This also tests start_creating_input_dataframe() and prepare_input_dataframe() -# from the same file since they are called by add_infrastructure_techs() -@pytest.mark.parametrize("SDG", ["baseline", "not_baseline"]) -def test_add_infrastructure_techs(test_context, SDG, request): - # FIXME You probably want this to be part of a common setup rather than writing - # something like this for every test - test_context.SDG = SDG +@pytest.fixture(scope="function") +def infrastructure_test_data(test_context, request): + """Common fixture for water infrastructure tests.""" + # Extract SDG parameter from the test request + sdg_param = ( + getattr(request, "param", "baseline") + if hasattr(request, "param") + else "baseline" + ) + + # Setup test context + test_context.SDG = sdg_param test_context.time = "year" test_context.type_reg = "country" - test_context.regions = "ZMB" + test_context.regions = "R12" nodes = get_codes(f"node/{test_context.regions}") nodes = list(map(str, nodes[nodes.index("World")].child)) test_context.map_ISO_c = {test_context.regions: nodes[0]} + # Create scenario mp = test_context.get_platform() scenario_info = { "mp": mp, @@ -34,60 +40,89 @@ def test_add_infrastructure_techs(test_context, SDG, request): s.add_horizon(year=[2020, 2030, 2040]) s.add_set("technology", ["tech1", "tech2"]) s.add_set("year", [2020, 2030, 2040]) - s.commit(comment="basic water add_infrastructure_techs test model") test_context.set_scenario(s) - - # FIXME same as above test_context["water build info"] = ScenarioInfo(s) - # Call the function to be tested + # Call the function and return results result = add_infrastructure_techs(context=test_context) - # Assert the results - assert isinstance(result, dict) - assert "input" in result - assert "output" in result - assert all( - col in result["input"].columns - for col in [ - "technology", - "value", - "unit", - "level", - "commodity", - "mode", - "time", - "time_origin", - "node_origin", - "node_loc", - "year_vtg", - "year_act", - ] + return {"result": result, "sdg": sdg_param, "context": test_context} + + +# ============================================================================= +# HELPER FUNCTIONS +# ============================================================================= + + +def validate_data_quality(result, sdg): + """Validate basic data structure, integrity, and configuration-specific behavior.""" + # Basic structure checks + assert isinstance(result, dict), "Result must be a dictionary" + assert "input" in result, "Result must contain 'input' key" + assert "output" in result, "Result must contain 'output' key" + + # Required columns for input DataFrame + input_required_cols = [ + "technology", + "value", + "unit", + "level", + "commodity", + "mode", + "time", + "time_origin", + "node_origin", + "node_loc", + "year_vtg", + "year_act", + ] + assert all(col in result["input"].columns for col in input_required_cols), ( + f"Input DataFrame missing required columns: {set(input_required_cols) - set(result['input'].columns)}" ) - # Check for NaN values in input DataFrame + # Required columns for output DataFrame + output_required_cols = [ + "technology", + "value", + "unit", + "level", + "commodity", + "mode", + "time", + "time_dest", + "node_loc", + "node_dest", + "year_vtg", + "year_act", + ] + assert all(col in result["output"].columns for col in output_required_cols), ( + f"Output DataFrame missing required columns: {set(output_required_cols) - set(result['output'].columns)}" + ) + + # Data integrity checks assert not result["input"]["value"].isna().any(), ( "Input DataFrame contains NaN values" ) - - # Check for NaN values in output DataFrame assert not result["output"]["value"].isna().any(), ( "Output DataFrame contains NaN values" ) - # Check that time values are not individual characters (common bug) + # Time format validation (no single-character time values) input_time_values = result["input"]["time"].unique() - assert not any(len(str(val)) == 1 for val in input_time_values), ( - f"Input DataFrame contains time values: {input_time_values}. " + invalid_input_times = [val for val in input_time_values if len(str(val)) == 1] + assert not invalid_input_times, ( + f"Input DataFrame contains invalid time values: {invalid_input_times}" ) output_time_values = result["output"]["time"].unique() - assert not any(len(str(val)) == 1 for val in output_time_values), ( - f"Output DataFrame contains time values: {output_time_values}. " + invalid_output_times = [val for val in output_time_values if len(str(val)) == 1] + assert not invalid_output_times, ( + f"Output DataFrame contains invalid time values: {invalid_output_times}" ) + # Duplicate detection input_duplicates = result["input"].duplicated().sum() assert input_duplicates == 0, ( f"Input DataFrame contains {input_duplicates} duplicate rows" @@ -98,23 +133,229 @@ def test_add_infrastructure_techs(test_context, SDG, request): f"Output DataFrame contains {output_duplicates} duplicate rows" ) - assert all( - col in result["output"].columns - for col in [ - "technology", - "value", - "unit", - "level", - "commodity", - "mode", - "time", - "time_dest", - "node_loc", - "node_dest", - "year_vtg", - "year_act", - ] + # Configuration-specific validation (baseline mode should have both M1 and Mf modes) + if sdg == "baseline": + output_df = result["output"] + tech_mode_counts = output_df.groupby("technology")["mode"].nunique() + techs_with_both_modes = tech_mode_counts[tech_mode_counts == 2] + + dist_techs = {"rural_t_d", "urban_t_d"} + dist_techs_in_output = set(output_df["technology"].unique()).intersection( + dist_techs + ) + + if dist_techs_in_output: + dist_with_both_modes = set(techs_with_both_modes.index).intersection( + dist_techs_in_output + ) + assert dist_with_both_modes, ( + f"Baseline mode data overwrite detected: No distribution technologies have both M1 and Mf modes. " + f"Distribution techs: {dist_techs_in_output}, techs with both modes: {set(techs_with_both_modes.index)}" + ) + + +def check_completeness(result, sdg): + """Check that all expected technologies and data pairings are complete.""" + expected_dist_techs = { + "urban_t_d", + "urban_unconnected", + "industry_unconnected", + "rural_t_d", + "rural_unconnected", + } + + # Technology completeness + input_techs = set(result["input"]["technology"].unique()) + output_techs = set(result["output"]["technology"].unique()) + + missing_dist_input = expected_dist_techs - input_techs + assert not missing_dist_input, ( + f"Distribution technologies missing from input: {missing_dist_input}" + ) + + critical_dist_techs = {"urban_t_d", "rural_t_d"} + missing_critical_output = critical_dist_techs - output_techs + assert not missing_critical_output, ( + f"Critical distribution technologies missing from output: {missing_critical_output}" + ) + + # Electric/non-electric pairing + elec_techs = set( + result["input"][result["input"]["commodity"] == "electr"]["technology"].unique() + ) + non_elec_techs = set( + result["input"][result["input"]["commodity"] != "electr"]["technology"].unique() ) + missing_non_elec = elec_techs - non_elec_techs + assert not missing_non_elec, ( + f"Technologies with electricity input missing non-electric input: {missing_non_elec}" + ) + + # Input/output mode pairing + output_tech_modes = { + (row["technology"], row["mode"]) for _, row in result["output"].iterrows() + } + input_tech_modes = { + (row["technology"], row["mode"]) for _, row in result["input"].iterrows() + } + missing_inputs = output_tech_modes - input_tech_modes + + if missing_inputs: + missing_by_mode = {} + for tech, mode in missing_inputs: + missing_by_mode.setdefault(mode, []).append(tech) + + error_details = "\n".join( + [f" {mode} mode: {techs}" for mode, techs in missing_by_mode.items()] + ) + error_msg = f"Technologies with output modes missing corresponding input modes:\n{error_details}" + + if "Mf" in missing_by_mode: + error_msg += f"\nCRITICAL: Missing Mf mode inputs detected in {sdg} mode: {missing_by_mode['Mf']}" + + assert False, error_msg + + # Even processing validation (early return bug detection) + if sdg != "baseline" and len(expected_dist_techs.intersection(input_techs)) > 1: + dist_tech_counts = result["input"]["technology"].value_counts() + dist_counts = [ + dist_tech_counts.get(tech, 0) + for tech in expected_dist_techs + if tech in input_techs + ] + + if len(dist_counts) > 1: + min_count, max_count = min(dist_counts), max(dist_counts) + if min_count > 0 and max_count > min_count * 2: + tech_count_details = { + tech: dist_tech_counts.get(tech, 0) for tech in expected_dist_techs + } + assert False, ( + f"Uneven distribution tech processing (early return bug): {tech_count_details}" + ) + + +def verify_parameter_consistency(result, sdg): + """Verify parameter values are technology-specific and mode consistency is maintained.""" + input_techs = set(result["input"]["technology"].unique()) + output_techs = set(result["output"]["technology"].unique()) + common_techs = input_techs.intersection(output_techs) + + # Mode consistency between input and output + expected_modes = {"M1", "Mf"} if sdg == "baseline" else {"Mf"} + + for tech in common_techs: + input_modes = set( + result["input"][result["input"]["technology"] == tech]["mode"].unique() + ) + output_modes = set( + result["output"][result["output"]["technology"] == tech]["mode"].unique() + ) + + assert input_modes == expected_modes, ( + f"Technology {tech} has incorrect input modes for {sdg} configuration. " + f"Expected: {expected_modes}, Found: {input_modes}" + ) + assert output_modes == expected_modes, ( + f"Technology {tech} has incorrect output modes for {sdg} configuration. " + f"Expected: {expected_modes}, Found: {output_modes}" + ) + + # Variable cost consistency (technology-specific values) + if "var_cost" in result: + var_cost_df = result["var_cost"] + tech_cost_patterns = {} + + for tech in var_cost_df["technology"].unique(): + tech_data = var_cost_df[var_cost_df["technology"] == tech].sort_values( + ["node_loc", "year_act"] + ) + cost_pattern = tuple(tech_data["value"].values) + tech_cost_patterns.setdefault(cost_pattern, []).append(tech) + + shared_patterns = { + pattern: techs + for pattern, techs in tech_cost_patterns.items() + if len(techs) > 1 + } + + if shared_patterns: + max_shared = max(len(techs) for techs in shared_patterns.values()) + total_techs = len(var_cost_df["technology"].unique()) + + assert max_shared / total_techs < 0.7, ( + f"Variable reference bug: {max_shared}/{total_techs} technologies have identical cost patterns" + ) + + # Technical lifetime consistency + if "technical_lifetime" in result: + lifetime_df = result["technical_lifetime"] + dist_techs = {"rural_t_d", "urban_t_d"} + available_dist_techs = dist_techs.intersection( + set(lifetime_df["technology"].unique()) + ) + non_dist_techs = set(lifetime_df["technology"].unique()) - dist_techs + + if len(available_dist_techs) >= 2 and non_dist_techs: + dist_lifetimes = [ + lifetime_df[lifetime_df["technology"] == tech]["value"].iloc[0] + for tech in available_dist_techs + ] + non_dist_lifetime = lifetime_df[ + lifetime_df["technology"] == list(non_dist_techs)[0] + ]["value"].iloc[0] + + identical_to_non_dist = sum( + 1 for lt in dist_lifetimes if lt == non_dist_lifetime + ) + + assert identical_to_non_dist < len(dist_lifetimes), ( + f"Stale variable bug: All distribution technologies have lifetime {non_dist_lifetime} " + f"identical to non-distribution technology" + ) + + +# ============================================================================= +# CONSOLIDATED TESTS +# ============================================================================= + + +@pytest.mark.parametrize( + "infrastructure_test_data", ["baseline", "not_baseline"], indirect=True +) +def test_infrastructure_data_quality(infrastructure_test_data): + """Comprehensive test for data structure, integrity, and configuration-specific behavior.""" + result = infrastructure_test_data["result"] + sdg = infrastructure_test_data["sdg"] + + validate_data_quality(result, sdg) + + +@pytest.mark.parametrize( + "infrastructure_test_data", ["baseline", "not_baseline"], indirect=True +) +def test_infrastructure_completeness(infrastructure_test_data): + """Comprehensive test for technology completeness and data pairing.""" + result = infrastructure_test_data["result"] + sdg = infrastructure_test_data["sdg"] + + check_completeness(result, sdg) + + +@pytest.mark.parametrize( + "infrastructure_test_data", ["baseline", "not_baseline"], indirect=True +) +def test_infrastructure_parameter_consistency(infrastructure_test_data): + """Comprehensive test for parameter consistency and technology-specific values.""" + result = infrastructure_test_data["result"] + sdg = infrastructure_test_data["sdg"] + + verify_parameter_consistency(result, sdg) + + +# ============================================================================= +# LEGACY DESALINATION TEST (Preserved) +# ============================================================================= def test_add_desalination(test_context, request): @@ -122,8 +363,8 @@ def test_add_desalination(test_context, request): # something like this for every test test_context.time = "year" test_context.type_reg = "global" - test_context.regions = "R11" - test_context.RCP = "7p0" + test_context.regions = "R12" + test_context.map_ISO_c = {} mp = test_context.get_platform() scenario_info = { @@ -137,7 +378,7 @@ def test_add_desalination(test_context, request): s.add_set("technology", ["tech1", "tech2"]) s.add_set("year", [2020, 2030, 2040]) - s.commit(comment="basic water add_infrastructure_techs test model") + s.commit(comment="basic water desalination test model") test_context.set_scenario(s) @@ -149,70 +390,9 @@ def test_add_desalination(test_context, request): # Assert the results assert isinstance(result, dict) - assert "input" in result assert "output" in result - assert all( - col in result["input"].columns - for col in [ - "technology", - "value", - "unit", - "level", - "commodity", - "mode", - "time", - "time_origin", - "node_origin", - "node_loc", - "year_vtg", - "year_act", - ] - ) - # Check for NaN values in input DataFrame - assert not result["input"]["value"].isna().any(), ( - "Input DataFrame contains NaN values" - ) - - # Check for NaN values in output DataFrame - assert not result["output"]["value"].isna().any(), ( - "Output DataFrame contains NaN values" - ) - - # Check that time values are not individual characters (common bug) - input_time_values = result["input"]["time"].unique() - assert not any(len(str(val)) == 1 for val in input_time_values), ( - f"Input DataFrame contains time values: {input_time_values}. " - ) - - output_time_values = result["output"]["time"].unique() - assert not any(len(str(val)) == 1 for val in output_time_values), ( - f"Output DataFrame contains time values: {output_time_values}. " - ) - - input_duplicates = result["input"].duplicated().sum() - assert input_duplicates == 0, ( - f"Input DataFrame contains {input_duplicates} duplicate rows" - ) - - output_duplicates = result["output"].duplicated().sum() - assert output_duplicates == 0, ( - f"Output DataFrame contains {output_duplicates} duplicate rows" - ) - - assert all( - col in result["output"].columns - for col in [ - "technology", - "value", - "unit", - "level", - "commodity", - "mode", - "time", - "time_dest", - "node_loc", - "node_dest", - "year_vtg", - "year_act", - ] - ) + assert "capacity_factor" in result + assert "technical_lifetime" in result + assert "inv_cost" in result + assert "fix_cost" in result + assert "input" in result From 36424ca5ccbd8e2caf27a6b9812daab805f59ca5 Mon Sep 17 00:00:00 2001 From: Vignesh Raghunathan Date: Tue, 12 Aug 2025 10:34:32 +0200 Subject: [PATCH 03/43] Consolidate tests --- .../model/water/data/test_infrastructure.py | 532 +++++++++--------- 1 file changed, 272 insertions(+), 260 deletions(-) diff --git a/message_ix_models/tests/model/water/data/test_infrastructure.py b/message_ix_models/tests/model/water/data/test_infrastructure.py index dbb4478298..5e3d08edeb 100644 --- a/message_ix_models/tests/model/water/data/test_infrastructure.py +++ b/message_ix_models/tests/model/water/data/test_infrastructure.py @@ -1,3 +1,4 @@ +import pandas as pd import pytest from message_ix import Scenario @@ -7,191 +8,228 @@ add_desalination, add_infrastructure_techs, ) +from message_ix_models.util import package_data_path -@pytest.fixture(scope="function") -def infrastructure_test_data(test_context, request): - """Common fixture for water infrastructure tests.""" - # Extract SDG parameter from the test request - sdg_param = ( - getattr(request, "param", "baseline") - if hasattr(request, "param") - else "baseline" - ) - - # Setup test context - test_context.SDG = sdg_param - test_context.time = "year" - test_context.type_reg = "country" - test_context.regions = "R12" - nodes = get_codes(f"node/{test_context.regions}") - nodes = list(map(str, nodes[nodes.index("World")].child)) - test_context.map_ISO_c = {test_context.regions: nodes[0]} - - # Create scenario - mp = test_context.get_platform() - scenario_info = { - "mp": mp, - "model": f"{request.node.name}/test water model", - "scenario": f"{request.node.name}/test water scenario", - "version": "new", +def get_technology_categories_from_source(): + """Extract technology categories directly from source data files.""" + # Get infrastructure technologies from water_distribution.csv + infra_path = package_data_path("water", "infrastructure", "water_distribution.csv") + df_infra = pd.read_csv(infra_path) + # Distribution technologies hardcoded in infrastructure.py lines 199-205 + distribution_techs = { + "urban_t_d", + "urban_unconnected", + "industry_unconnected", + "rural_t_d", + "rural_unconnected", } - s = Scenario(**scenario_info) - s.add_horizon(year=[2020, 2030, 2040]) - s.add_set("technology", ["tech1", "tech2"]) - s.add_set("year", [2020, 2030, 2040]) - s.commit(comment="basic water add_infrastructure_techs test model") - test_context.set_scenario(s) - test_context["water build info"] = ScenarioInfo(s) - - # Call the function and return results - result = add_infrastructure_techs(context=test_context) + infra_categories = { + "distribution": list( + distribution_techs.intersection(set(df_infra["tec"].dropna())) + ), + "electric": list( + df_infra[df_infra["incmd"] == "electr"]["tec"].dropna().unique() + ), + "non_electric": list( + df_infra[df_infra["incmd"] != "electr"]["tec"].dropna().unique() + ), + "all": list(df_infra["tec"].dropna().unique()), + } - return {"result": result, "sdg": sdg_param, "context": test_context} + # Get desalination technologies from desalination.csv + desal_path = package_data_path("water", "infrastructure", "desalination.csv") + df_desal = pd.read_csv(desal_path) + desal_categories = {"all": list(df_desal["tec"].dropna().unique())} -# ============================================================================= -# HELPER FUNCTIONS -# ============================================================================= + return {"infrastructure": infra_categories, "desalination": desal_categories} -def validate_data_quality(result, sdg): - """Validate basic data structure, integrity, and configuration-specific behavior.""" - # Basic structure checks - assert isinstance(result, dict), "Result must be a dictionary" - assert "input" in result, "Result must contain 'input' key" - assert "output" in result, "Result must contain 'output' key" - - # Required columns for input DataFrame - input_required_cols = [ +def _get_required_columns(function_type): + """Get required column definitions for input and output DataFrames.""" + # Common base columns for all function types + base_input_cols = [ "technology", "value", "unit", "level", "commodity", "mode", - "time", - "time_origin", - "node_origin", "node_loc", "year_vtg", "year_act", ] - assert all(col in result["input"].columns for col in input_required_cols), ( - f"Input DataFrame missing required columns: {set(input_required_cols) - set(result['input'].columns)}" - ) - # Required columns for output DataFrame - output_required_cols = [ + base_output_cols = [ "technology", "value", "unit", "level", "commodity", "mode", - "time", - "time_dest", "node_loc", - "node_dest", "year_vtg", "year_act", ] - assert all(col in result["output"].columns for col in output_required_cols), ( - f"Output DataFrame missing required columns: {set(output_required_cols) - set(result['output'].columns)}" + + if function_type == "infrastructure": + # Infrastructure-specific additions + input_required_cols = base_input_cols + ["time", "time_origin", "node_origin"] + output_required_cols = base_output_cols + ["time", "time_dest", "node_dest"] + else: # desalination + # Desalination-specific additions + input_required_cols = base_input_cols + ["time_origin", "node_origin"] + output_required_cols = base_output_cols + ["time"] + + return input_required_cols, output_required_cols + + +@pytest.mark.parametrize( + "water_function_test_data", + [ + ("infrastructure", "baseline"), + ("infrastructure", "not_baseline"), + ("desalination", None), + ], + indirect=True, +) +def test_water_data_structure(water_function_test_data): + """Test for data structure, integrity, and configuration-specific behavior.""" + data = water_function_test_data + result = data["result"] + function_type = data["function_type"] + data["sdg_config"] + + # Basic structure checks + assert isinstance(result, dict), f"{function_type}: Result must be a dictionary" + assert "input" in result, f"{function_type}: Result must contain 'input' key" + assert "output" in result, f"{function_type}: Result must contain 'output' key" + + # Get required columns based on function type + input_required_cols, output_required_cols = _get_required_columns(function_type) + + # Column validation + missing_input_cols = set(input_required_cols) - set(result["input"].columns) + assert not missing_input_cols, ( + f"{function_type}: Input DataFrame missing columns: {missing_input_cols}" + ) + + missing_output_cols = set(output_required_cols) - set(result["output"].columns) + assert not missing_output_cols, ( + f"{function_type}: Output DataFrame missing columns: {missing_output_cols}" ) # Data integrity checks assert not result["input"]["value"].isna().any(), ( - "Input DataFrame contains NaN values" + f"{function_type}: Input DataFrame contains NaN values" ) assert not result["output"]["value"].isna().any(), ( - "Output DataFrame contains NaN values" + f"{function_type}: Output DataFrame contains NaN values" ) - # Time format validation (no single-character time values) - input_time_values = result["input"]["time"].unique() + # Time format validation (catches single-character time bug) + input_time_values = ( + result["input"]["time"].unique() if "time" in result["input"].columns else [] + ) invalid_input_times = [val for val in input_time_values if len(str(val)) == 1] assert not invalid_input_times, ( - f"Input DataFrame contains invalid time values: {invalid_input_times}" + f"{function_type}: Input DataFrame has invalid time values: " + f"{invalid_input_times}" ) - output_time_values = result["output"]["time"].unique() + output_time_values = ( + result["output"]["time"].unique() if "time" in result["output"].columns else [] + ) invalid_output_times = [val for val in output_time_values if len(str(val)) == 1] assert not invalid_output_times, ( - f"Output DataFrame contains invalid time values: {invalid_output_times}" + f"{function_type}: Output DataFrame has invalid time values: " + f"{invalid_output_times}" ) # Duplicate detection input_duplicates = result["input"].duplicated().sum() assert input_duplicates == 0, ( - f"Input DataFrame contains {input_duplicates} duplicate rows" + f"{function_type}: Input DataFrame contains {input_duplicates} duplicate rows" ) output_duplicates = result["output"].duplicated().sum() assert output_duplicates == 0, ( - f"Output DataFrame contains {output_duplicates} duplicate rows" + f"{function_type}: Output DataFrame contains {output_duplicates} duplicate rows" ) - # Configuration-specific validation (baseline mode should have both M1 and Mf modes) - if sdg == "baseline": - output_df = result["output"] - tech_mode_counts = output_df.groupby("technology")["mode"].nunique() - techs_with_both_modes = tech_mode_counts[tech_mode_counts == 2] - - dist_techs = {"rural_t_d", "urban_t_d"} - dist_techs_in_output = set(output_df["technology"].unique()).intersection( - dist_techs - ) - - if dist_techs_in_output: - dist_with_both_modes = set(techs_with_both_modes.index).intersection( - dist_techs_in_output - ) - assert dist_with_both_modes, ( - f"Baseline mode data overwrite detected: No distribution technologies have both M1 and Mf modes. " - f"Distribution techs: {dist_techs_in_output}, techs with both modes: {set(techs_with_both_modes.index)}" - ) - -def check_completeness(result, sdg): - """Check that all expected technologies and data pairings are complete.""" - expected_dist_techs = { - "urban_t_d", - "urban_unconnected", - "industry_unconnected", - "rural_t_d", - "rural_unconnected", - } - - # Technology completeness +@pytest.mark.parametrize( + "water_function_test_data", + [ + ("infrastructure", "baseline"), + ("infrastructure", "not_baseline"), + ("desalination", None), + ], + indirect=True, +) +def test_water_technology(water_function_test_data): + """Test for technology completeness, data pairing, and catch early return bugs.""" + data = water_function_test_data + result = data["result"] + function_type = data["function_type"] + sdg_config = data["sdg_config"] + tech_categories = get_technology_categories_from_source()[function_type] input_techs = set(result["input"]["technology"].unique()) output_techs = set(result["output"]["technology"].unique()) - missing_dist_input = expected_dist_techs - input_techs - assert not missing_dist_input, ( - f"Distribution technologies missing from input: {missing_dist_input}" - ) - - critical_dist_techs = {"urban_t_d", "rural_t_d"} - missing_critical_output = critical_dist_techs - output_techs - assert not missing_critical_output, ( - f"Critical distribution technologies missing from output: {missing_critical_output}" - ) - - # Electric/non-electric pairing - elec_techs = set( - result["input"][result["input"]["commodity"] == "electr"]["technology"].unique() - ) - non_elec_techs = set( - result["input"][result["input"]["commodity"] != "electr"]["technology"].unique() - ) - missing_non_elec = elec_techs - non_elec_techs - assert not missing_non_elec, ( - f"Technologies with electricity input missing non-electric input: {missing_non_elec}" - ) + if function_type == "infrastructure": + # Distribution technology completeness (catches early return bug) + expected_dist_techs = set(tech_categories["distribution"]) + missing_dist_input = expected_dist_techs - input_techs + assert ( + not missing_dist_input + ), f"""{function_type}: Distribution technologies missing + from input (early return bug): {missing_dist_input}""" + + # Electric/non-electric pairing + elec_techs = set( + result["input"][result["input"]["commodity"] == "electr"][ + "technology" + ].unique() + ) + non_elec_techs = set( + result["input"][result["input"]["commodity"] != "electr"][ + "technology" + ].unique() + ) + missing_non_elec = elec_techs - non_elec_techs + assert ( + not missing_non_elec + ), f"""{function_type}: Technologies with electricity input + missing non-electric input: {missing_non_elec}""" + + # Even processing validation (early return bug detection) + if ( + sdg_config != "baseline" + and len(expected_dist_techs.intersection(input_techs)) > 1 + ): + dist_tech_counts = result["input"]["technology"].value_counts() + dist_counts = [ + dist_tech_counts.get(tech, 0) + for tech in expected_dist_techs + if tech in input_techs + ] - # Input/output mode pairing + if len(dist_counts) > 1: + min_count, max_count = min(dist_counts), max(dist_counts) + if min_count > 0 and max_count > min_count * 2: + tech_count_details = { + tech: dist_tech_counts.get(tech, 0) + for tech in expected_dist_techs + } + assert ( + False + ), f"""{function_type}: Uneven distribution tech processing + : {tech_count_details}""" + + # Input/output mode pairing (catches missing Mf inputs bug) output_tech_modes = { (row["technology"], row["mode"]) for _, row in result["output"].iterrows() } @@ -205,70 +243,71 @@ def check_completeness(result, sdg): for tech, mode in missing_inputs: missing_by_mode.setdefault(mode, []).append(tech) - error_details = "\n".join( + error_details = "\\n".join( [f" {mode} mode: {techs}" for mode, techs in missing_by_mode.items()] ) - error_msg = f"Technologies with output modes missing corresponding input modes:\n{error_details}" - - if "Mf" in missing_by_mode: - error_msg += f"\nCRITICAL: Missing Mf mode inputs detected in {sdg} mode: {missing_by_mode['Mf']}" + error_msg = f"""{function_type}: Technologies with output modes missing + corresponding input modes:\\n{error_details}""" assert False, error_msg - # Even processing validation (early return bug detection) - if sdg != "baseline" and len(expected_dist_techs.intersection(input_techs)) > 1: - dist_tech_counts = result["input"]["technology"].value_counts() - dist_counts = [ - dist_tech_counts.get(tech, 0) - for tech in expected_dist_techs - if tech in input_techs - ] - - if len(dist_counts) > 1: - min_count, max_count = min(dist_counts), max(dist_counts) - if min_count > 0 and max_count > min_count * 2: - tech_count_details = { - tech: dist_tech_counts.get(tech, 0) for tech in expected_dist_techs - } - assert False, ( - f"Uneven distribution tech processing (early return bug): {tech_count_details}" + # Mode consistency validation between input and output for infrastructure + if function_type == "infrastructure": + common_techs = input_techs.intersection(output_techs) + if common_techs: + expected_modes = {"M1", "Mf"} if sdg_config == "baseline" else {"Mf"} + + for tech in common_techs: + input_modes = set( + result["input"][result["input"]["technology"] == tech][ + "mode" + ].unique() + ) + output_modes = set( + result["output"][result["output"]["technology"] == tech][ + "mode" + ].unique() ) + assert input_modes == expected_modes, ( + f"{function_type}: Technology {tech} has incorrect input " + f"modes for {sdg_config} configuration. " + f"Expected: {expected_modes}, Found: {input_modes}" + ) + assert output_modes == expected_modes, ( + f"{function_type}: Technology {tech} has incorrect output " + f"modes for {sdg_config} configuration. " + f"Expected: {expected_modes}, Found: {output_modes}" + ) -def verify_parameter_consistency(result, sdg): - """Verify parameter values are technology-specific and mode consistency is maintained.""" - input_techs = set(result["input"]["technology"].unique()) - output_techs = set(result["output"]["technology"].unique()) - common_techs = input_techs.intersection(output_techs) - - # Mode consistency between input and output - expected_modes = {"M1", "Mf"} if sdg == "baseline" else {"Mf"} - - for tech in common_techs: - input_modes = set( - result["input"][result["input"]["technology"] == tech]["mode"].unique() - ) - output_modes = set( - result["output"][result["output"]["technology"] == tech]["mode"].unique() - ) - assert input_modes == expected_modes, ( - f"Technology {tech} has incorrect input modes for {sdg} configuration. " - f"Expected: {expected_modes}, Found: {input_modes}" - ) - assert output_modes == expected_modes, ( - f"Technology {tech} has incorrect output modes for {sdg} configuration. " - f"Expected: {expected_modes}, Found: {output_modes}" - ) - - # Variable cost consistency (technology-specific values) - if "var_cost" in result: +@pytest.mark.parametrize( + "water_function_test_data", + [ + ("infrastructure", "baseline"), + ("infrastructure", "not_baseline"), + ("desalination", None), + ], + indirect=True, +) +def test_water_parameter(water_function_test_data): + """Test for parameter consistency and technology-specific uniqueness. + + Catches variable reference bugs. + """ + data = water_function_test_data + result = data["result"] + function_type = data["function_type"] + data["sdg_config"] + + # Variable cost consistency (catches variable reference bug) + if "var_cost" in result and not result["var_cost"].empty: var_cost_df = result["var_cost"] tech_cost_patterns = {} for tech in var_cost_df["technology"].unique(): tech_data = var_cost_df[var_cost_df["technology"] == tech].sort_values( - ["node_loc", "year_act"] + [col for col in ["node_loc", "year_act"] if col in var_cost_df.columns] ) cost_pattern = tuple(tech_data["value"].values) tech_cost_patterns.setdefault(cost_pattern, []).append(tech) @@ -284,88 +323,63 @@ def verify_parameter_consistency(result, sdg): total_techs = len(var_cost_df["technology"].unique()) assert max_shared / total_techs < 0.7, ( - f"Variable reference bug: {max_shared}/{total_techs} technologies have identical cost patterns" + f"{function_type}: Variable reference bug detected - " + f"{max_shared}/{total_techs} technologies have identical cost patterns" ) - # Technical lifetime consistency - if "technical_lifetime" in result: + # Technical lifetime consistency (catches stale variable bug) + if "technical_lifetime" in result and not result["technical_lifetime"].empty: lifetime_df = result["technical_lifetime"] - dist_techs = {"rural_t_d", "urban_t_d"} - available_dist_techs = dist_techs.intersection( - set(lifetime_df["technology"].unique()) - ) - non_dist_techs = set(lifetime_df["technology"].unique()) - dist_techs - - if len(available_dist_techs) >= 2 and non_dist_techs: - dist_lifetimes = [ - lifetime_df[lifetime_df["technology"] == tech]["value"].iloc[0] - for tech in available_dist_techs - ] - non_dist_lifetime = lifetime_df[ - lifetime_df["technology"] == list(non_dist_techs)[0] - ]["value"].iloc[0] - - identical_to_non_dist = sum( - 1 for lt in dist_lifetimes if lt == non_dist_lifetime - ) - assert identical_to_non_dist < len(dist_lifetimes), ( - f"Stale variable bug: All distribution technologies have lifetime {non_dist_lifetime} " - f"identical to non-distribution technology" + if function_type == "infrastructure": + tech_categories = get_technology_categories_from_source()[function_type] + dist_techs = set(tech_categories["distribution"]) + available_dist_techs = dist_techs.intersection( + set(lifetime_df["technology"].unique()) ) + non_dist_techs = set(lifetime_df["technology"].unique()) - dist_techs + + if len(available_dist_techs) >= 2 and non_dist_techs: + dist_lifetimes = [ + lifetime_df[lifetime_df["technology"] == tech]["value"].iloc[0] + for tech in available_dist_techs + ] + non_dist_lifetime = lifetime_df[ + lifetime_df["technology"] == list(non_dist_techs)[0] + ]["value"].iloc[0] + + identical_to_non_dist = sum( + 1 for lt in dist_lifetimes if lt == non_dist_lifetime + ) + assert identical_to_non_dist < len(dist_lifetimes), ( + f"{function_type}: Stale variable bug detected - " + f"""all distribution technologies have lifetime + {non_dist_lifetime} identical to non-distribution technology""" + ) -# ============================================================================= -# CONSOLIDATED TESTS -# ============================================================================= - - -@pytest.mark.parametrize( - "infrastructure_test_data", ["baseline", "not_baseline"], indirect=True -) -def test_infrastructure_data_quality(infrastructure_test_data): - """Comprehensive test for data structure, integrity, and configuration-specific behavior.""" - result = infrastructure_test_data["result"] - sdg = infrastructure_test_data["sdg"] - - validate_data_quality(result, sdg) - - -@pytest.mark.parametrize( - "infrastructure_test_data", ["baseline", "not_baseline"], indirect=True -) -def test_infrastructure_completeness(infrastructure_test_data): - """Comprehensive test for technology completeness and data pairing.""" - result = infrastructure_test_data["result"] - sdg = infrastructure_test_data["sdg"] - - check_completeness(result, sdg) - - -@pytest.mark.parametrize( - "infrastructure_test_data", ["baseline", "not_baseline"], indirect=True -) -def test_infrastructure_parameter_consistency(infrastructure_test_data): - """Comprehensive test for parameter consistency and technology-specific values.""" - result = infrastructure_test_data["result"] - sdg = infrastructure_test_data["sdg"] - - verify_parameter_consistency(result, sdg) - - -# ============================================================================= -# LEGACY DESALINATION TEST (Preserved) -# ============================================================================= +@pytest.fixture(scope="function") +def water_function_test_data(test_context, request): + """Unified fixture for testing both infrastructure and desalination functions.""" + # Parse test parameters: (function_type, sdg_config) + function_type, sdg_config = request.param -def test_add_desalination(test_context, request): - # FIXME You probably want this to be part of a common setup rather than writing - # something like this for every test + # Setup test context + if sdg_config: + test_context.SDG = sdg_config test_context.time = "year" - test_context.type_reg = "global" + test_context.type_reg = "country" if function_type == "infrastructure" else "global" test_context.regions = "R12" - test_context.map_ISO_c = {} + nodes = get_codes(f"node/{test_context.regions}") + nodes = list(map(str, nodes[nodes.index("World")].child)) + test_context.map_ISO_c = {test_context.regions: nodes[0]} + # Add RCP for desalination + if function_type == "desalination": + test_context.RCP = "7p0" # Default RCP value + + # Create scenario mp = test_context.get_platform() scenario_info = { "mp": mp, @@ -377,22 +391,20 @@ def test_add_desalination(test_context, request): s.add_horizon(year=[2020, 2030, 2040]) s.add_set("technology", ["tech1", "tech2"]) s.add_set("year", [2020, 2030, 2040]) - - s.commit(comment="basic water desalination test model") + s.commit(comment=f"basic water {function_type} test model") test_context.set_scenario(s) - - # FIXME same as above test_context["water build info"] = ScenarioInfo(s) - # Call the function to be tested - result = add_desalination(context=test_context) - - # Assert the results - assert isinstance(result, dict) - assert "output" in result - assert "capacity_factor" in result - assert "technical_lifetime" in result - assert "inv_cost" in result - assert "fix_cost" in result - assert "input" in result + # Call appropriate function + if function_type == "infrastructure": + result = add_infrastructure_techs(context=test_context) + else: # desalination + result = add_desalination(context=test_context) + + return { + "result": result, + "function_type": function_type, + "sdg_config": sdg_config, + "context": test_context, + } From e35bcbab7d28856b7b3ef92c755ce9536134ed98 Mon Sep 17 00:00:00 2001 From: Vignesh Raghunathan Date: Tue, 12 Aug 2025 11:07:54 +0200 Subject: [PATCH 04/43] Patch M1 Mf input issue --- .../model/water/data/infrastructure.py | 86 ++++++++++++------- .../model/water/data/test_infrastructure.py | 81 +++++++++-------- 2 files changed, 103 insertions(+), 64 deletions(-) diff --git a/message_ix_models/model/water/data/infrastructure.py b/message_ix_models/model/water/data/infrastructure.py index 3f8de3a8a3..032c2fa4f6 100644 --- a/message_ix_models/model/water/data/infrastructure.py +++ b/message_ix_models/model/water/data/infrastructure.py @@ -66,7 +66,7 @@ def start_creating_input_dataframe( ) if sdg != "baseline": for index, rows in df_dist.iterrows(): - return pd.concat( + inp_df = pd.concat( [ inp_df, ( @@ -94,6 +94,7 @@ def start_creating_input_dataframe( ) else: for index, rows in df_dist.iterrows(): + # Add M1 mode input inp_df = pd.concat( [ inp_df, @@ -120,33 +121,35 @@ def start_creating_input_dataframe( ), ] ) - - return pd.concat( - [ - inp_df, - ( - make_df( - "input", - technology=rows["tec"], - value=rows["value_high"], - unit="MCM", - level=rows["inlvl"], - commodity=rows["incmd"], - mode="Mf", - ) - .pipe( - broadcast, - get_vintage_and_active_years( - scenario_info, rows["technical_lifetime_mid"] + # Add Mf mode input for baseline to match Mf output mode + inp_df = pd.concat( + [ + inp_df, + ( + make_df( + "input", + technology=rows["tec"], + value=rows["value_high"], + unit="MCM", + level=rows["inlvl"], + commodity=rows["incmd"], + mode="Mf", + ) + .pipe( + broadcast, + get_vintage_and_active_years( + scenario_info, rows["technical_lifetime_mid"] + ), + node_loc=df_node["node"], + time=sub_time, + ) + .pipe(same_node) + .pipe(same_time) ), - node_loc=df_node["node"], - time=sub_time, - ) - .pipe(same_node) - .pipe(same_time) - ), - ] - ) + ] + ) + + return inp_df def add_infrastructure_techs(context: "Context") -> dict[str, pd.DataFrame]: @@ -748,6 +751,27 @@ def add_desalination(context: "Context") -> dict[str, pd.DataFrame]: .pipe(same_time) ) + # input dataframe for extract_salinewater_basin to match M1 output mode + extract_inp_df = ( + make_df( + "input", + technology="extract_salinewater_basin", + value=1, + unit="MCM/year", + level="water_avail_basin", + commodity="salinewater_basin", + mode="M1", + ) + .pipe( + broadcast, + get_vintage_and_active_years(scenario_info, 20), + node_loc=df_node["node"], + time=pd.Series(sub_time), + ) + .pipe(same_node) + .pipe(same_time) + ) + tl = ( make_df( "technical_lifetime", @@ -782,7 +806,7 @@ def add_desalination(context: "Context") -> dict[str, pd.DataFrame]: unit="MCM/year", ) # Making negative values zero - bound_up["value"].clip(lower=0, inplace=True) + bound_up["value"] = bound_up["value"].clip(lower=0) # Bound should start from 2025 bound_up = bound_up[bound_up["year_act"] >= firstyear] @@ -818,8 +842,6 @@ def add_desalination(context: "Context") -> dict[str, pd.DataFrame]: ] ) - results["fix_cost"] = fix_cost - # Variable cost var_cost = pd.concat( [ @@ -851,6 +873,7 @@ def add_desalination(context: "Context") -> dict[str, pd.DataFrame]: # ).pipe(broadcast, year_vtg=year_wat, year_act=year_wat, node_loc=df_node["node"]) # ) + results["fix_cost"] = fix_cost results["var_cost"] = var_cost tl = pd.concat( @@ -960,6 +983,9 @@ def add_desalination(context: "Context") -> dict[str, pd.DataFrame]: ] ) + # Add extract_salinewater_basin input to match M1 output mode + inp_df = pd.concat([inp_df, extract_inp_df]) + inp_df.dropna(inplace=True) results["input"] = inp_df diff --git a/message_ix_models/tests/model/water/data/test_infrastructure.py b/message_ix_models/tests/model/water/data/test_infrastructure.py index 5e3d08edeb..01d848b9fe 100644 --- a/message_ix_models/tests/model/water/data/test_infrastructure.py +++ b/message_ix_models/tests/model/water/data/test_infrastructure.py @@ -12,7 +12,7 @@ def get_technology_categories_from_source(): - """Extract technology categories directly from source data files.""" + """Extract technology categories and cost data directly from source data files.""" # Get infrastructure technologies from water_distribution.csv infra_path = package_data_path("water", "infrastructure", "water_distribution.csv") df_infra = pd.read_csv(infra_path) @@ -36,13 +36,17 @@ def get_technology_categories_from_source(): df_infra[df_infra["incmd"] != "electr"]["tec"].dropna().unique() ), "all": list(df_infra["tec"].dropna().unique()), + "raw_data": df_infra, # Include raw data for verification } # Get desalination technologies from desalination.csv desal_path = package_data_path("water", "infrastructure", "desalination.csv") df_desal = pd.read_csv(desal_path) - desal_categories = {"all": list(df_desal["tec"].dropna().unique())} + desal_categories = { + "all": list(df_desal["tec"].dropna().unique()), + "raw_data": df_desal, # Include raw data for verification + } return {"infrastructure": infra_categories, "desalination": desal_categories} @@ -205,30 +209,6 @@ def test_water_technology(water_function_test_data): ), f"""{function_type}: Technologies with electricity input missing non-electric input: {missing_non_elec}""" - # Even processing validation (early return bug detection) - if ( - sdg_config != "baseline" - and len(expected_dist_techs.intersection(input_techs)) > 1 - ): - dist_tech_counts = result["input"]["technology"].value_counts() - dist_counts = [ - dist_tech_counts.get(tech, 0) - for tech in expected_dist_techs - if tech in input_techs - ] - - if len(dist_counts) > 1: - min_count, max_count = min(dist_counts), max(dist_counts) - if min_count > 0 and max_count > min_count * 2: - tech_count_details = { - tech: dist_tech_counts.get(tech, 0) - for tech in expected_dist_techs - } - assert ( - False - ), f"""{function_type}: Uneven distribution tech processing - : {tech_count_details}""" - # Input/output mode pairing (catches missing Mf inputs bug) output_tech_modes = { (row["technology"], row["mode"]) for _, row in result["output"].iterrows() @@ -254,10 +234,20 @@ def test_water_technology(water_function_test_data): # Mode consistency validation between input and output for infrastructure if function_type == "infrastructure": common_techs = input_techs.intersection(output_techs) - if common_techs: - expected_modes = {"M1", "Mf"} if sdg_config == "baseline" else {"Mf"} + distribution_techs = set(tech_categories["distribution"]) + if common_techs: for tech in common_techs: + # Distribution technologies should have both M1 and Mf in baseline, + # only Mf in non-baseline + # Non-distribution technologies should only have M1 + if tech in distribution_techs: + expected_modes = ( + {"M1", "Mf"} if sdg_config == "baseline" else {"Mf"} + ) + else: + expected_modes = {"M1"} + input_modes = set( result["input"][result["input"]["technology"] == tech][ "mode" @@ -299,6 +289,7 @@ def test_water_parameter(water_function_test_data): result = data["result"] function_type = data["function_type"] data["sdg_config"] + tech_categories = get_technology_categories_from_source()[function_type] # Variable cost consistency (catches variable reference bug) if "var_cost" in result and not result["var_cost"].empty: @@ -319,14 +310,36 @@ def test_water_parameter(water_function_test_data): } if shared_patterns: - max_shared = max(len(techs) for techs in shared_patterns.values()) - total_techs = len(var_cost_df["technology"].unique()) - - assert max_shared / total_techs < 0.7, ( - f"{function_type}: Variable reference bug detected - " - f"{max_shared}/{total_techs} technologies have identical cost patterns" + # Check against raw CSV data - this is required + raw_data = tech_categories.get("raw_data") + assert raw_data is not None, ( + f"{function_type}: Raw data not available for validation" + ) + assert "var_cost_mid" in raw_data.columns, ( + f"{function_type}: var_cost_mid column missing from raw data" ) + # Get unique var_cost_mid values from raw data + raw_var_costs = raw_data[["tec", "var_cost_mid"]].dropna() + unique_costs = raw_var_costs.groupby("tec")["var_cost_mid"].first() + + # If all technologies have the same cost in raw data, it's not a bug + if len(unique_costs.unique()) == 1: + # All technologies have the same cost in source data + # this is intentional + pass + else: + # Different costs in source but identical in output - this is a bug + max_shared = max(len(techs) for techs in shared_patterns.values()) + total_techs = len(var_cost_df["technology"].unique()) + + assert max_shared / total_techs < 0.7, ( + f"{function_type}: Variable reference bug detected -" + f"""{max_shared}/{total_techs} technologies + have identical cost patterns""" + f"but source data shows different costs" + ) + # Technical lifetime consistency (catches stale variable bug) if "technical_lifetime" in result and not result["technical_lifetime"].empty: lifetime_df = result["technical_lifetime"] From ca01eb64e8be866445c603b8ce8815333e809d36 Mon Sep 17 00:00:00 2001 From: Vignesh Raghunathan Date: Tue, 12 Aug 2025 11:36:00 +0200 Subject: [PATCH 05/43] Add test for M1 Mf efficiency --- .../model/water/data/test_infrastructure.py | 159 ++++++++++++------ 1 file changed, 110 insertions(+), 49 deletions(-) diff --git a/message_ix_models/tests/model/water/data/test_infrastructure.py b/message_ix_models/tests/model/water/data/test_infrastructure.py index 01d848b9fe..8f515e88fa 100644 --- a/message_ix_models/tests/model/water/data/test_infrastructure.py +++ b/message_ix_models/tests/model/water/data/test_infrastructure.py @@ -11,7 +11,7 @@ from message_ix_models.util import package_data_path -def get_technology_categories_from_source(): +def _get_technology_categories(): """Extract technology categories and cost data directly from source data files.""" # Get infrastructure technologies from water_distribution.csv infra_path = package_data_path("water", "infrastructure", "water_distribution.csv") @@ -90,6 +90,57 @@ def _get_required_columns(function_type): return input_required_cols, output_required_cols +@pytest.fixture(scope="function") +def water_function_test_data(test_context, request): + """Unified fixture for testing both infrastructure and desalination functions.""" + # Parse test parameters: (function_type, sdg_config) + function_type, sdg_config = request.param + + # Setup test context + if sdg_config: + test_context.SDG = sdg_config + test_context.time = "year" + test_context.type_reg = "country" if function_type == "infrastructure" else "global" + test_context.regions = "R12" + nodes = get_codes(f"node/{test_context.regions}") + nodes = list(map(str, nodes[nodes.index("World")].child)) + test_context.map_ISO_c = {test_context.regions: nodes[0]} + + # Add RCP for desalination + if function_type == "desalination": + test_context.RCP = "7p0" # Default RCP value + + # Create scenario + mp = test_context.get_platform() + scenario_info = { + "mp": mp, + "model": f"{request.node.name}/test water model", + "scenario": f"{request.node.name}/test water scenario", + "version": "new", + } + s = Scenario(**scenario_info) + s.add_horizon(year=[2020, 2030, 2040]) + s.add_set("technology", ["tech1", "tech2"]) + s.add_set("year", [2020, 2030, 2040]) + s.commit(comment=f"basic water {function_type} test model") + + test_context.set_scenario(s) + test_context["water build info"] = ScenarioInfo(s) + + # Call appropriate function + if function_type == "infrastructure": + result = add_infrastructure_techs(context=test_context) + else: # desalination + result = add_desalination(context=test_context) + + return { + "result": result, + "function_type": function_type, + "sdg_config": sdg_config, + "context": test_context, + } + + @pytest.mark.parametrize( "water_function_test_data", [ @@ -179,7 +230,7 @@ def test_water_technology(water_function_test_data): result = data["result"] function_type = data["function_type"] sdg_config = data["sdg_config"] - tech_categories = get_technology_categories_from_source()[function_type] + tech_categories = _get_technology_categories()[function_type] input_techs = set(result["input"]["technology"].unique()) output_techs = set(result["output"]["technology"].unique()) @@ -289,7 +340,7 @@ def test_water_parameter(water_function_test_data): result = data["result"] function_type = data["function_type"] data["sdg_config"] - tech_categories = get_technology_categories_from_source()[function_type] + tech_categories = _get_technology_categories()[function_type] # Variable cost consistency (catches variable reference bug) if "var_cost" in result and not result["var_cost"].empty: @@ -345,7 +396,7 @@ def test_water_parameter(water_function_test_data): lifetime_df = result["technical_lifetime"] if function_type == "infrastructure": - tech_categories = get_technology_categories_from_source()[function_type] + tech_categories = _get_technology_categories()[function_type] dist_techs = set(tech_categories["distribution"]) available_dist_techs = dist_techs.intersection( set(lifetime_df["technology"].unique()) @@ -372,52 +423,62 @@ def test_water_parameter(water_function_test_data): ) -@pytest.fixture(scope="function") -def water_function_test_data(test_context, request): - """Unified fixture for testing both infrastructure and desalination functions.""" - # Parse test parameters: (function_type, sdg_config) - function_type, sdg_config = request.param - - # Setup test context - if sdg_config: - test_context.SDG = sdg_config - test_context.time = "year" - test_context.type_reg = "country" if function_type == "infrastructure" else "global" - test_context.regions = "R12" - nodes = get_codes(f"node/{test_context.regions}") - nodes = list(map(str, nodes[nodes.index("World")].child)) - test_context.map_ISO_c = {test_context.regions: nodes[0]} - - # Add RCP for desalination - if function_type == "desalination": - test_context.RCP = "7p0" # Default RCP value +@pytest.mark.parametrize( + "water_function_test_data", [("infrastructure", "baseline")], indirect=True +) +def test_efficiency_mode_mapping(water_function_test_data): + """Test that Mf mode represents higher efficiency. - # Create scenario - mp = test_context.get_platform() - scenario_info = { - "mp": mp, - "model": f"{request.node.name}/test water model", - "scenario": f"{request.node.name}/test water scenario", - "version": "new", - } - s = Scenario(**scenario_info) - s.add_horizon(year=[2020, 2030, 2040]) - s.add_set("technology", ["tech1", "tech2"]) - s.add_set("year", [2020, 2030, 2040]) - s.commit(comment=f"basic water {function_type} test model") + Only tests baseline configuration where both M1 and Mf modes exist. + """ + data = water_function_test_data + result = data["result"] + function_type = data["function_type"] - test_context.set_scenario(s) - test_context["water build info"] = ScenarioInfo(s) + input_df = result["input"] + tech_categories = _get_technology_categories()[function_type] + distribution_techs = set(tech_categories["distribution"]) + + failures = [] + + # Check distribution technologies with both M1 and Mf modes + for tech in distribution_techs: + tech_inputs = input_df[input_df["technology"] == tech] + if tech_inputs.empty: + continue + + modes = set(tech_inputs["mode"].unique()) + if {"M1", "Mf"}.issubset(modes): + # Get input coefficients for both modes (non-electricity commodities) + m1_inputs = tech_inputs[ + (tech_inputs["mode"] == "M1") & (tech_inputs["commodity"] != "electr") + ] + mf_inputs = tech_inputs[ + (tech_inputs["mode"] == "Mf") & (tech_inputs["commodity"] != "electr") + ] + + if not m1_inputs.empty and not mf_inputs.empty: + m1_coeff = m1_inputs["value"].iloc[0] + mf_coeff = mf_inputs["value"].iloc[0] + + # Mf should be more efficient (lower input coefficient) + if mf_coeff >= m1_coeff: + failures.append( + { + "tech": tech, + "m1_coeff": m1_coeff, + "mf_coeff": mf_coeff, + "issue": "Mf not more efficient than M1", + } + ) - # Call appropriate function - if function_type == "infrastructure": - result = add_infrastructure_techs(context=test_context) - else: # desalination - result = add_desalination(context=test_context) + # Report findings from actual function outputs + if failures: + failure_details = "\n".join( + [ + f" {f['tech']}: M1={f['m1_coeff']}, Mf={f['mf_coeff']} - {f['issue']}" + for f in failures + ] + ) - return { - "result": result, - "function_type": function_type, - "sdg_config": sdg_config, - "context": test_context, - } + assert False, f"Efficiency mapping violations:\n{failure_details}\n\n" From 15c4ce8015203060b389c3394c9ad3724f07d310 Mon Sep 17 00:00:00 2001 From: Vignesh Raghunathan Date: Tue, 12 Aug 2025 11:43:32 +0200 Subject: [PATCH 06/43] Fix swap M1 Mf inp eff - M1 was erroneously more efficient than Mf --- .../model/water/data/infrastructure.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/message_ix_models/model/water/data/infrastructure.py b/message_ix_models/model/water/data/infrastructure.py index 032c2fa4f6..a4c0115e5c 100644 --- a/message_ix_models/model/water/data/infrastructure.py +++ b/message_ix_models/model/water/data/infrastructure.py @@ -44,7 +44,7 @@ def start_creating_input_dataframe( make_df( "input", technology=rows["tec"], - value=rows["value_mid"], + value=rows["value_high"], unit="MCM", # MCM as all non elec technology have water as input level=rows["inlvl"], @@ -73,7 +73,7 @@ def start_creating_input_dataframe( make_df( "input", technology=rows["tec"], - value=rows["value_high"], + value=rows["value_mid"], unit="MCM", level=rows["inlvl"], commodity=rows["incmd"], @@ -102,7 +102,7 @@ def start_creating_input_dataframe( make_df( "input", technology=rows["tec"], - value=rows["value_mid"], + value=rows["value_high"], unit="MCM", level=rows["inlvl"], commodity=rows["incmd"], @@ -129,7 +129,7 @@ def start_creating_input_dataframe( make_df( "input", technology=rows["tec"], - value=rows["value_high"], + value=rows["value_mid"], unit="MCM", level=rows["inlvl"], commodity=rows["incmd"], @@ -578,7 +578,7 @@ def prepare_input_dataframe( inp = make_df( "input", technology=rows["tec"], - value=rows["value_high"] * kWh_m3_TO_GWa_MCM, + value=rows["value_mid"] * kWh_m3_TO_GWa_MCM, unit="GWa/MCM", level="final", commodity="electr", @@ -601,7 +601,7 @@ def prepare_input_dataframe( inp = make_df( "input", technology=rows["tec"], - value=rows["value_high"] * kWh_m3_TO_GWa_MCM, + value=rows["value_mid"] * kWh_m3_TO_GWa_MCM, unit="GWa/MCM", level="final", commodity="electr", @@ -625,7 +625,7 @@ def prepare_input_dataframe( make_df( "input", technology=rows["tec"], - value=rows["value_mid"] * kWh_m3_TO_GWa_MCM, + value=rows["value_high"] * kWh_m3_TO_GWa_MCM, unit="GWa/MCM", level="final", commodity="electr", @@ -647,7 +647,7 @@ def prepare_input_dataframe( inp = make_df( "input", technology=rows["tec"], - value=rows["value_mid"] * kWh_m3_TO_GWa_MCM, + value=rows["value_high"] * kWh_m3_TO_GWa_MCM, unit="GWa/MCM", level="final", commodity="electr", From 07801a596888f3bd7bf8cec01909dcd8766f1a66 Mon Sep 17 00:00:00 2001 From: Vignesh Raghunathan Date: Thu, 14 Aug 2025 16:27:03 +0200 Subject: [PATCH 07/43] Consolidate test logic --- .../model/water/data/test_infrastructure.py | 338 ++++++------------ 1 file changed, 112 insertions(+), 226 deletions(-) diff --git a/message_ix_models/tests/model/water/data/test_infrastructure.py b/message_ix_models/tests/model/water/data/test_infrastructure.py index 8f515e88fa..f152405251 100644 --- a/message_ix_models/tests/model/water/data/test_infrastructure.py +++ b/message_ix_models/tests/model/water/data/test_infrastructure.py @@ -108,7 +108,7 @@ def water_function_test_data(test_context, request): # Add RCP for desalination if function_type == "desalination": - test_context.RCP = "7p0" # Default RCP value + test_context.RCP = "7p0" # Shouldn't require a param for this # Create scenario mp = test_context.get_platform() @@ -146,12 +146,25 @@ def water_function_test_data(test_context, request): [ ("infrastructure", "baseline"), ("infrastructure", "not_baseline"), - ("desalination", None), + ("desalination", "baseline"), + ("desalination", "not_baseline"), ], indirect=True, + ids=[ + "infrastructure-baseline", + "infrastructure-sdg", + "desalination-baseline", + "desalination-sdg", + ], ) -def test_water_data_structure(water_function_test_data): - """Test for data structure, integrity, and configuration-specific behavior.""" +def test_data_quality(water_function_test_data): + """Test basic data quality + Validates that the output DataFrames have: + - Required columns present + - No NaN values in the value column + - No duplicate rows + - Valid time format (not single character) + """ data = water_function_test_data result = data["result"] function_type = data["function_type"] @@ -220,12 +233,20 @@ def test_water_data_structure(water_function_test_data): [ ("infrastructure", "baseline"), ("infrastructure", "not_baseline"), - ("desalination", None), ], indirect=True, + ids=["infrastructure-baseline", "infrastructure-sdg"], ) -def test_water_technology(water_function_test_data): - """Test for technology completeness, data pairing, and catch early return bugs.""" +def test_infrastructure_modes(water_function_test_data): + """Test all M1/Mf mode requirements for infrastructure technologies. + + Validates: + - Distribution technologies have correct modes (M1+Mf for baseline, Mf only for SDG) + - Non-distribution technologies only have M1 mode + - All output modes have corresponding input modes + - Mf mode is more efficient than M1 (lower input coefficients) + - No early return bugs (all distribution techs present) + """ data = water_function_test_data result = data["result"] function_type = data["function_type"] @@ -233,34 +254,30 @@ def test_water_technology(water_function_test_data): tech_categories = _get_technology_categories()[function_type] input_techs = set(result["input"]["technology"].unique()) output_techs = set(result["output"]["technology"].unique()) + input_df = result["input"] - if function_type == "infrastructure": - # Distribution technology completeness (catches early return bug) - expected_dist_techs = set(tech_categories["distribution"]) - missing_dist_input = expected_dist_techs - input_techs - assert ( - not missing_dist_input - ), f"""{function_type}: Distribution technologies missing - from input (early return bug): {missing_dist_input}""" - - # Electric/non-electric pairing - elec_techs = set( - result["input"][result["input"]["commodity"] == "electr"][ - "technology" - ].unique() - ) - non_elec_techs = set( - result["input"][result["input"]["commodity"] != "electr"][ - "technology" - ].unique() - ) - missing_non_elec = elec_techs - non_elec_techs - assert ( - not missing_non_elec - ), f"""{function_type}: Technologies with electricity input - missing non-electric input: {missing_non_elec}""" + # Distribution technology completeness (catches early return bug) + expected_dist_techs = set(tech_categories["distribution"]) + missing_dist_input = expected_dist_techs - input_techs + assert ( + not missing_dist_input + ), f"""{function_type}: Distribution technologies missing + from input (early return bug): {missing_dist_input}""" + + # Electric/non-electric pairing + elec_techs = set( + result["input"][result["input"]["commodity"] == "electr"]["technology"].unique() + ) + non_elec_techs = set( + result["input"][result["input"]["commodity"] != "electr"]["technology"].unique() + ) + missing_non_elec = elec_techs - non_elec_techs + assert ( + not missing_non_elec + ), f"""{function_type}: Technologies with electricity input + missing non-electric input: {missing_non_elec}""" - # Input/output mode pairing (catches missing Mf inputs bug) + # Input/output mode pairing output_tech_modes = { (row["technology"], row["mode"]) for _, row in result["output"].iterrows() } @@ -283,202 +300,71 @@ def test_water_technology(water_function_test_data): assert False, error_msg # Mode consistency validation between input and output for infrastructure - if function_type == "infrastructure": - common_techs = input_techs.intersection(output_techs) - distribution_techs = set(tech_categories["distribution"]) - - if common_techs: - for tech in common_techs: - # Distribution technologies should have both M1 and Mf in baseline, - # only Mf in non-baseline - # Non-distribution technologies should only have M1 - if tech in distribution_techs: - expected_modes = ( - {"M1", "Mf"} if sdg_config == "baseline" else {"Mf"} - ) - else: - expected_modes = {"M1"} - - input_modes = set( - result["input"][result["input"]["technology"] == tech][ - "mode" - ].unique() - ) - output_modes = set( - result["output"][result["output"]["technology"] == tech][ - "mode" - ].unique() - ) - - assert input_modes == expected_modes, ( - f"{function_type}: Technology {tech} has incorrect input " - f"modes for {sdg_config} configuration. " - f"Expected: {expected_modes}, Found: {input_modes}" - ) - assert output_modes == expected_modes, ( - f"{function_type}: Technology {tech} has incorrect output " - f"modes for {sdg_config} configuration. " - f"Expected: {expected_modes}, Found: {output_modes}" - ) - - -@pytest.mark.parametrize( - "water_function_test_data", - [ - ("infrastructure", "baseline"), - ("infrastructure", "not_baseline"), - ("desalination", None), - ], - indirect=True, -) -def test_water_parameter(water_function_test_data): - """Test for parameter consistency and technology-specific uniqueness. - - Catches variable reference bugs. - """ - data = water_function_test_data - result = data["result"] - function_type = data["function_type"] - data["sdg_config"] - tech_categories = _get_technology_categories()[function_type] - - # Variable cost consistency (catches variable reference bug) - if "var_cost" in result and not result["var_cost"].empty: - var_cost_df = result["var_cost"] - tech_cost_patterns = {} - - for tech in var_cost_df["technology"].unique(): - tech_data = var_cost_df[var_cost_df["technology"] == tech].sort_values( - [col for col in ["node_loc", "year_act"] if col in var_cost_df.columns] - ) - cost_pattern = tuple(tech_data["value"].values) - tech_cost_patterns.setdefault(cost_pattern, []).append(tech) - - shared_patterns = { - pattern: techs - for pattern, techs in tech_cost_patterns.items() - if len(techs) > 1 - } - - if shared_patterns: - # Check against raw CSV data - this is required - raw_data = tech_categories.get("raw_data") - assert raw_data is not None, ( - f"{function_type}: Raw data not available for validation" - ) - assert "var_cost_mid" in raw_data.columns, ( - f"{function_type}: var_cost_mid column missing from raw data" - ) - - # Get unique var_cost_mid values from raw data - raw_var_costs = raw_data[["tec", "var_cost_mid"]].dropna() - unique_costs = raw_var_costs.groupby("tec")["var_cost_mid"].first() + common_techs = input_techs.intersection(output_techs) + distribution_techs = set(tech_categories["distribution"]) - # If all technologies have the same cost in raw data, it's not a bug - if len(unique_costs.unique()) == 1: - # All technologies have the same cost in source data - # this is intentional - pass + if common_techs: + # Single pass through technologies to get modes, coefficients, and validate + tech_data = {} + for tech in common_techs: + tech_inputs = input_df[input_df["technology"] == tech] + tech_outputs = result["output"][result["output"]["technology"] == tech] + + input_modes = set(tech_inputs["mode"].unique()) + output_modes = set(tech_outputs["mode"].unique()) + + # Get M1/Mf coefficients if both modes exist + m1_coeff = mf_coeff = None + if {"M1", "Mf"}.issubset(input_modes): + m1_data = tech_inputs[ + (tech_inputs["mode"] == "M1") + & (tech_inputs["commodity"] != "electr") + ] + mf_data = tech_inputs[ + (tech_inputs["mode"] == "Mf") + & (tech_inputs["commodity"] != "electr") + ] + if not m1_data.empty and not mf_data.empty: + m1_coeff = m1_data["value"].iloc[0] + mf_coeff = mf_data["value"].iloc[0] + + tech_data[tech] = { + "input_modes": input_modes, + "output_modes": output_modes, + "m1_coeff": m1_coeff, + "mf_coeff": mf_coeff, + } + + # Validate all technologies using collected data + for tech, data in tech_data.items(): + # Distribution technologies should have both M1 and Mf in baseline, + # only Mf in non-baseline + # Non-distribution technologies should only have M1 + if tech in distribution_techs: + expected_modes = {"M1", "Mf"} if sdg_config == "baseline" else {"Mf"} else: - # Different costs in source but identical in output - this is a bug - max_shared = max(len(techs) for techs in shared_patterns.values()) - total_techs = len(var_cost_df["technology"].unique()) - - assert max_shared / total_techs < 0.7, ( - f"{function_type}: Variable reference bug detected -" - f"""{max_shared}/{total_techs} technologies - have identical cost patterns""" - f"but source data shows different costs" - ) + expected_modes = {"M1"} - # Technical lifetime consistency (catches stale variable bug) - if "technical_lifetime" in result and not result["technical_lifetime"].empty: - lifetime_df = result["technical_lifetime"] - - if function_type == "infrastructure": - tech_categories = _get_technology_categories()[function_type] - dist_techs = set(tech_categories["distribution"]) - available_dist_techs = dist_techs.intersection( - set(lifetime_df["technology"].unique()) + assert data["input_modes"] == expected_modes, ( + f"{function_type}: Technology {tech} has incorrect input " + f"modes for {sdg_config} configuration. " + f"Expected: {expected_modes}, Found: {data['input_modes']}" + ) + assert data["output_modes"] == expected_modes, ( + f"{function_type}: Technology {tech} has incorrect output " + f"modes for {sdg_config} configuration. " + f"Expected: {expected_modes}, Found: {data['output_modes']}" ) - non_dist_techs = set(lifetime_df["technology"].unique()) - dist_techs - - if len(available_dist_techs) >= 2 and non_dist_techs: - dist_lifetimes = [ - lifetime_df[lifetime_df["technology"] == tech]["value"].iloc[0] - for tech in available_dist_techs - ] - non_dist_lifetime = lifetime_df[ - lifetime_df["technology"] == list(non_dist_techs)[0] - ]["value"].iloc[0] - - identical_to_non_dist = sum( - 1 for lt in dist_lifetimes if lt == non_dist_lifetime - ) - assert identical_to_non_dist < len(dist_lifetimes), ( - f"{function_type}: Stale variable bug detected - " - f"""all distribution technologies have lifetime - {non_dist_lifetime} identical to non-distribution technology""" + # Test efficiency: Mf should be more efficient than + # M1 for distribution techs in baseline + if ( + tech in distribution_techs + and sdg_config == "baseline" + and data["m1_coeff"] is not None + and data["mf_coeff"] is not None + ): + assert data["mf_coeff"] < data["m1_coeff"], ( + f"{function_type}: Technology {tech} - Mf < efficient than M1. " + f"M1={data['m1_coeff']}, Mf={data['mf_coeff']}" ) - - -@pytest.mark.parametrize( - "water_function_test_data", [("infrastructure", "baseline")], indirect=True -) -def test_efficiency_mode_mapping(water_function_test_data): - """Test that Mf mode represents higher efficiency. - - Only tests baseline configuration where both M1 and Mf modes exist. - """ - data = water_function_test_data - result = data["result"] - function_type = data["function_type"] - - input_df = result["input"] - tech_categories = _get_technology_categories()[function_type] - distribution_techs = set(tech_categories["distribution"]) - - failures = [] - - # Check distribution technologies with both M1 and Mf modes - for tech in distribution_techs: - tech_inputs = input_df[input_df["technology"] == tech] - if tech_inputs.empty: - continue - - modes = set(tech_inputs["mode"].unique()) - if {"M1", "Mf"}.issubset(modes): - # Get input coefficients for both modes (non-electricity commodities) - m1_inputs = tech_inputs[ - (tech_inputs["mode"] == "M1") & (tech_inputs["commodity"] != "electr") - ] - mf_inputs = tech_inputs[ - (tech_inputs["mode"] == "Mf") & (tech_inputs["commodity"] != "electr") - ] - - if not m1_inputs.empty and not mf_inputs.empty: - m1_coeff = m1_inputs["value"].iloc[0] - mf_coeff = mf_inputs["value"].iloc[0] - - # Mf should be more efficient (lower input coefficient) - if mf_coeff >= m1_coeff: - failures.append( - { - "tech": tech, - "m1_coeff": m1_coeff, - "mf_coeff": mf_coeff, - "issue": "Mf not more efficient than M1", - } - ) - - # Report findings from actual function outputs - if failures: - failure_details = "\n".join( - [ - f" {f['tech']}: M1={f['m1_coeff']}, Mf={f['mf_coeff']} - {f['issue']}" - for f in failures - ] - ) - - assert False, f"Efficiency mapping violations:\n{failure_details}\n\n" From 20529538dd8d64d9d3ceebac5c9b04809a0615d7 Mon Sep 17 00:00:00 2001 From: Vignesh Raghunathan Date: Thu, 14 Aug 2025 16:44:00 +0200 Subject: [PATCH 08/43] Set region global --- .../tests/model/water/data/test_infrastructure.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/message_ix_models/tests/model/water/data/test_infrastructure.py b/message_ix_models/tests/model/water/data/test_infrastructure.py index f152405251..5c73498547 100644 --- a/message_ix_models/tests/model/water/data/test_infrastructure.py +++ b/message_ix_models/tests/model/water/data/test_infrastructure.py @@ -100,7 +100,7 @@ def water_function_test_data(test_context, request): if sdg_config: test_context.SDG = sdg_config test_context.time = "year" - test_context.type_reg = "country" if function_type == "infrastructure" else "global" + test_context.type_reg = "global" test_context.regions = "R12" nodes = get_codes(f"node/{test_context.regions}") nodes = list(map(str, nodes[nodes.index("World")].child)) @@ -256,7 +256,7 @@ def test_infrastructure_modes(water_function_test_data): output_techs = set(result["output"]["technology"].unique()) input_df = result["input"] - # Distribution technology completeness (catches early return bug) + # Distribution technology completeness expected_dist_techs = set(tech_categories["distribution"]) missing_dist_input = expected_dist_techs - input_techs assert ( From 2dd683ee670c61fcfc57c7ef5a2f47beeb79bd4c Mon Sep 17 00:00:00 2001 From: Vignesh Raghunathan Date: Mon, 18 Aug 2025 15:05:30 +0200 Subject: [PATCH 09/43] Fix magic technology inp ratios - Value of 0.8 inp means 1 unit water for 0.8 units of input --- .../data/water/infrastructure/water_distribution.csv | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/message_ix_models/data/water/infrastructure/water_distribution.csv b/message_ix_models/data/water/infrastructure/water_distribution.csv index bdf5a5c629..881c1b71b7 100644 --- a/message_ix_models/data/water/infrastructure/water_distribution.csv +++ b/message_ix_models/data/water/infrastructure/water_distribution.csv @@ -1,14 +1,14 @@ tec,incmd,inlvl,outcmd,outlvl,value_low,value_mid,value_high,capacity_factor_low,capacity_factor_mid,capacity_factor,investment_low_high,investment_mid,investment_high,technical_lifetime_low,technical_lifetime_mid,technical_lifetime_high,fix_cost_low,fix_cost_mid,fix_cost_high,var_cost_low,var_cost_mid,var_cost_high,out_value_low,out_value_mid,out_value_high,recovery_rate_low,recovery_rate_mid,recovery_rate_high -industry_unconnected,freshwater_basin,water_supply_basin,industry_mw,final,1.0,0.8,1.0,1.0,1.0,1.0,0.0,0.0,0.0,1.0,1.0,1.0,0.0,0.0,0.0,9.323630136986303,21.6138698630137,40.684931506849324,1.0,1.0,1.0,0.0,0.0,0.0 +industry_unconnected,freshwater_basin,water_supply_basin,industry_mw,final,1.01,1.1,1.2,1.0,1.0,1.0,0.0,0.0,0.0,1.0,1.0,1.0,0.0,0.0,0.0,9.323630136986303,21.6138698630137,40.684931506849324,1.0,1.0,1.0,0.0,0.0,0.0 industry_untreated,industry_uncollected_wst,final,,,1.0,1.0,1.0,1.0,1.0,1.0,0.0,0.0,0.0,1.0,1.0,1.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0,1.0,1.0,0.0,0.0,0.0 rural_discharge,rural_collected_wst,water_treat,,,1.0,1.0,1.0,1.0,1.0,1.0,660.0,2080.0,3560.0,30.0,25.0,20.0,66.0,208.0,356.0,0.0,0.0,0.0,0.97,0.95,0.9,0.0,0.0,0.0 rural_discharge,electr,final,,,0.0,0.01484018,0.02968037,,,,,,,,,,,,,,,,,,,,, rural_recycle,rural_collected_wst,water_treat,freshwater_basin,water_supply_basin,1.0,1.0,1.0,0.95,0.9,0.85,495.0,1560.0,2670.0,40.0,30.0,25.0,49.5,156.0,267.0,0.0,0.0,0.0,0.9,0.8,0.7,0.0,0.0,0.0 rural_sewerage,electr,final,,,0.00197869,0.04303653,0.08409437,,,,,,,,,,,,,,,,,,,0.0,0.0,0.0 rural_sewerage,rural_collected_wst,final,rural_collected_wst,water_treat,1.0,1.0,1.0,1.0,1.0,1.0,870.2054794520549,1613.8356164383563,2278.3561643835615,50.0,40.0,30.0,129.45205479452054,201.36986301369862,359.58904109589037,0.0,0.0,0.0,1.0,1.0,1.0,0.0,0.0,0.0 -rural_t_d,freshwater_basin,water_supply_basin,rural_mw,final,1.0,0.9,1.0,1.0,1.0,1.0,666.027397260274,901.095890410959,2154.7945205479455,30.0,20.0,10.0,33.301369863013704,45.05479452054795,107.73972602739728,23.310958904109594,47.307534246575344,226.25342465753428,1.0,1.0,1.0,0.0,0.0,0.0 +rural_t_d,freshwater_basin,water_supply_basin,rural_mw,final,1.01,1.1,1.2,1.0,1.0,1.0,666.027397260274,901.095890410959,2154.7945205479455,30.0,20.0,10.0,33.301369863013704,45.05479452054795,107.73972602739728,23.310958904109594,47.307534246575344,226.25342465753428,1.0,1.0,1.0,0.0,0.0,0.0 rural_t_d,electr,final,,,0.00228311,0.19178082,0.38127854,,,,,,,,,,,,,,,,,,,,, -rural_unconnected,freshwater_basin,water_supply_basin,rural_disconnected,final,1.0,0.8,1.0,1.0,1.0,1.0,0.0,0.0,0.0,1.0,1.0,1.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0,1.0,1.0,0.0,0.0,0.0 +rural_unconnected,freshwater_basin,water_supply_basin,rural_disconnected,final,1.01,1.1,1.2,1.0,1.0,1.0,0.0,0.0,0.0,1.0,1.0,1.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0,1.0,1.0,0.0,0.0,0.0 rural_untreated,rural_uncollected_wst,final,,,1.0,1.0,1.0,1.0,1.0,1.0,0.0,0.0,0.0,1.0,1.0,1.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0,1.0,1.0,0.0,0.0,0.0 urban_discharge,urban_collected_wst,water_treat,,,1.0,1.0,1.0,0.95,0.9,0.85,303.0,429.0,627.0,40.0,30.0,25.0,21.0,35.0,67.0,0.0,0.0,0.0,0.95,0.9,0.85,0.0,0.0,0.0 urban_discharge,electr,final,,,0.0,0.01484018,0.02968037,,,,,,,,,,,,,,,,,,,,, @@ -16,9 +16,9 @@ urban_recycle,urban_collected_wst,water_treat,freshwater_basin,water_supply_basi urban_recycle,electr,final,,,0.091324200913242,0.1141552511415525,0.17123287671232876,,,,,,,,,,,,,,,,,,,0.0,0.0,0.0 urban_sewerage,urban_collected_wst,final,urban_collected_wst,water_treat,1.0,1.0,1.0,1.0,1.0,1.0,1160.2739726027398,2151.780821917808,3037.808219178082,50.0,40.0,30.0,290.06849315068496,537.945205479452,759.4520547945204,0.0,0.0,0.0,1.0,1.0,1.0,0.0,0.0,0.0 urban_sewerage,electr,final,,,0.00197869,0.04303653,0.08409437,,,,,,,,,,,,,,,,,,,0.0,0.0,0.0 -urban_t_d,freshwater_basin,water_supply_basin,urban_mw,final,1.0,0.9,1.0,1.0,1.0,1.0,1491.7808219178085,2766.5753424657537,3905.7534246575347,50.0,40.0,30.0,372.9452054794521,691.6438356164384,976.4383561643837,37.29452054794521,86.4554794520548,162.7397260273973,1.0,1.0,1.0,0.0,0.0,0.0 +urban_t_d,freshwater_basin,water_supply_basin,urban_mw,final,1.01,1.1,1.2,1.0,1.0,1.0,1491.7808219178085,2766.5753424657537,3905.7534246575347,50.0,40.0,30.0,372.9452054794521,691.6438356164384,976.4383561643837,37.29452054794521,86.4554794520548,162.7397260273973,1.0,1.0,1.0,0.0,0.0,0.0 urban_t_d,electr,final,,,0.00228311,0.19178082,0.38127854,,,,,,,,,,,,,,,,,,,,, -urban_unconnected,freshwater_basin,water_supply_basin,urban_disconnected,final,1.0,0.8,1.0,1.0,1.0,1.0,0.0,0.0,0.0,1.0,1.0,1.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0,1.0,1.0,0.0,0.0,0.0 +urban_unconnected,freshwater_basin,water_supply_basin,urban_disconnected,final,1.01,1.1,1.2,1.0,1.0,1.0,0.0,0.0,0.0,1.0,1.0,1.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0,1.0,1.0,0.0,0.0,0.0 urban_untreated,urban_uncollected_wst,final,,,1.0,1.0,1.0,1.0,1.0,1.0,0.0,0.0,0.0,1.0,1.0,1.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0,1.0,1.0,0.0,0.0,0.0 ,,,,,,,,,,,,,,,,,,,,,,,,,,,, ,,,,,,,,,,,,,,,,,,,,,,,,,,,, From ae19d8b0144f7e45efc8c2e0b62475a36a4eff99 Mon Sep 17 00:00:00 2001 From: Vignesh Raghunathan Date: Mon, 18 Aug 2025 16:01:23 +0200 Subject: [PATCH 10/43] Modify output coeffs to represent efficiency losses --- .../data/water/infrastructure/water_distribution.csv | 10 +++++----- message_ix_models/model/water/data/infrastructure.py | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/message_ix_models/data/water/infrastructure/water_distribution.csv b/message_ix_models/data/water/infrastructure/water_distribution.csv index 881c1b71b7..c0b4a5f856 100644 --- a/message_ix_models/data/water/infrastructure/water_distribution.csv +++ b/message_ix_models/data/water/infrastructure/water_distribution.csv @@ -1,14 +1,14 @@ tec,incmd,inlvl,outcmd,outlvl,value_low,value_mid,value_high,capacity_factor_low,capacity_factor_mid,capacity_factor,investment_low_high,investment_mid,investment_high,technical_lifetime_low,technical_lifetime_mid,technical_lifetime_high,fix_cost_low,fix_cost_mid,fix_cost_high,var_cost_low,var_cost_mid,var_cost_high,out_value_low,out_value_mid,out_value_high,recovery_rate_low,recovery_rate_mid,recovery_rate_high -industry_unconnected,freshwater_basin,water_supply_basin,industry_mw,final,1.01,1.1,1.2,1.0,1.0,1.0,0.0,0.0,0.0,1.0,1.0,1.0,0.0,0.0,0.0,9.323630136986303,21.6138698630137,40.684931506849324,1.0,1.0,1.0,0.0,0.0,0.0 +industry_unconnected,freshwater_basin,water_supply_basin,industry_mw,final,1.0,1.0,1.0,1.0,1.0,1.0,0.0,0.0,0.0,1.0,1.0,1.0,0.0,0.0,0.0,9.323630136986303,21.6138698630137,40.684931506849324,0.99,0.9,0.8,0.0,0.0,0.0 industry_untreated,industry_uncollected_wst,final,,,1.0,1.0,1.0,1.0,1.0,1.0,0.0,0.0,0.0,1.0,1.0,1.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0,1.0,1.0,0.0,0.0,0.0 rural_discharge,rural_collected_wst,water_treat,,,1.0,1.0,1.0,1.0,1.0,1.0,660.0,2080.0,3560.0,30.0,25.0,20.0,66.0,208.0,356.0,0.0,0.0,0.0,0.97,0.95,0.9,0.0,0.0,0.0 rural_discharge,electr,final,,,0.0,0.01484018,0.02968037,,,,,,,,,,,,,,,,,,,,, rural_recycle,rural_collected_wst,water_treat,freshwater_basin,water_supply_basin,1.0,1.0,1.0,0.95,0.9,0.85,495.0,1560.0,2670.0,40.0,30.0,25.0,49.5,156.0,267.0,0.0,0.0,0.0,0.9,0.8,0.7,0.0,0.0,0.0 rural_sewerage,electr,final,,,0.00197869,0.04303653,0.08409437,,,,,,,,,,,,,,,,,,,0.0,0.0,0.0 rural_sewerage,rural_collected_wst,final,rural_collected_wst,water_treat,1.0,1.0,1.0,1.0,1.0,1.0,870.2054794520549,1613.8356164383563,2278.3561643835615,50.0,40.0,30.0,129.45205479452054,201.36986301369862,359.58904109589037,0.0,0.0,0.0,1.0,1.0,1.0,0.0,0.0,0.0 -rural_t_d,freshwater_basin,water_supply_basin,rural_mw,final,1.01,1.1,1.2,1.0,1.0,1.0,666.027397260274,901.095890410959,2154.7945205479455,30.0,20.0,10.0,33.301369863013704,45.05479452054795,107.73972602739728,23.310958904109594,47.307534246575344,226.25342465753428,1.0,1.0,1.0,0.0,0.0,0.0 +rural_t_d,freshwater_basin,water_supply_basin,rural_mw,final,1.0,1.0,1.0,1.0,1.0,1.0,666.027397260274,901.095890410959,2154.7945205479455,30.0,20.0,10.0,33.301369863013704,45.05479452054795,107.73972602739728,23.310958904109594,47.307534246575344,226.25342465753428,0.99,0.9,0.8,0.0,0.0,0.0 rural_t_d,electr,final,,,0.00228311,0.19178082,0.38127854,,,,,,,,,,,,,,,,,,,,, -rural_unconnected,freshwater_basin,water_supply_basin,rural_disconnected,final,1.01,1.1,1.2,1.0,1.0,1.0,0.0,0.0,0.0,1.0,1.0,1.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0,1.0,1.0,0.0,0.0,0.0 +rural_unconnected,freshwater_basin,water_supply_basin,rural_disconnected,final,1.0,1.0,1.0,1.0,1.0,1.0,0.0,0.0,0.0,1.0,1.0,1.0,0.0,0.0,0.0,0.0,0.0,0.0,0.99,0.9,0.8,0.0,0.0,0.0 rural_untreated,rural_uncollected_wst,final,,,1.0,1.0,1.0,1.0,1.0,1.0,0.0,0.0,0.0,1.0,1.0,1.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0,1.0,1.0,0.0,0.0,0.0 urban_discharge,urban_collected_wst,water_treat,,,1.0,1.0,1.0,0.95,0.9,0.85,303.0,429.0,627.0,40.0,30.0,25.0,21.0,35.0,67.0,0.0,0.0,0.0,0.95,0.9,0.85,0.0,0.0,0.0 urban_discharge,electr,final,,,0.0,0.01484018,0.02968037,,,,,,,,,,,,,,,,,,,,, @@ -16,9 +16,9 @@ urban_recycle,urban_collected_wst,water_treat,freshwater_basin,water_supply_basi urban_recycle,electr,final,,,0.091324200913242,0.1141552511415525,0.17123287671232876,,,,,,,,,,,,,,,,,,,0.0,0.0,0.0 urban_sewerage,urban_collected_wst,final,urban_collected_wst,water_treat,1.0,1.0,1.0,1.0,1.0,1.0,1160.2739726027398,2151.780821917808,3037.808219178082,50.0,40.0,30.0,290.06849315068496,537.945205479452,759.4520547945204,0.0,0.0,0.0,1.0,1.0,1.0,0.0,0.0,0.0 urban_sewerage,electr,final,,,0.00197869,0.04303653,0.08409437,,,,,,,,,,,,,,,,,,,0.0,0.0,0.0 -urban_t_d,freshwater_basin,water_supply_basin,urban_mw,final,1.01,1.1,1.2,1.0,1.0,1.0,1491.7808219178085,2766.5753424657537,3905.7534246575347,50.0,40.0,30.0,372.9452054794521,691.6438356164384,976.4383561643837,37.29452054794521,86.4554794520548,162.7397260273973,1.0,1.0,1.0,0.0,0.0,0.0 +urban_t_d,freshwater_basin,water_supply_basin,urban_mw,final,1.0,1.0,1.0,1.0,1.0,1.0,1491.7808219178085,2766.5753424657537,3905.7534246575347,50.0,40.0,30.0,372.9452054794521,691.6438356164384,976.4383561643837,37.29452054794521,86.4554794520548,162.7397260273973,0.99,0.9,0.8,0.0,0.0,0.0 urban_t_d,electr,final,,,0.00228311,0.19178082,0.38127854,,,,,,,,,,,,,,,,,,,,, -urban_unconnected,freshwater_basin,water_supply_basin,urban_disconnected,final,1.01,1.1,1.2,1.0,1.0,1.0,0.0,0.0,0.0,1.0,1.0,1.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0,1.0,1.0,0.0,0.0,0.0 +urban_unconnected,freshwater_basin,water_supply_basin,urban_disconnected,final,1.0,1.0,1.0,1.0,1.0,1.0,0.0,0.0,0.0,1.0,1.0,1.0,0.0,0.0,0.0,0.0,0.0,0.0,0.99,0.9,0.8,0.0,0.0,0.0 urban_untreated,urban_uncollected_wst,final,,,1.0,1.0,1.0,1.0,1.0,1.0,0.0,0.0,0.0,1.0,1.0,1.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0,1.0,1.0,0.0,0.0,0.0 ,,,,,,,,,,,,,,,,,,,,,,,,,,,, ,,,,,,,,,,,,,,,,,,,,,,,,,,,, diff --git a/message_ix_models/model/water/data/infrastructure.py b/message_ix_models/model/water/data/infrastructure.py index a4c0115e5c..1adc85a675 100644 --- a/message_ix_models/model/water/data/infrastructure.py +++ b/message_ix_models/model/water/data/infrastructure.py @@ -300,7 +300,7 @@ def add_infrastructure_techs(context: "Context") -> dict[str, pd.DataFrame]: make_df( "output", technology=df_out_dist["tec"], - value=df_out_dist["out_value_mid"], + value=df_out_dist["out_value_high"], unit="MCM", level=df_out_dist["outlvl"], commodity=df_out_dist["outcmd"], From 649b3f1d18027361376817598007e01e73e40096 Mon Sep 17 00:00:00 2001 From: Vignesh Raghunathan Date: Thu, 21 Aug 2025 13:19:24 +0200 Subject: [PATCH 11/43] Raise costs fossil gw --- .../model/water/data/water_supply.py | 27 ++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/message_ix_models/model/water/data/water_supply.py b/message_ix_models/model/water/data/water_supply.py index 142dacc775..aa25769459 100644 --- a/message_ix_models/model/water/data/water_supply.py +++ b/message_ix_models/model/water/data/water_supply.py @@ -745,8 +745,8 @@ def add_water_supply(context: "Context") -> dict[str, pd.DataFrame]: make_df( "inv_cost", technology="extract_gw_fossil", - value=(54.52 * 150) * USD_KM3_TO_USD_MCM, - # assume higher as normal GW + value=7808.22 * USD_KM3_TO_USD_MCM, + # 50% higher than membrane desalination (5205.48 * 1.5) unit="USD/MCM", ).pipe(broadcast, year_vtg=year_wat, node_loc=df_node["node"]), ] @@ -757,12 +757,33 @@ def add_water_supply(context: "Context") -> dict[str, pd.DataFrame]: fix_cost = make_df( "fix_cost", technology="extract_gw_fossil", - value=300 * USD_KM3_TO_USD_MCM, # assumed + value=6780.83 * USD_KM3_TO_USD_MCM, + # 50% higher than distillation fix_cost (4520.55 * 1.5) unit="USD/MCM", ).pipe(broadcast, yv_ya_gw, node_loc=df_node["node"]) results["fix_cost"] = fix_cost + # Add variable cost for fossil groundwater to make it truly expensive + var_cost_fossil = make_df( + "var_cost", + technology="extract_gw_fossil", + value=1000 * USD_KM3_TO_USD_MCM, + # High variable cost to ensure it's only used as last resort + unit="USD/MCM", + mode="M1", + ).pipe( + broadcast, + yv_ya_gw, + node_loc=df_node["node"], + time=pd.Series(sub_time), + ) + + if "var_cost" in results: + results["var_cost"] = pd.concat([results["var_cost"], var_cost_fossil]) + else: + results["var_cost"] = var_cost_fossil + # Remove duplicates and NaN values from all DataFrames in results for key, df in results.items(): results[key] = df.dropna().drop_duplicates().reset_index(drop=True) From 5ab03567cc474628f54834f8467f5679d9283db5 Mon Sep 17 00:00:00 2001 From: Vignesh Raghunathan Date: Thu, 21 Aug 2025 13:19:49 +0200 Subject: [PATCH 12/43] Add desal bound assertion to test --- .../model/water/data/test_infrastructure.py | 369 ++++++++++++------ 1 file changed, 255 insertions(+), 114 deletions(-) diff --git a/message_ix_models/tests/model/water/data/test_infrastructure.py b/message_ix_models/tests/model/water/data/test_infrastructure.py index 5c73498547..1635cf0657 100644 --- a/message_ix_models/tests/model/water/data/test_infrastructure.py +++ b/message_ix_models/tests/model/water/data/test_infrastructure.py @@ -100,7 +100,7 @@ def water_function_test_data(test_context, request): if sdg_config: test_context.SDG = sdg_config test_context.time = "year" - test_context.type_reg = "global" + test_context.type_reg = "country" if function_type == "infrastructure" else "global" test_context.regions = "R12" nodes = get_codes(f"node/{test_context.regions}") nodes = list(map(str, nodes[nodes.index("World")].child)) @@ -108,7 +108,7 @@ def water_function_test_data(test_context, request): # Add RCP for desalination if function_type == "desalination": - test_context.RCP = "7p0" # Shouldn't require a param for this + test_context.RCP = "6p0" # Use RCP that exists in R12 data # Create scenario mp = test_context.get_platform() @@ -146,25 +146,12 @@ def water_function_test_data(test_context, request): [ ("infrastructure", "baseline"), ("infrastructure", "not_baseline"), - ("desalination", "baseline"), - ("desalination", "not_baseline"), + ("desalination", None), ], indirect=True, - ids=[ - "infrastructure-baseline", - "infrastructure-sdg", - "desalination-baseline", - "desalination-sdg", - ], ) -def test_data_quality(water_function_test_data): - """Test basic data quality - Validates that the output DataFrames have: - - Required columns present - - No NaN values in the value column - - No duplicate rows - - Valid time format (not single character) - """ +def test_water_data_structure(water_function_test_data): + """Test for data structure, integrity, and configuration-specific behavior.""" data = water_function_test_data result = data["result"] function_type = data["function_type"] @@ -233,20 +220,12 @@ def test_data_quality(water_function_test_data): [ ("infrastructure", "baseline"), ("infrastructure", "not_baseline"), + ("desalination", None), ], indirect=True, - ids=["infrastructure-baseline", "infrastructure-sdg"], ) -def test_infrastructure_modes(water_function_test_data): - """Test all M1/Mf mode requirements for infrastructure technologies. - - Validates: - - Distribution technologies have correct modes (M1+Mf for baseline, Mf only for SDG) - - Non-distribution technologies only have M1 mode - - All output modes have corresponding input modes - - Mf mode is more efficient than M1 (lower input coefficients) - - No early return bugs (all distribution techs present) - """ +def test_water_technology(water_function_test_data): + """Test for technology completeness, data pairing, and catch early return bugs.""" data = water_function_test_data result = data["result"] function_type = data["function_type"] @@ -254,30 +233,34 @@ def test_infrastructure_modes(water_function_test_data): tech_categories = _get_technology_categories()[function_type] input_techs = set(result["input"]["technology"].unique()) output_techs = set(result["output"]["technology"].unique()) - input_df = result["input"] - - # Distribution technology completeness - expected_dist_techs = set(tech_categories["distribution"]) - missing_dist_input = expected_dist_techs - input_techs - assert ( - not missing_dist_input - ), f"""{function_type}: Distribution technologies missing - from input (early return bug): {missing_dist_input}""" - - # Electric/non-electric pairing - elec_techs = set( - result["input"][result["input"]["commodity"] == "electr"]["technology"].unique() - ) - non_elec_techs = set( - result["input"][result["input"]["commodity"] != "electr"]["technology"].unique() - ) - missing_non_elec = elec_techs - non_elec_techs - assert ( - not missing_non_elec - ), f"""{function_type}: Technologies with electricity input - missing non-electric input: {missing_non_elec}""" - # Input/output mode pairing + if function_type == "infrastructure": + # Distribution technology completeness (catches early return bug) + expected_dist_techs = set(tech_categories["distribution"]) + missing_dist_input = expected_dist_techs - input_techs + assert ( + not missing_dist_input + ), f"""{function_type}: Distribution technologies missing + from input (early return bug): {missing_dist_input}""" + + # Electric/non-electric pairing + elec_techs = set( + result["input"][result["input"]["commodity"] == "electr"][ + "technology" + ].unique() + ) + non_elec_techs = set( + result["input"][result["input"]["commodity"] != "electr"][ + "technology" + ].unique() + ) + missing_non_elec = elec_techs - non_elec_techs + assert ( + not missing_non_elec + ), f"""{function_type}: Technologies with electricity input + missing non-electric input: {missing_non_elec}""" + + # Input/output mode pairing (catches missing Mf inputs bug) output_tech_modes = { (row["technology"], row["mode"]) for _, row in result["output"].iterrows() } @@ -300,71 +283,229 @@ def test_infrastructure_modes(water_function_test_data): assert False, error_msg # Mode consistency validation between input and output for infrastructure - common_techs = input_techs.intersection(output_techs) - distribution_techs = set(tech_categories["distribution"]) + if function_type == "infrastructure": + common_techs = input_techs.intersection(output_techs) + distribution_techs = set(tech_categories["distribution"]) + + if common_techs: + for tech in common_techs: + # Distribution technologies should have both M1 and Mf in baseline, + # only Mf in non-baseline + # Non-distribution technologies should only have M1 + if tech in distribution_techs: + expected_modes = ( + {"M1", "Mf"} if sdg_config == "baseline" else {"Mf"} + ) + else: + expected_modes = {"M1"} + + input_modes = set( + result["input"][result["input"]["technology"] == tech][ + "mode" + ].unique() + ) + output_modes = set( + result["output"][result["output"]["technology"] == tech][ + "mode" + ].unique() + ) - if common_techs: - # Single pass through technologies to get modes, coefficients, and validate - tech_data = {} - for tech in common_techs: - tech_inputs = input_df[input_df["technology"] == tech] - tech_outputs = result["output"][result["output"]["technology"] == tech] - - input_modes = set(tech_inputs["mode"].unique()) - output_modes = set(tech_outputs["mode"].unique()) - - # Get M1/Mf coefficients if both modes exist - m1_coeff = mf_coeff = None - if {"M1", "Mf"}.issubset(input_modes): - m1_data = tech_inputs[ - (tech_inputs["mode"] == "M1") - & (tech_inputs["commodity"] != "electr") - ] - mf_data = tech_inputs[ - (tech_inputs["mode"] == "Mf") - & (tech_inputs["commodity"] != "electr") - ] - if not m1_data.empty and not mf_data.empty: - m1_coeff = m1_data["value"].iloc[0] - mf_coeff = mf_data["value"].iloc[0] - - tech_data[tech] = { - "input_modes": input_modes, - "output_modes": output_modes, - "m1_coeff": m1_coeff, - "mf_coeff": mf_coeff, - } - - # Validate all technologies using collected data - for tech, data in tech_data.items(): - # Distribution technologies should have both M1 and Mf in baseline, - # only Mf in non-baseline - # Non-distribution technologies should only have M1 - if tech in distribution_techs: - expected_modes = {"M1", "Mf"} if sdg_config == "baseline" else {"Mf"} - else: - expected_modes = {"M1"} + assert input_modes == expected_modes, ( + f"{function_type}: Technology {tech} has incorrect input " + f"modes for {sdg_config} configuration. " + f"Expected: {expected_modes}, Found: {input_modes}" + ) + assert output_modes == expected_modes, ( + f"{function_type}: Technology {tech} has incorrect output " + f"modes for {sdg_config} configuration. " + f"Expected: {expected_modes}, Found: {output_modes}" + ) + + +@pytest.mark.parametrize( + "water_function_test_data", + [ + ("infrastructure", "baseline"), + ("infrastructure", "not_baseline"), + ("desalination", None), + ], + indirect=True, +) +def test_water_parameter(water_function_test_data): + """Test for parameter consistency and technology-specific uniqueness. + + Catches variable reference bugs. + """ + data = water_function_test_data + result = data["result"] + function_type = data["function_type"] + data["sdg_config"] + tech_categories = _get_technology_categories()[function_type] + + # Check for bound constraints in desalination + if function_type == "desalination": + # Check for bound_total_capacity_up + assert "bound_total_capacity_up" in result, ( + "desalination: Missing 'bound_total_capacity_up' constraint" + ) + assert not result["bound_total_capacity_up"].empty, ( + "desalination: 'bound_total_capacity_up' DataFrame is empty" + ) + + # Check for bound_activity_lo + assert "bound_activity_lo" in result, ( + "desalination: Missing 'bound_activity_lo' constraint" + ) + assert not result["bound_activity_lo"].empty, ( + "desalination: 'bound_activity_lo' DataFrame is empty" + ) + + # Check if bound_capacity exists (might be expected but missing) + if "bound_capacity" in result: + assert not result["bound_capacity"].empty, ( + "desalination: 'bound_capacity' DataFrame exists but is empty" + ) + else: + # Note: bound_capacity is not present in the output + # This assertion documents the current behavior + assert "bound_capacity" not in result, ( + "desalination: 'bound_capacity' constraint is missing from output" + ) - assert data["input_modes"] == expected_modes, ( - f"{function_type}: Technology {tech} has incorrect input " - f"modes for {sdg_config} configuration. " - f"Expected: {expected_modes}, Found: {data['input_modes']}" + # Variable cost consistency (catches variable reference bug) + if "var_cost" in result and not result["var_cost"].empty: + var_cost_df = result["var_cost"] + tech_cost_patterns = {} + + for tech in var_cost_df["technology"].unique(): + tech_data = var_cost_df[var_cost_df["technology"] == tech].sort_values( + [col for col in ["node_loc", "year_act"] if col in var_cost_df.columns] + ) + cost_pattern = tuple(tech_data["value"].values) + tech_cost_patterns.setdefault(cost_pattern, []).append(tech) + + shared_patterns = { + pattern: techs + for pattern, techs in tech_cost_patterns.items() + if len(techs) > 1 + } + + if shared_patterns: + # Check against raw CSV data - this is required + raw_data = tech_categories.get("raw_data") + assert raw_data is not None, ( + f"{function_type}: Raw data not available for validation" ) - assert data["output_modes"] == expected_modes, ( - f"{function_type}: Technology {tech} has incorrect output " - f"modes for {sdg_config} configuration. " - f"Expected: {expected_modes}, Found: {data['output_modes']}" + assert "var_cost_mid" in raw_data.columns, ( + f"{function_type}: var_cost_mid column missing from raw data" ) - # Test efficiency: Mf should be more efficient than - # M1 for distribution techs in baseline - if ( - tech in distribution_techs - and sdg_config == "baseline" - and data["m1_coeff"] is not None - and data["mf_coeff"] is not None - ): - assert data["mf_coeff"] < data["m1_coeff"], ( - f"{function_type}: Technology {tech} - Mf < efficient than M1. " - f"M1={data['m1_coeff']}, Mf={data['mf_coeff']}" + # Get unique var_cost_mid values from raw data + raw_var_costs = raw_data[["tec", "var_cost_mid"]].dropna() + unique_costs = raw_var_costs.groupby("tec")["var_cost_mid"].first() + + # If all technologies have the same cost in raw data, it's not a bug + if len(unique_costs.unique()) == 1: + # All technologies have the same cost in source data + # this is intentional + pass + else: + # Different costs in source but identical in output - this is a bug + max_shared = max(len(techs) for techs in shared_patterns.values()) + total_techs = len(var_cost_df["technology"].unique()) + + assert max_shared / total_techs < 0.7, ( + f"{function_type}: Variable reference bug detected -" + f"""{max_shared}/{total_techs} technologies + have identical cost patterns""" + f"but source data shows different costs" + ) + + # Technical lifetime consistency (catches stale variable bug) + if "technical_lifetime" in result and not result["technical_lifetime"].empty: + lifetime_df = result["technical_lifetime"] + + if function_type == "infrastructure": + tech_categories = _get_technology_categories()[function_type] + dist_techs = set(tech_categories["distribution"]) + available_dist_techs = dist_techs.intersection( + set(lifetime_df["technology"].unique()) + ) + non_dist_techs = set(lifetime_df["technology"].unique()) - dist_techs + + if len(available_dist_techs) >= 2 and non_dist_techs: + dist_lifetimes = [ + lifetime_df[lifetime_df["technology"] == tech]["value"].iloc[0] + for tech in available_dist_techs + ] + non_dist_lifetime = lifetime_df[ + lifetime_df["technology"] == list(non_dist_techs)[0] + ]["value"].iloc[0] + + identical_to_non_dist = sum( + 1 for lt in dist_lifetimes if lt == non_dist_lifetime ) + + assert identical_to_non_dist < len(dist_lifetimes), ( + f"{function_type}: Stale variable bug detected - " + f"""all distribution technologies have lifetime + {non_dist_lifetime} identical to non-distribution technology""" + ) + + +@pytest.mark.parametrize( + "water_function_test_data", [("infrastructure", "baseline")], indirect=True +) +def test_efficiency_mode_mapping(water_function_test_data): + """Test that Mf mode represents higher efficiency. + + Only tests baseline configuration where both M1 and Mf modes exist. + Since output coefficients now reflect efficiency, Mf should have higher output than M1. + """ + data = water_function_test_data + result = data["result"] + function_type = data["function_type"] + + output_df = result["output"] + tech_categories = _get_technology_categories()[function_type] + distribution_techs = set(tech_categories["distribution"]) + + failures = [] + + # Check distribution technologies with both M1 and Mf modes + for tech in distribution_techs: + tech_outputs = output_df[output_df["technology"] == tech] + if tech_outputs.empty: + continue + + modes = set(tech_outputs["mode"].unique()) + if {"M1", "Mf"}.issubset(modes): + # Get output coefficients for both modes + m1_outputs = tech_outputs[tech_outputs["mode"] == "M1"] + mf_outputs = tech_outputs[tech_outputs["mode"] == "Mf"] + + if not m1_outputs.empty and not mf_outputs.empty: + m1_coeff = m1_outputs["value"].iloc[0] + mf_coeff = mf_outputs["value"].iloc[0] + + # Mf should be more efficient (higher output coefficient) + if mf_coeff <= m1_coeff: + failures.append( + { + "tech": tech, + "m1_coeff": m1_coeff, + "mf_coeff": mf_coeff, + "issue": "Mf output not higher than M1 (efficiency not reflected)", + } + ) + + # Report findings from actual function outputs + if failures: + failure_details = "\n".join( + [ + f" {f['tech']}: M1={f['m1_coeff']}, Mf={f['mf_coeff']} - {f['issue']}" + for f in failures + ] + ) + + assert False, f"Efficiency mapping violations (output coefficients should show Mf > M1):\n{failure_details}\n\n" From cf02e145d951c2d7a6a49761fcc956857d005565 Mon Sep 17 00:00:00 2001 From: Vignesh Raghunathan Date: Thu, 21 Aug 2025 13:21:38 +0200 Subject: [PATCH 13/43] Increase fossil_gw elec inp req --- message_ix_models/model/water/data/water_supply.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/message_ix_models/model/water/data/water_supply.py b/message_ix_models/model/water/data/water_supply.py index aa25769459..974cbbf770 100644 --- a/message_ix_models/model/water/data/water_supply.py +++ b/message_ix_models/model/water/data/water_supply.py @@ -454,7 +454,7 @@ def add_water_supply(context: "Context") -> dict[str, pd.DataFrame]: make_df( "input", technology="extract_gw_fossil", - value=((df_gwt["GW_per_km3_per_year"] + 0.043464579) * 2) + value=((df_gwt["GW_per_km3_per_year"] + 0.043464579) * 50) * GWa_KM3_TO_GWa_MCM, # twice as much normal gw unit="GWa/MCM", level="final", From f8360ee08da0a3543d129113d77b772f9720a96b Mon Sep 17 00:00:00 2001 From: Vignesh Raghunathan Date: Thu, 21 Aug 2025 13:58:07 +0200 Subject: [PATCH 14/43] Remove bad input - Circular logic --- .../model/water/data/infrastructure.py | 23 ------------------- 1 file changed, 23 deletions(-) diff --git a/message_ix_models/model/water/data/infrastructure.py b/message_ix_models/model/water/data/infrastructure.py index 1adc85a675..4c22ad2128 100644 --- a/message_ix_models/model/water/data/infrastructure.py +++ b/message_ix_models/model/water/data/infrastructure.py @@ -751,27 +751,6 @@ def add_desalination(context: "Context") -> dict[str, pd.DataFrame]: .pipe(same_time) ) - # input dataframe for extract_salinewater_basin to match M1 output mode - extract_inp_df = ( - make_df( - "input", - technology="extract_salinewater_basin", - value=1, - unit="MCM/year", - level="water_avail_basin", - commodity="salinewater_basin", - mode="M1", - ) - .pipe( - broadcast, - get_vintage_and_active_years(scenario_info, 20), - node_loc=df_node["node"], - time=pd.Series(sub_time), - ) - .pipe(same_node) - .pipe(same_time) - ) - tl = ( make_df( "technical_lifetime", @@ -983,8 +962,6 @@ def add_desalination(context: "Context") -> dict[str, pd.DataFrame]: ] ) - # Add extract_salinewater_basin input to match M1 output mode - inp_df = pd.concat([inp_df, extract_inp_df]) inp_df.dropna(inplace=True) From ad03e7c90435f29222b7e5755d660491ca9ff013 Mon Sep 17 00:00:00 2001 From: Vignesh Raghunathan Date: Thu, 21 Aug 2025 14:32:30 +0200 Subject: [PATCH 15/43] Change vintage active calc for dummy tech --- .../model/water/data/infrastructure.py | 322 +++++++++++++----- message_ix_models/model/water/utils.py | 12 +- 2 files changed, 241 insertions(+), 93 deletions(-) diff --git a/message_ix_models/model/water/data/infrastructure.py b/message_ix_models/model/water/data/infrastructure.py index 4c22ad2128..2834546ba5 100644 --- a/message_ix_models/model/water/data/infrastructure.py +++ b/message_ix_models/model/water/data/infrastructure.py @@ -25,6 +25,26 @@ ) +def is_dummy_technology(df_row) -> bool: + """Check if a technology is a dummy (has zero investment, fix, and var costs). + + Parameters + ---------- + df_row : pandas.Series + Row from the infrastructure CSV containing cost data + + Returns + ------- + bool + True if technology has zero costs (is dummy), False otherwise + """ + return ( + df_row.get("investment_mid", 0) == 0.0 + and df_row.get("fix_cost_mid", 0) == 0.0 + and df_row.get("var_cost_mid", 0) == 0.0 + ) + + def start_creating_input_dataframe( sdg: str, df_node: pd.DataFrame, @@ -37,6 +57,9 @@ def start_creating_input_dataframe( inp_df = pd.DataFrame([]) # Input Dataframe for non elec commodities for index, rows in df_non_elec.iterrows(): + # Check if this is a dummy technology + use_same_year = is_dummy_technology(rows) + inp_df = pd.concat( [ inp_df, @@ -55,7 +78,9 @@ def start_creating_input_dataframe( .pipe( broadcast, get_vintage_and_active_years( - scenario_info, rows["technical_lifetime_mid"] + scenario_info, + rows["technical_lifetime_mid"], + same_year_only=use_same_year ), time=sub_time, ) @@ -66,6 +91,9 @@ def start_creating_input_dataframe( ) if sdg != "baseline": for index, rows in df_dist.iterrows(): + # Check if this is a dummy technology + use_same_year = is_dummy_technology(rows) + inp_df = pd.concat( [ inp_df, @@ -82,7 +110,9 @@ def start_creating_input_dataframe( .pipe( broadcast, get_vintage_and_active_years( - scenario_info, rows["technical_lifetime_mid"] + scenario_info, + rows["technical_lifetime_mid"], + same_year_only=use_same_year ), node_loc=df_node["node"], time=sub_time, @@ -94,6 +124,9 @@ def start_creating_input_dataframe( ) else: for index, rows in df_dist.iterrows(): + # Check if this is a dummy technology + use_same_year = is_dummy_technology(rows) + # Add M1 mode input inp_df = pd.concat( [ @@ -111,7 +144,9 @@ def start_creating_input_dataframe( .pipe( broadcast, get_vintage_and_active_years( - scenario_info, rows["technical_lifetime_mid"] + scenario_info, + rows["technical_lifetime_mid"], + same_year_only=use_same_year ), node_loc=df_node["node"], time=sub_time, @@ -138,7 +173,9 @@ def start_creating_input_dataframe( .pipe( broadcast, get_vintage_and_active_years( - scenario_info, rows["technical_lifetime_mid"] + scenario_info, + rows["technical_lifetime_mid"], + same_year_only=use_same_year ), node_loc=df_node["node"], time=sub_time, @@ -241,6 +278,9 @@ def add_infrastructure_techs(context: "Context") -> dict[str, pd.DataFrame]: out_df = pd.DataFrame([]) for index, rows in df_out.iterrows(): + # Check if this is a dummy technology + use_same_year = is_dummy_technology(rows) + out_df = pd.concat( [ out_df, @@ -257,7 +297,9 @@ def add_infrastructure_techs(context: "Context") -> dict[str, pd.DataFrame]: .pipe( broadcast, get_vintage_and_active_years( - scenario_info, rows["technical_lifetime_mid"] + scenario_info, + rows["technical_lifetime_mid"], + same_year_only=use_same_year ), node_loc=df_node["node"], time=sub_time, @@ -269,79 +311,95 @@ def add_infrastructure_techs(context: "Context") -> dict[str, pd.DataFrame]: ) if context.SDG != "baseline": - out_df = pd.concat( - [ - out_df, - make_df( - "output", - technology=df_out_dist["tec"], - value=df_out_dist["out_value_mid"], - unit="MCM", - level=df_out_dist["outlvl"], - commodity=df_out_dist["outcmd"], - mode="Mf", - ) - .pipe( - broadcast, - get_vintage_and_active_years( - scenario_info, rows["technical_lifetime_mid"] - ), - node_loc=df_node["node"], - time=sub_time, - ) - .pipe(same_node) - .pipe(same_time), - ] - ) + for index, dist_rows in df_out_dist.iterrows(): + # Check if this is a dummy distribution technology + use_same_year_dist = is_dummy_technology(dist_rows) + + out_df = pd.concat( + [ + out_df, + make_df( + "output", + technology=dist_rows["tec"], + value=dist_rows["out_value_mid"], + unit="MCM", + level=dist_rows["outlvl"], + commodity=dist_rows["outcmd"], + mode="Mf", + ) + .pipe( + broadcast, + get_vintage_and_active_years( + scenario_info, + dist_rows["technical_lifetime_mid"], + same_year_only=use_same_year_dist + ), + node_loc=df_node["node"], + time=sub_time, + ) + .pipe(same_node) + .pipe(same_time), + ] + ) else: - out_df = pd.concat( - [ - out_df, - make_df( - "output", - technology=df_out_dist["tec"], - value=df_out_dist["out_value_high"], - unit="MCM", - level=df_out_dist["outlvl"], - commodity=df_out_dist["outcmd"], - mode="M1", - ) - .pipe( - broadcast, - get_vintage_and_active_years( - scenario_info, rows["technical_lifetime_mid"] - ), - node_loc=df_node["node"], - time=sub_time, - ) - .pipe(same_node) - .pipe(same_time), - ] - ) - out_df = pd.concat( - [ - out_df, - make_df( - "output", - technology=df_out_dist["tec"], - value=df_out_dist["out_value_mid"], - unit="MCM", - level=df_out_dist["outlvl"], - commodity=df_out_dist["outcmd"], - mode="Mf", - ) - .pipe( - broadcast, - get_vintage_and_active_years( - scenario_info, rows["technical_lifetime_mid"] - ), - node_loc=df_node["node"], - time=sub_time, - ) - .pipe(same_node) - .pipe(same_time), - ] - ) + for index, dist_rows in df_out_dist.iterrows(): + # Check if this is a dummy distribution technology + use_same_year_dist = is_dummy_technology(dist_rows) + + # Add M1 mode output + out_df = pd.concat( + [ + out_df, + make_df( + "output", + technology=dist_rows["tec"], + value=dist_rows["out_value_high"], + unit="MCM", + level=dist_rows["outlvl"], + commodity=dist_rows["outcmd"], + mode="M1", + ) + .pipe( + broadcast, + get_vintage_and_active_years( + scenario_info, + dist_rows["technical_lifetime_mid"], + same_year_only=use_same_year_dist + ), + node_loc=df_node["node"], + time=sub_time, + ) + .pipe(same_node) + .pipe(same_time), + ] + ) + # Add Mf mode output + out_df = pd.concat( + [ + out_df, + make_df( + "output", + technology=dist_rows["tec"], + value=dist_rows["out_value_mid"], + unit="MCM", + level=dist_rows["outlvl"], + commodity=dist_rows["outcmd"], + mode="Mf", + ) + .pipe( + broadcast, + get_vintage_and_active_years( + scenario_info, + dist_rows["technical_lifetime_mid"], + same_year_only=use_same_year_dist + ), + node_loc=df_node["node"], + time=sub_time, + ) + .pipe(same_node) + .pipe(same_time), + ] + ) results["output"] = out_df @@ -350,6 +408,9 @@ def add_infrastructure_techs(context: "Context") -> dict[str, pd.DataFrame]: cap_df = pd.DataFrame([]) # Adding capacity factor dataframe for index, rows in df_cap.iterrows(): + # Check if this is a dummy technology + use_same_year = is_dummy_technology(rows) + cap_df = pd.concat( [ cap_df, @@ -362,7 +423,9 @@ def add_infrastructure_techs(context: "Context") -> dict[str, pd.DataFrame]: .pipe( broadcast, get_vintage_and_active_years( - scenario_info, rows["technical_lifetime_mid"] + scenario_info, + rows["technical_lifetime_mid"], + same_year_only=use_same_year ), node_loc=df_node["node"], time=sub_time, @@ -413,6 +476,9 @@ def add_infrastructure_techs(context: "Context") -> dict[str, pd.DataFrame]: var_cost = pd.DataFrame([]) for index, rows in df_inv.iterrows(): + # Check if this is a dummy technology + use_same_year = is_dummy_technology(rows) + fix_cost = pd.concat( [ fix_cost, @@ -424,7 +490,9 @@ def add_infrastructure_techs(context: "Context") -> dict[str, pd.DataFrame]: ).pipe( broadcast, get_vintage_and_active_years( - scenario_info, rows["technical_lifetime_mid"] + scenario_info, + rows["technical_lifetime_mid"], + same_year_only=use_same_year ), node_loc=df_node["node"], ), @@ -443,6 +511,9 @@ def add_infrastructure_techs(context: "Context") -> dict[str, pd.DataFrame]: if context.SDG != "baseline": for index, rows in df_var.iterrows(): + # Check if this is a dummy technology + use_same_year = is_dummy_technology(rows) + # Variable cost var_cost = pd.concat( [ @@ -456,7 +527,9 @@ def add_infrastructure_techs(context: "Context") -> dict[str, pd.DataFrame]: ).pipe( broadcast, get_vintage_and_active_years( - scenario_info, rows["technical_lifetime_mid"] + scenario_info, + rows["technical_lifetime_mid"], + same_year_only=use_same_year ), node_loc=df_node["node"], time=sub_time, @@ -466,6 +539,9 @@ def add_infrastructure_techs(context: "Context") -> dict[str, pd.DataFrame]: # Variable cost for distribution technologies for index, rows in df_var_dist.iterrows(): + # Check if this is a dummy technology + use_same_year = is_dummy_technology(rows) + var_cost = pd.concat( [ var_cost, @@ -478,7 +554,9 @@ def add_infrastructure_techs(context: "Context") -> dict[str, pd.DataFrame]: ).pipe( broadcast, get_vintage_and_active_years( - scenario_info, rows["technical_lifetime_mid"] + scenario_info, + rows["technical_lifetime_mid"], + same_year_only=use_same_year ), node_loc=df_node["node"], time=sub_time, @@ -489,6 +567,9 @@ def add_infrastructure_techs(context: "Context") -> dict[str, pd.DataFrame]: else: # Variable cost for index, rows in df_var.iterrows(): + # Check if this is a dummy technology + use_same_year = is_dummy_technology(rows) + var_cost = pd.concat( [ var_cost, @@ -501,7 +582,9 @@ def add_infrastructure_techs(context: "Context") -> dict[str, pd.DataFrame]: ).pipe( broadcast, get_vintage_and_active_years( - scenario_info, rows["technical_lifetime_mid"] + scenario_info, + rows["technical_lifetime_mid"], + same_year_only=use_same_year ), node_loc=df_node["node"], time=sub_time, @@ -510,6 +593,9 @@ def add_infrastructure_techs(context: "Context") -> dict[str, pd.DataFrame]: ) for index, rows in df_var_dist.iterrows(): + # Check if this is a dummy technology + use_same_year = is_dummy_technology(rows) + var_cost = pd.concat( [ var_cost, @@ -522,7 +608,9 @@ def add_infrastructure_techs(context: "Context") -> dict[str, pd.DataFrame]: ).pipe( broadcast, get_vintage_and_active_years( - scenario_info, rows["technical_lifetime_mid"] + scenario_info, + rows["technical_lifetime_mid"], + same_year_only=use_same_year ), node_loc=df_node["node"], time=sub_time, @@ -542,7 +630,9 @@ def add_infrastructure_techs(context: "Context") -> dict[str, pd.DataFrame]: ).pipe( broadcast, get_vintage_and_active_years( - scenario_info, rows["technical_lifetime_mid"] + scenario_info, + rows["technical_lifetime_mid"], + same_year_only=use_same_year ), node_loc=df_node["node"], time=sub_time, @@ -574,6 +664,9 @@ def prepare_input_dataframe( # which is the only explanation as to how the model solved. for _, rows in df_elec.iterrows(): if rows["tec"] in techs: + # Check if this is a dummy technology (for distribution techs) + use_same_year = is_dummy_technology(rows) + if context.SDG != "baseline": inp = make_df( "input", @@ -592,6 +685,7 @@ def prepare_input_dataframe( scenario_info, # 1 because elec commodities don't have technical lifetime 1, + same_year_only=use_same_year ), time=sub_time, ) @@ -615,6 +709,7 @@ def prepare_input_dataframe( scenario_info, # 1 because elec commodities don't have technical lifetime 1, + same_year_only=use_same_year ), time=sub_time, ) @@ -636,7 +731,11 @@ def prepare_input_dataframe( ).pipe( broadcast, # 1 because elec commodities don't have technical lifetime - get_vintage_and_active_years(scenario_info, 1), + get_vintage_and_active_years( + scenario_info, + 1, + same_year_only=use_same_year + ), time=sub_time, ), ] @@ -644,6 +743,9 @@ def prepare_input_dataframe( result_dc["input"].append(inp) else: + # Check if this is a dummy technology (for non-distribution techs) + use_same_year = is_dummy_technology(rows) + inp = make_df( "input", technology=rows["tec"], @@ -657,7 +759,11 @@ def prepare_input_dataframe( node_origin=df_node["region"], ).pipe( broadcast, - get_vintage_and_active_years(scenario_info, 1), + get_vintage_and_active_years( + scenario_info, + 1, + same_year_only=use_same_year + ), time=sub_time, ) @@ -803,6 +909,9 @@ def add_desalination(context: "Context") -> dict[str, pd.DataFrame]: fix_cost = pd.DataFrame([]) var_cost = pd.DataFrame([]) for index, rows in df_desal.iterrows(): + # Check if this is a dummy technology (desalination techs have real costs) + use_same_year = is_dummy_technology(rows) + # Fixed costs # Prepare dataframe for fix_cost fix_cost = pd.concat( @@ -815,7 +924,11 @@ def add_desalination(context: "Context") -> dict[str, pd.DataFrame]: unit="USD/MCM", ).pipe( broadcast, - get_vintage_and_active_years(scenario_info, rows["lifetime_mid"]), + get_vintage_and_active_years( + scenario_info, + rows["lifetime_mid"], + same_year_only=use_same_year + ), node_loc=df_node["node"], ), ] @@ -833,7 +946,11 @@ def add_desalination(context: "Context") -> dict[str, pd.DataFrame]: mode="M1", ).pipe( broadcast, - get_vintage_and_active_years(scenario_info, rows["lifetime_mid"]), + get_vintage_and_active_years( + scenario_info, + rows["lifetime_mid"], + same_year_only=use_same_year + ), node_loc=df_node["node"], time=pd.Series(sub_time), ), @@ -881,6 +998,9 @@ def add_desalination(context: "Context") -> dict[str, pd.DataFrame]: result_dc = defaultdict(list) for index, rows in df_desal.iterrows(): + # Check if this is a dummy technology (desalination techs have real costs) + use_same_year = is_dummy_technology(rows) + inp = make_df( "input", technology=rows["tec"], @@ -894,7 +1014,11 @@ def add_desalination(context: "Context") -> dict[str, pd.DataFrame]: node_origin=df_node["region"], ).pipe( broadcast, - get_vintage_and_active_years(scenario_info, rows["lifetime_mid"]), + get_vintage_and_active_years( + scenario_info, + rows["lifetime_mid"], + same_year_only=use_same_year + ), time=pd.Series(sub_time), ) @@ -910,6 +1034,9 @@ def add_desalination(context: "Context") -> dict[str, pd.DataFrame]: result_dc = defaultdict(list) for index, rows in df_heat.iterrows(): + # Check if this is a dummy technology (desalination techs have real costs) + use_same_year = is_dummy_technology(rows) + inp = make_df( "input", technology=rows["tec"], @@ -923,7 +1050,11 @@ def add_desalination(context: "Context") -> dict[str, pd.DataFrame]: node_origin=df_node["region"], ).pipe( broadcast, - get_vintage_and_active_years(scenario_info, rows["lifetime_mid"]), + get_vintage_and_active_years( + scenario_info, + rows["lifetime_mid"], + same_year_only=use_same_year + ), time=pd.Series(sub_time), ) @@ -935,6 +1066,9 @@ def add_desalination(context: "Context") -> dict[str, pd.DataFrame]: # Adding input dataframe for index, rows in df_desal.iterrows(): + # Check if this is a dummy technology (desalination techs have real costs) + use_same_year = is_dummy_technology(rows) + inp_df = pd.concat( [ inp_df, @@ -951,7 +1085,9 @@ def add_desalination(context: "Context") -> dict[str, pd.DataFrame]: .pipe( broadcast, get_vintage_and_active_years( - scenario_info, rows["lifetime_mid"] + scenario_info, + rows["lifetime_mid"], + same_year_only=use_same_year ), node_loc=df_node["node"], time=pd.Series(sub_time), @@ -983,7 +1119,9 @@ def add_desalination(context: "Context") -> dict[str, pd.DataFrame]: .pipe( broadcast, get_vintage_and_active_years( - scenario_info, rows["lifetime_mid"] + scenario_info, + rows["lifetime_mid"], + same_year_only=use_same_year ), node_loc=df_node["node"], time=pd.Series(sub_time), diff --git a/message_ix_models/model/water/utils.py b/message_ix_models/model/water/utils.py index 728f295fba..5c3a0b477f 100644 --- a/message_ix_models/model/water/utils.py +++ b/message_ix_models/model/water/utils.py @@ -146,7 +146,9 @@ def func(row: pd.Series): def get_vintage_and_active_years( - info: Optional["ScenarioInfo"], technical_lifetime: Optional[int] = None + info: Optional["ScenarioInfo"], + technical_lifetime: Optional[int] = None, + same_year_only: bool = False, ) -> pd.DataFrame: """Calculate valid vintage-activity year combinations without scenario dependency. @@ -160,6 +162,9 @@ def get_vintage_and_active_years( Contains the base yv_ya combinations and duration_period data technical_lifetime : int, optional Technical lifetime in years. If None, returns all combinations. + same_year_only : bool, optional + If True, returns only combinations where year_vtg == year_act. + Useful for dummy technologies where vintage doesn't matter. Returns ------- @@ -169,6 +174,11 @@ def get_vintage_and_active_years( # Get base yv_ya from ScenarioInfo property yv_ya = info.yv_ya + # If same_year_only is requested, return only year_vtg == year_act combinations + if same_year_only: + same_year_mask = yv_ya["year_vtg"] == yv_ya["year_act"] + return yv_ya[same_year_mask].reset_index(drop=True) + # If no technical lifetime specified or is nan, return all combinations if technical_lifetime is None or pd.isna(technical_lifetime): warn( From 96b32db325e872a32c2d18c0db71963eaefadf59 Mon Sep 17 00:00:00 2001 From: Vignesh Raghunathan Date: Wed, 27 Aug 2025 11:22:06 +0200 Subject: [PATCH 16/43] Relabel 6p0 to 7p0 - Minor change to values ommitted. --- ...ed_desalination_potential_km3_year_R12.csv | 5850 ++++++++--------- 1 file changed, 2925 insertions(+), 2925 deletions(-) diff --git a/message_ix_models/data/water/infrastructure/projected_desalination_potential_km3_year_R12.csv b/message_ix_models/data/water/infrastructure/projected_desalination_potential_km3_year_R12.csv index ab0f2c5261..c63c66eaf0 100644 --- a/message_ix_models/data/water/infrastructure/projected_desalination_potential_km3_year_R12.csv +++ b/message_ix_models/data/water/infrastructure/projected_desalination_potential_km3_year_R12.csv @@ -2924,2931 +2924,2931 @@ "9|LAM","2p6",2080,0.0170028309842757 "9|LAM","2p6",2085,0.0188074204474749 "9|LAM","2p6",2090,0.0213065595362694 -"0|EEU","6p0",2020,0.000770369787974928 -"0|EEU","6p0",2025,0.00181980634126776 -"0|EEU","6p0",2030,0.00354058740349036 -"0|EEU","6p0",2035,0.00701838361298046 -"0|EEU","6p0",2040,0.0114807929449322 -"0|EEU","6p0",2045,0.0175605322782623 -"0|EEU","6p0",2050,0.0250530099457705 -"0|EEU","6p0",2055,0.0308947944199912 -"0|EEU","6p0",2060,0.0364356999971388 -"0|EEU","6p0",2065,0.0420934586961256 -"0|EEU","6p0",2070,0.0452892316306283 -"0|EEU","6p0",2075,0.0598604770915547 -"0|EEU","6p0",2080,0.0831949938594963 -"0|EEU","6p0",2085,0.114907360556197 -"0|EEU","6p0",2090,0.152919205601056 -"0|WEU","6p0",2020,0.063119280280433 -"0|WEU","6p0",2025,0.0696039081382802 -"0|WEU","6p0",2030,0.077890485916225 -"0|WEU","6p0",2035,0.092195890170881 -"0|WEU","6p0",2040,0.10788785864666 -"0|WEU","6p0",2045,0.130409216328508 -"0|WEU","6p0",2050,0.15781203828465 -"0|WEU","6p0",2055,0.198495243887982 -"0|WEU","6p0",2060,0.248868162183691 -"0|WEU","6p0",2065,0.321747329473729 -"0|WEU","6p0",2070,0.412515739670669 -"0|WEU","6p0",2075,0.533148804444813 -"0|WEU","6p0",2080,0.696500265640374 -"0|WEU","6p0",2085,0.922129133875154 -"0|WEU","6p0",2090,1.21317665988141 -"100|LAM","6p0",2020,0.0563866295829225 -"100|LAM","6p0",2025,0.067113159274847 -"100|LAM","6p0",2030,0.0853237048188165 -"100|LAM","6p0",2035,0.124697804344412 -"100|LAM","6p0",2040,0.170242230549555 -"100|LAM","6p0",2045,0.234861272651735 -"100|LAM","6p0",2050,0.323119283620502 -"100|LAM","6p0",2055,0.437355724887679 -"100|LAM","6p0",2060,0.590563630286847 -"100|LAM","6p0",2065,0.797402363420372 -"100|LAM","6p0",2070,1.06349708222813 -"100|LAM","6p0",2075,1.42183551208695 -"100|LAM","6p0",2080,1.88018214779325 -"100|LAM","6p0",2085,2.49171198019951 -"100|LAM","6p0",2090,3.28525763991779 -"101|LAM","6p0",2020,0.0172173369550732 -"101|LAM","6p0",2025,0.0172186582995376 -"101|LAM","6p0",2030,0.0172203965914032 -"101|LAM","6p0",2035,0.0172234062461284 -"101|LAM","6p0",2040,0.0172274711933056 -"101|LAM","6p0",2045,0.0172318883592909 -"101|LAM","6p0",2050,0.0172369596209203 -"101|LAM","6p0",2055,0.0172424434348177 -"101|LAM","6p0",2060,0.0172471698970619 -"101|LAM","6p0",2065,0.0172531224880811 -"101|LAM","6p0",2070,0.0172605348300718 -"101|LAM","6p0",2075,0.0172730992548303 -"101|LAM","6p0",2080,0.01729104424695 -"101|LAM","6p0",2085,0.0173087447856411 -"101|LAM","6p0",2090,0.0173297483208161 -"103|NAM","6p0",2020,0.0573753792429438 -"103|NAM","6p0",2025,0.0573814653264432 -"103|NAM","6p0",2030,0.0573864410374558 -"103|NAM","6p0",2035,0.0573957775283307 -"103|NAM","6p0",2040,0.057407151968569 -"103|NAM","6p0",2045,0.0574235149493508 -"103|NAM","6p0",2050,0.0574429896275635 -"103|NAM","6p0",2055,0.0574561257770291 -"103|NAM","6p0",2060,0.0574710925409049 -"103|NAM","6p0",2065,0.0574838127836297 -"103|NAM","6p0",2070,0.0575000892743356 -"103|NAM","6p0",2075,0.0575391566752519 -"103|NAM","6p0",2080,0.0576046780770343 -"103|NAM","6p0",2085,0.0576851124111371 -"103|NAM","6p0",2090,0.0577882472262017 -"104|NAM","6p0",2020,2.23829863260831 -"104|NAM","6p0",2025,2.26711060344692 -"104|NAM","6p0",2030,2.29599748581039 -"104|NAM","6p0",2035,2.34085014065719 -"104|NAM","6p0",2040,2.38207949012962 -"104|NAM","6p0",2045,2.42755768775334 -"104|NAM","6p0",2050,2.45384539989207 -"104|NAM","6p0",2055,2.46955150844563 -"104|NAM","6p0",2060,2.5018884823142 -"104|NAM","6p0",2065,2.53014222343263 -"104|NAM","6p0",2070,2.58446608938566 -"104|NAM","6p0",2075,2.60752062652705 -"104|NAM","6p0",2080,2.65464572089265 -"104|NAM","6p0",2085,2.68915216146568 -"104|NAM","6p0",2090,2.70195591241237 -"105|CHN","6p0",2020,0.662569907974022 -"105|CHN","6p0",2025,1.09190029904704 -"105|CHN","6p0",2030,1.61402892483756 -"105|CHN","6p0",2035,2.59202933566204 -"105|CHN","6p0",2040,3.59555293900328 -"105|CHN","6p0",2045,4.73435354203136 -"105|CHN","6p0",2050,6.05128530970315 -"105|CHN","6p0",2055,7.17499186119268 -"105|CHN","6p0",2060,8.38033504041639 -"105|CHN","6p0",2065,9.85251662148007 -"105|CHN","6p0",2070,11.576206467227 -"105|CHN","6p0",2075,13.3946484784425 -"105|CHN","6p0",2080,15.2303977252738 -"105|CHN","6p0",2085,17.3665505559509 -"105|CHN","6p0",2090,19.9126964957391 -"105|FSU","6p0",2020,0.0733416897024373 -"105|FSU","6p0",2025,0.0777159924832669 -"105|FSU","6p0",2030,0.086601610965077 -"105|FSU","6p0",2035,0.104961974391647 -"105|FSU","6p0",2040,0.119184342456679 -"105|FSU","6p0",2045,0.129029157594833 -"105|FSU","6p0",2050,0.136185999091377 -"105|FSU","6p0",2055,0.129760071348643 -"105|FSU","6p0",2060,0.124847187290782 -"105|FSU","6p0",2065,0.122421548052013 -"105|FSU","6p0",2070,0.118506520145955 -"105|FSU","6p0",2075,0.11926560672986 -"105|FSU","6p0",2080,0.124587687697589 -"105|FSU","6p0",2085,0.129899143736446 -"105|FSU","6p0",2090,0.136304267315551 -"106|EEU","6p0",2020,0.00357380625 -"106|EEU","6p0",2025,0.00553777268508564 -"106|EEU","6p0",2030,0.00770161320578731 -"106|EEU","6p0",2035,0.0116056064537624 -"106|EEU","6p0",2040,0.0158707636346966 -"106|EEU","6p0",2045,0.020812907942641 -"106|EEU","6p0",2050,0.0271268970167797 -"106|EEU","6p0",2055,0.0312031056101253 -"106|EEU","6p0",2060,0.0369362325469143 -"106|EEU","6p0",2065,0.0431653919199874 -"106|EEU","6p0",2070,0.0498835853565054 -"106|EEU","6p0",2075,0.0659101582279557 -"106|EEU","6p0",2080,0.0862377057896713 -"106|EEU","6p0",2085,0.11123854260155 -"106|EEU","6p0",2090,0.142681105694534 -"106|FSU","6p0",2020,0.0603339107250931 -"106|FSU","6p0",2025,0.0632462000893907 -"106|FSU","6p0",2030,0.0687062324953408 -"106|FSU","6p0",2035,0.0808895246246561 -"106|FSU","6p0",2040,0.0904139697430482 -"106|FSU","6p0",2045,0.09810665457783 -"106|FSU","6p0",2050,0.104231818153122 -"106|FSU","6p0",2055,0.101740565474111 -"106|FSU","6p0",2060,0.0997809004247827 -"106|FSU","6p0",2065,0.0952596873059937 -"106|FSU","6p0",2070,0.0880725216354386 -"106|FSU","6p0",2075,0.0924293449296204 -"106|FSU","6p0",2080,0.100237464227229 -"106|FSU","6p0",2085,0.108245526438737 -"106|FSU","6p0",2090,0.118057563710935 -"106|WEU","6p0",2020,0.0693680017289847 -"106|WEU","6p0",2025,0.0832848843359136 -"106|WEU","6p0",2030,0.0931516808464657 -"106|WEU","6p0",2035,0.11185105908143 -"106|WEU","6p0",2040,0.134694939625442 -"106|WEU","6p0",2045,0.161943838465134 -"106|WEU","6p0",2050,0.199439503896551 -"106|WEU","6p0",2055,0.22962381683916 -"106|WEU","6p0",2060,0.274940307445397 -"106|WEU","6p0",2065,0.334205279268721 -"106|WEU","6p0",2070,0.400589556284618 -"106|WEU","6p0",2075,0.523107954484997 -"106|WEU","6p0",2080,0.685452776361424 -"106|WEU","6p0",2085,0.860773239826445 -"106|WEU","6p0",2090,1.09149375026897 -"107|AFR","6p0",2020,0.0391132342656112 -"107|AFR","6p0",2025,0.0394383720348599 -"107|AFR","6p0",2030,0.0414890784206211 -"107|AFR","6p0",2035,0.0463230345169697 -"107|AFR","6p0",2040,0.0526158382797821 -"107|AFR","6p0",2045,0.0615333557178777 -"107|AFR","6p0",2050,0.0724643408752832 -"107|AFR","6p0",2055,0.0854230434471005 -"107|AFR","6p0",2060,0.104330929116325 -"107|AFR","6p0",2065,0.129595785163495 -"107|AFR","6p0",2070,0.153767899672943 -"107|AFR","6p0",2075,0.188296847554645 -"107|AFR","6p0",2080,0.227054439005142 -"107|AFR","6p0",2085,0.274443711894301 -"107|AFR","6p0",2090,0.332659638900644 -"108|LAM","6p0",2020,0.00397382019693143 -"108|LAM","6p0",2025,0.00403559155077912 -"108|LAM","6p0",2030,0.00411223666583721 -"108|LAM","6p0",2035,0.00425988990496796 -"108|LAM","6p0",2040,0.00442925008825347 -"108|LAM","6p0",2045,0.00467240826960913 -"108|LAM","6p0",2050,0.00495367059309343 -"108|LAM","6p0",2055,0.00523716235415962 -"108|LAM","6p0",2060,0.00554780844651607 -"108|LAM","6p0",2065,0.00590330267806557 -"108|LAM","6p0",2070,0.00637079721499963 -"108|LAM","6p0",2075,0.00702318783608822 -"108|LAM","6p0",2080,0.00797107735924993 -"108|LAM","6p0",2085,0.00894939979307839 -"108|LAM","6p0",2090,0.0101378144266847 -"109|NAM","6p0",2020,1.62226220804067 -"109|NAM","6p0",2025,1.62293022756583 -"109|NAM","6p0",2030,1.62318506576471 -"109|NAM","6p0",2035,1.62371186584182 -"109|NAM","6p0",2040,1.62423632314625 -"109|NAM","6p0",2045,1.62458402804162 -"109|NAM","6p0",2050,1.62488681630248 -"109|NAM","6p0",2055,1.62461572598353 -"109|NAM","6p0",2060,1.62421872917848 -"109|NAM","6p0",2065,1.6238982103256 -"109|NAM","6p0",2070,1.6233990998672 -"109|NAM","6p0",2075,1.62333104716033 -"109|NAM","6p0",2080,1.62346723428768 -"109|NAM","6p0",2085,1.62375028932724 -"109|NAM","6p0",2090,1.6240822881475 -"10|FSU","6p0",2020,0.112457479726025 -"10|FSU","6p0",2025,0.126056792960982 -"10|FSU","6p0",2030,0.147129310124674 -"10|FSU","6p0",2035,0.182237805735928 -"10|FSU","6p0",2040,0.209071524187569 -"10|FSU","6p0",2045,0.227299132046101 -"10|FSU","6p0",2050,0.234662364240155 -"10|FSU","6p0",2055,0.236471398609689 -"10|FSU","6p0",2060,0.241620464472381 -"10|FSU","6p0",2065,0.253469166592994 -"10|FSU","6p0",2070,0.267864156104003 -"10|FSU","6p0",2075,0.297577549089618 -"10|FSU","6p0",2080,0.320759867628357 -"10|FSU","6p0",2085,0.349325419095257 -"10|FSU","6p0",2090,0.386082011972642 -"10|SAS","6p0",2020,0.0367672377438594 -"10|SAS","6p0",2025,0.0368365796111055 -"10|SAS","6p0",2030,0.0369360928549386 -"10|SAS","6p0",2035,0.0371224465178331 -"10|SAS","6p0",2040,0.0374047747180576 -"10|SAS","6p0",2045,0.0378293803669602 -"10|SAS","6p0",2050,0.0385039422075343 -"10|SAS","6p0",2055,0.0394924142000316 -"10|SAS","6p0",2060,0.0409551860193689 -"10|SAS","6p0",2065,0.043065251138513 -"10|SAS","6p0",2070,0.0462461817594522 -"10|SAS","6p0",2075,0.051419921555748 -"10|SAS","6p0",2080,0.0581282822508792 -"10|SAS","6p0",2085,0.0668296685741073 -"10|SAS","6p0",2090,0.0791116356616638 -"110|PAS","6p0",2020,0.0777858481446616 -"110|PAS","6p0",2025,0.079560478899473 -"110|PAS","6p0",2030,0.0820347954166109 -"110|PAS","6p0",2035,0.0854985870874764 -"110|PAS","6p0",2040,0.0884483481336499 -"110|PAS","6p0",2045,0.0921079483760585 -"110|PAS","6p0",2050,0.0964013953085619 -"110|PAS","6p0",2055,0.103817555792535 -"110|PAS","6p0",2060,0.114976202790493 -"110|PAS","6p0",2065,0.127760939946253 -"110|PAS","6p0",2070,0.14504694589801 -"110|PAS","6p0",2075,0.162667070186262 -"110|PAS","6p0",2080,0.180859720775924 -"110|PAS","6p0",2085,0.203227092231736 -"110|PAS","6p0",2090,0.231390072254262 -"111|LAM","6p0",2020,0.010984645923044 -"111|LAM","6p0",2025,0.0110758660862776 -"111|LAM","6p0",2030,0.0112879248764101 -"111|LAM","6p0",2035,0.0117852124553382 -"111|LAM","6p0",2040,0.0124143881825692 -"111|LAM","6p0",2045,0.0132188808194253 -"111|LAM","6p0",2050,0.0144120975343663 -"111|LAM","6p0",2055,0.0158024693095791 -"111|LAM","6p0",2060,0.0176664592852071 -"111|LAM","6p0",2065,0.0201075103289253 -"111|LAM","6p0",2070,0.023532620847336 -"111|LAM","6p0",2075,0.0291424345779649 -"111|LAM","6p0",2080,0.0368510880028778 -"111|LAM","6p0",2085,0.0486347935980058 -"111|LAM","6p0",2090,0.0619764387632028 -"113|LAM","6p0",2020,0.0179038537236138 -"113|LAM","6p0",2025,0.0180012322923844 -"113|LAM","6p0",2030,0.0181936165628162 -"113|LAM","6p0",2035,0.0185296176700886 -"113|LAM","6p0",2040,0.0188304569631807 -"113|LAM","6p0",2045,0.0193952655594807 -"113|LAM","6p0",2050,0.0202611560758704 -"113|LAM","6p0",2055,0.0213621718601043 -"113|LAM","6p0",2060,0.0227249796506015 -"113|LAM","6p0",2065,0.0237788074910814 -"113|LAM","6p0",2070,0.0252923247219861 -"113|LAM","6p0",2075,0.0268796280819587 -"113|LAM","6p0",2080,0.0290338158008396 -"113|LAM","6p0",2085,0.0317696897604934 -"113|LAM","6p0",2090,0.0349705952707742 -"114|PAS","6p0",2020,0.018863053020097 -"114|PAS","6p0",2025,0.0224378334606377 -"114|PAS","6p0",2030,0.0267623397528321 -"114|PAS","6p0",2035,0.03415267395481 -"114|PAS","6p0",2040,0.0421930427796566 -"114|PAS","6p0",2045,0.0529558527117344 -"114|PAS","6p0",2050,0.0661635588550381 -"114|PAS","6p0",2055,0.0841487554584983 -"114|PAS","6p0",2060,0.107140147302499 -"114|PAS","6p0",2065,0.138502488481566 -"114|PAS","6p0",2070,0.179248677162953 -"114|PAS","6p0",2075,0.225715391017952 -"114|PAS","6p0",2080,0.285901832132804 -"114|PAS","6p0",2085,0.354383146793055 -"114|PAS","6p0",2090,0.439546765048136 -"115|MEA","6p0",2020,0.12829132930437 -"115|MEA","6p0",2025,0.133778407165827 -"115|MEA","6p0",2030,0.140700388544178 -"115|MEA","6p0",2035,0.165043614641803 -"115|MEA","6p0",2040,0.19648988976577 -"115|MEA","6p0",2045,0.23770997361247 -"115|MEA","6p0",2050,0.301306777959865 -"115|MEA","6p0",2055,0.363319639638913 -"115|MEA","6p0",2060,0.446739035906533 -"115|MEA","6p0",2065,0.526305714358807 -"115|MEA","6p0",2070,0.631812286692778 -"115|MEA","6p0",2075,0.788205015049708 -"115|MEA","6p0",2080,1.01248985548456 -"115|MEA","6p0",2085,1.32016523357743 -"115|MEA","6p0",2090,1.73432631049447 -"115|SAS","6p0",2020,0.0547708406077226 -"115|SAS","6p0",2025,0.0589450376814177 -"115|SAS","6p0",2030,0.0629743781274774 -"115|SAS","6p0",2035,0.072011530649804 -"115|SAS","6p0",2040,0.0847485056355399 -"115|SAS","6p0",2045,0.104244990317922 -"115|SAS","6p0",2050,0.138362606151148 -"115|SAS","6p0",2055,0.189621105454739 -"115|SAS","6p0",2060,0.262730370257245 -"115|SAS","6p0",2065,0.357976594844281 -"115|SAS","6p0",2070,0.485141477581679 -"115|SAS","6p0",2075,0.659048919583939 -"115|SAS","6p0",2080,0.897792515769255 -"115|SAS","6p0",2085,1.21262882065286 -"115|SAS","6p0",2090,1.68503029334188 -"116|LAM","6p0",2020,0.0107570863535817 -"116|LAM","6p0",2025,0.0123369238636448 -"116|LAM","6p0",2030,0.0150887806101147 -"116|LAM","6p0",2035,0.0217929945194926 -"116|LAM","6p0",2040,0.0314898860301829 -"116|LAM","6p0",2045,0.0462250698008731 -"116|LAM","6p0",2050,0.0689928921534712 -"116|LAM","6p0",2055,0.102584188413168 -"116|LAM","6p0",2060,0.150296312839587 -"116|LAM","6p0",2065,0.219003611569803 -"116|LAM","6p0",2070,0.314461516268748 -"116|LAM","6p0",2075,0.450605749671156 -"116|LAM","6p0",2080,0.638598182249808 -"116|LAM","6p0",2085,0.899488842324374 -"116|LAM","6p0",2090,1.25782507288344 -"117|PAS","6p0",2020,0.02346585 -"117|PAS","6p0",2025,0.0362579904751998 -"117|PAS","6p0",2030,0.0465712251356281 -"117|PAS","6p0",2035,0.0605253745801831 -"117|PAS","6p0",2040,0.0789004154498567 -"117|PAS","6p0",2045,0.101586177315224 -"117|PAS","6p0",2050,0.132689349922043 -"117|PAS","6p0",2055,0.174019495173683 -"117|PAS","6p0",2060,0.234182196644303 -"117|PAS","6p0",2065,0.313679294230339 -"117|PAS","6p0",2070,0.414560381189421 -"117|PAS","6p0",2075,0.535662416651046 -"117|PAS","6p0",2080,0.694805324988663 -"117|PAS","6p0",2085,0.891299416152408 -"117|PAS","6p0",2090,1.1780151321837 -"118|CHN","6p0",2020,0 -"118|CHN","6p0",2025,0 -"118|CHN","6p0",2030,0 -"118|CHN","6p0",2035,0 -"118|CHN","6p0",2040,0 -"118|CHN","6p0",2045,0 -"118|CHN","6p0",2050,0 -"118|CHN","6p0",2055,0 -"118|CHN","6p0",2060,0 -"118|CHN","6p0",2065,0 -"118|CHN","6p0",2070,0 -"118|CHN","6p0",2075,0 -"118|CHN","6p0",2080,0.0197189303009914 -"118|CHN","6p0",2085,0.030370924199769 -"118|CHN","6p0",2090,0.0374790991229906 -"119|WEU","6p0",2020,0.106549703876353 -"119|WEU","6p0",2025,0.119226425149589 -"119|WEU","6p0",2030,0.131132566773588 -"119|WEU","6p0",2035,0.152318831101706 -"119|WEU","6p0",2040,0.175569060646875 -"119|WEU","6p0",2045,0.205327257674657 -"119|WEU","6p0",2050,0.244684855947157 -"119|WEU","6p0",2055,0.29903174490408 -"119|WEU","6p0",2060,0.373200771692887 -"119|WEU","6p0",2065,0.47305662564664 -"119|WEU","6p0",2070,0.59795237718242 -"119|WEU","6p0",2075,0.77575554451612 -"119|WEU","6p0",2080,0.999896435392722 -"119|WEU","6p0",2085,1.30745628443265 -"119|WEU","6p0",2090,1.69097788553499 -"11|CHN","6p0",2020,0.334049842346328 -"11|CHN","6p0",2025,0.628827849828849 -"11|CHN","6p0",2030,1.06604186637385 -"11|CHN","6p0",2035,1.73991756281933 -"11|CHN","6p0",2040,2.44292800694964 -"11|CHN","6p0",2045,3.21854442586928 -"11|CHN","6p0",2050,3.95463247860387 -"11|CHN","6p0",2055,4.68055729648695 -"11|CHN","6p0",2060,5.58552774324699 -"11|CHN","6p0",2065,6.38648980091449 -"11|CHN","6p0",2070,7.29895255329314 -"11|CHN","6p0",2075,8.22805641201539 -"11|CHN","6p0",2080,9.2927676383486 -"11|CHN","6p0",2085,10.7457172012601 -"11|CHN","6p0",2090,12.0680747777928 -"11|FSU","6p0",2020,0.06194775574083 -"11|FSU","6p0",2025,0.0631812092026153 -"11|FSU","6p0",2030,0.0659761249150061 -"11|FSU","6p0",2035,0.0716128090533579 -"11|FSU","6p0",2040,0.0756989324152051 -"11|FSU","6p0",2045,0.079344609988963 -"11|FSU","6p0",2050,0.0813894511499148 -"11|FSU","6p0",2055,0.081103352075996 -"11|FSU","6p0",2060,0.0807329412981782 -"11|FSU","6p0",2065,0.0795847705448962 -"11|FSU","6p0",2070,0.0781208242344914 -"11|FSU","6p0",2075,0.0792153258641846 -"11|FSU","6p0",2080,0.0811100673937 -"11|FSU","6p0",2085,0.0832078730153414 -"11|FSU","6p0",2090,0.0843217852516656 -"120|MEA","6p0",2020,5.02702734374886 -"120|MEA","6p0",2025,5.37660454372928 -"120|MEA","6p0",2030,5.69319595980406 -"120|MEA","6p0",2035,6.00042587804269 -"120|MEA","6p0",2040,6.28733528618027 -"120|MEA","6p0",2045,6.60565179816854 -"120|MEA","6p0",2050,6.92623518072643 -"120|MEA","6p0",2055,7.45529321186612 -"120|MEA","6p0",2060,7.88036079440525 -"120|MEA","6p0",2065,8.37049462201372 -"120|MEA","6p0",2070,9.20727219023202 -"120|MEA","6p0",2075,10.000795074259 -"120|MEA","6p0",2080,11.1840757153538 -"120|MEA","6p0",2085,12.6133279806359 -"120|MEA","6p0",2090,14.2026423548345 -"121|AFR","6p0",2020,0.00422434817099042 -"121|AFR","6p0",2025,0.00505201127117869 -"121|AFR","6p0",2030,0.00618412124937341 -"121|AFR","6p0",2035,0.00843430986195597 -"121|AFR","6p0",2040,0.0120881376839443 -"121|AFR","6p0",2045,0.0182225311288768 -"121|AFR","6p0",2050,0.0295001144151353 -"121|AFR","6p0",2055,0.0531609506453447 -"121|AFR","6p0",2060,0.0912669453649335 -"121|AFR","6p0",2065,0.153443097988393 -"121|AFR","6p0",2070,0.260017894781437 -"121|AFR","6p0",2075,0.394857111785011 -"121|AFR","6p0",2080,0.598008465889515 -"121|AFR","6p0",2085,0.923051118721979 -"121|AFR","6p0",2090,1.34502641185643 -"122|LAM","6p0",2020,0.158563077978415 -"122|LAM","6p0",2025,0.168651606397225 -"122|LAM","6p0",2030,0.183028223599204 -"122|LAM","6p0",2035,0.218142790219223 -"122|LAM","6p0",2040,0.253941877814357 -"122|LAM","6p0",2045,0.288536917974256 -"122|LAM","6p0",2050,0.339599322343078 -"122|LAM","6p0",2055,0.406546580303088 -"122|LAM","6p0",2060,0.475259867556852 -"122|LAM","6p0",2065,0.576624062193171 -"122|LAM","6p0",2070,0.69255620816272 -"122|LAM","6p0",2075,0.816577357957623 -"122|LAM","6p0",2080,0.981927820158246 -"122|LAM","6p0",2085,1.16520481201209 -"122|LAM","6p0",2090,1.35350878707909 -"122|NAM","6p0",2020,3.55978528895408 -"122|NAM","6p0",2025,3.82168011221028 -"122|NAM","6p0",2030,4.03457201461554 -"122|NAM","6p0",2035,4.30876944623864 -"122|NAM","6p0",2040,4.56520292659063 -"122|NAM","6p0",2045,4.70357426393747 -"122|NAM","6p0",2050,4.94271817872128 -"122|NAM","6p0",2055,5.14983130089162 -"122|NAM","6p0",2060,5.2438532303621 -"122|NAM","6p0",2065,5.40411852361184 -"122|NAM","6p0",2070,5.57444391156542 -"122|NAM","6p0",2075,5.78288911394556 -"122|NAM","6p0",2080,6.07323484123997 -"122|NAM","6p0",2085,6.4349856672141 -"122|NAM","6p0",2090,6.5858679525161 -"123|CHN","6p0",2020,0.242339153412553 -"123|CHN","6p0",2025,0.483250270432147 -"123|CHN","6p0",2030,0.894784661859789 -"123|CHN","6p0",2035,1.51298389849383 -"123|CHN","6p0",2040,2.21125367680179 -"123|CHN","6p0",2045,3.04099534369157 -"123|CHN","6p0",2050,3.87844478173287 -"123|CHN","6p0",2055,4.51557649019533 -"123|CHN","6p0",2060,5.21005391629191 -"123|CHN","6p0",2065,5.77168836685966 -"123|CHN","6p0",2070,6.39159754284659 -"123|CHN","6p0",2075,6.87712480124242 -"123|CHN","6p0",2080,7.48577812599956 -"123|CHN","6p0",2085,8.33883277777968 -"123|CHN","6p0",2090,8.88874650586474 -"123|FSU","6p0",2020,0.0639523745587218 -"123|FSU","6p0",2025,0.065879998694472 -"123|FSU","6p0",2030,0.0705217520396801 -"123|FSU","6p0",2035,0.0799545933985254 -"123|FSU","6p0",2040,0.0874590050065904 -"123|FSU","6p0",2045,0.0942617598401306 -"123|FSU","6p0",2050,0.0986136174067618 -"123|FSU","6p0",2055,0.0978688634908718 -"123|FSU","6p0",2060,0.0962817133908736 -"123|FSU","6p0",2065,0.0937378902515378 -"123|FSU","6p0",2070,0.0912322905541591 -"123|FSU","6p0",2075,0.0916938951703174 -"123|FSU","6p0",2080,0.0944366713872927 -"123|FSU","6p0",2085,0.0983397574169591 -"123|FSU","6p0",2090,0.099079704388033 -"124|SAS","6p0",2020,0.518969587196116 -"124|SAS","6p0",2025,0.776127264647 -"124|SAS","6p0",2030,1.03883239850157 -"124|SAS","6p0",2035,1.49455172682256 -"124|SAS","6p0",2040,2.06058544049015 -"124|SAS","6p0",2045,2.79831395431397 -"124|SAS","6p0",2050,3.77246653854761 -"124|SAS","6p0",2055,4.99092912315963 -"124|SAS","6p0",2060,6.59044960959809 -"124|SAS","6p0",2065,8.63845680828872 -"124|SAS","6p0",2070,11.3634386660537 -"124|SAS","6p0",2075,14.4504527566661 -"124|SAS","6p0",2080,18.6688240818308 -"124|SAS","6p0",2085,23.7784149140221 -"124|SAS","6p0",2090,29.5056094938963 -"125|LAM","6p0",2020,0.0191360658930006 -"125|LAM","6p0",2025,0.0193981929869119 -"125|LAM","6p0",2030,0.0197808989936089 -"125|LAM","6p0",2035,0.0206425259762677 -"125|LAM","6p0",2040,0.0215492321314909 -"125|LAM","6p0",2045,0.0229828468888046 -"125|LAM","6p0",2050,0.0251964038715269 -"125|LAM","6p0",2055,0.0278929736946557 -"125|LAM","6p0",2060,0.0309638198931082 -"125|LAM","6p0",2065,0.0345955018135663 -"125|LAM","6p0",2070,0.0397844817455171 -"125|LAM","6p0",2075,0.0435841794971368 -"125|LAM","6p0",2080,0.0496530013768958 -"125|LAM","6p0",2085,0.0569445009087633 -"125|LAM","6p0",2090,0.0651448210750494 -"126|NAM","6p0",2020,0.363398475772434 -"126|NAM","6p0",2025,0.372336714379421 -"126|NAM","6p0",2030,0.377881888579622 -"126|NAM","6p0",2035,0.389783806587983 -"126|NAM","6p0",2040,0.395723065400503 -"126|NAM","6p0",2045,0.405342304133556 -"126|NAM","6p0",2050,0.414792716983206 -"126|NAM","6p0",2055,0.421253724969958 -"126|NAM","6p0",2060,0.438551484123046 -"126|NAM","6p0",2065,0.445674172210128 -"126|NAM","6p0",2070,0.462508255716381 -"126|NAM","6p0",2075,0.481634474978973 -"126|NAM","6p0",2080,0.506969864512922 -"126|NAM","6p0",2085,0.540702485274139 -"126|NAM","6p0",2090,0.575747606391809 -"127|FSU","6p0",2020,0.0623264023582618 -"127|FSU","6p0",2025,0.0637247902239973 -"127|FSU","6p0",2030,0.0668409257779846 -"127|FSU","6p0",2035,0.0736561252058698 -"127|FSU","6p0",2040,0.0788512590364239 -"127|FSU","6p0",2045,0.0832742881118552 -"127|FSU","6p0",2050,0.0861300560038991 -"127|FSU","6p0",2055,0.0840582154559453 -"127|FSU","6p0",2060,0.0817134248547784 -"127|FSU","6p0",2065,0.0777356401507655 -"127|FSU","6p0",2070,0.0724383898079084 -"127|FSU","6p0",2075,0.0724092608555842 -"127|FSU","6p0",2080,0.0740079713949925 -"127|FSU","6p0",2085,0.075172567403116 -"127|FSU","6p0",2090,0.0762629123592981 -"127|WEU","6p0",2020,0.00140737083569987 -"127|WEU","6p0",2025,0.00142558853631459 -"127|WEU","6p0",2030,0.00144228521075031 -"127|WEU","6p0",2035,0.00146745037623271 -"127|WEU","6p0",2040,0.00149666694335188 -"127|WEU","6p0",2045,0.0015318013226897 -"127|WEU","6p0",2050,0.00158351242460794 -"127|WEU","6p0",2055,0.0016592285344573 -"127|WEU","6p0",2060,0.0017747603922886 -"127|WEU","6p0",2065,0.0019420898661119 -"127|WEU","6p0",2070,0.00219463160408448 -"127|WEU","6p0",2075,0.00256157348836199 -"127|WEU","6p0",2080,0.00309279764294559 -"127|WEU","6p0",2085,0.00383375659017362 -"127|WEU","6p0",2090,0.00493795253315515 -"128|WEU","6p0",2020,0.0919785259535156 -"128|WEU","6p0",2025,0.0917771347758881 -"128|WEU","6p0",2030,0.0894675497288728 -"128|WEU","6p0",2035,0.0875395377636493 -"128|WEU","6p0",2040,0.0846006188849798 -"128|WEU","6p0",2045,0.0832127690735181 -"128|WEU","6p0",2050,0.0832919509695226 -"128|WEU","6p0",2055,0.0834876133814536 -"128|WEU","6p0",2060,0.0837528194551022 -"128|WEU","6p0",2065,0.0841296096988585 -"128|WEU","6p0",2070,0.0845896541039714 -"128|WEU","6p0",2075,0.0849919674530035 -"128|WEU","6p0",2080,0.0854773398668284 -"128|WEU","6p0",2085,0.0859532109680166 -"128|WEU","6p0",2090,0.0864535307994131 -"129|AFR","6p0",2020,0.000128425476446968 -"129|AFR","6p0",2025,0.000173619302372174 -"129|AFR","6p0",2030,0.000334838842012011 -"129|AFR","6p0",2035,0.000988410812037993 -"129|AFR","6p0",2040,0.0022567535659322 -"129|AFR","6p0",2045,0.00479671920712528 -"129|AFR","6p0",2050,0.00948495021423838 -"129|AFR","6p0",2055,0.0161342159205257 -"129|AFR","6p0",2060,0.0255581234507286 -"129|AFR","6p0",2065,0.0375949533697951 -"129|AFR","6p0",2070,0.0529404939628039 -"129|AFR","6p0",2075,0.0768961537628404 -"129|AFR","6p0",2080,0.110290579276823 -"129|AFR","6p0",2085,0.155564137216177 -"129|AFR","6p0",2090,0.21555979849248 -"12|SAS","6p0",2020,0.124621484087745 -"12|SAS","6p0",2025,0.125493300792386 -"12|SAS","6p0",2030,0.126633152469145 -"12|SAS","6p0",2035,0.128725358682156 -"12|SAS","6p0",2040,0.131285434629108 -"12|SAS","6p0",2045,0.134347648005765 -"12|SAS","6p0",2050,0.137358585691497 -"12|SAS","6p0",2055,0.1410334149346 -"12|SAS","6p0",2060,0.145834883020684 -"12|SAS","6p0",2065,0.151520986053095 -"12|SAS","6p0",2070,0.161171612068016 -"12|SAS","6p0",2075,0.170855183254055 -"12|SAS","6p0",2080,0.184801139235393 -"12|SAS","6p0",2085,0.199694882292002 -"12|SAS","6p0",2090,0.222646796760554 -"130|AFR","6p0",2020,0.00699476180964749 -"130|AFR","6p0",2025,0.00787152866830975 -"130|AFR","6p0",2030,0.00889771955948225 -"130|AFR","6p0",2035,0.0111132501607689 -"130|AFR","6p0",2040,0.0145866428093433 -"130|AFR","6p0",2045,0.0199618346139695 -"130|AFR","6p0",2050,0.0297150493133103 -"130|AFR","6p0",2055,0.0491031411456801 -"130|AFR","6p0",2060,0.0803384118040801 -"130|AFR","6p0",2065,0.124524738521973 -"130|AFR","6p0",2070,0.205153735422409 -"130|AFR","6p0",2075,0.294687930829656 -"130|AFR","6p0",2080,0.395197351749516 -"130|AFR","6p0",2085,0.567954665148944 -"130|AFR","6p0",2090,0.765068602170332 -"131|FSU","6p0",2020,0.0578250421994669 -"131|FSU","6p0",2025,0.0578395742690864 -"131|FSU","6p0",2030,0.0578674159648556 -"131|FSU","6p0",2035,0.0579281893455976 -"131|FSU","6p0",2040,0.0579727940190661 -"131|FSU","6p0",2045,0.0580052959174246 -"131|FSU","6p0",2050,0.0580313954710772 -"131|FSU","6p0",2055,0.0580098136689501 -"131|FSU","6p0",2060,0.0579835712823681 -"131|FSU","6p0",2065,0.057943866981997 -"131|FSU","6p0",2070,0.0578825617048225 -"131|FSU","6p0",2075,0.057876056883698 -"131|FSU","6p0",2080,0.0578834320578225 -"131|FSU","6p0",2085,0.0578899574216537 -"131|FSU","6p0",2090,0.0578955299984405 -"132|FSU","6p0",2020,0.0580863451660042 -"132|FSU","6p0",2025,0.0581864101758523 -"132|FSU","6p0",2030,0.0583938775581628 -"132|FSU","6p0",2035,0.0588405501734685 -"132|FSU","6p0",2040,0.0591770856922209 -"132|FSU","6p0",2045,0.0594436807158132 -"132|FSU","6p0",2050,0.0596300405440752 -"132|FSU","6p0",2055,0.0594771098694659 -"132|FSU","6p0",2060,0.0593038404391819 -"132|FSU","6p0",2065,0.0590587994132688 -"132|FSU","6p0",2070,0.0586926392841799 -"132|FSU","6p0",2075,0.058668879385838 -"132|FSU","6p0",2080,0.0587466273595853 -"132|FSU","6p0",2085,0.058817373762779 -"132|FSU","6p0",2090,0.0588653357084873 -"134|LAM","6p0",2020,0.000487445166576338 -"134|LAM","6p0",2025,0.00051877233659721 -"134|LAM","6p0",2030,0.000593575040193228 -"134|LAM","6p0",2035,0.000781911639570876 -"134|LAM","6p0",2040,0.00104840784515896 -"134|LAM","6p0",2045,0.00145947443446897 -"134|LAM","6p0",2050,0.00206107191893795 -"134|LAM","6p0",2055,0.00287588298562141 -"134|LAM","6p0",2060,0.00404595412754491 -"134|LAM","6p0",2065,0.00603065396205445 -"134|LAM","6p0",2070,0.00882792242968168 -"134|LAM","6p0",2075,0.0209427348366371 -"134|LAM","6p0",2080,0.0340556865365361 -"134|LAM","6p0",2085,0.0485520487265737 -"134|LAM","6p0",2090,0.0691723304530233 -"135|AFR","6p0",2020,0.0594802920757487 -"135|AFR","6p0",2025,0.060328875832185 -"135|AFR","6p0",2030,0.0646554401887715 -"135|AFR","6p0",2035,0.0754511665283089 -"135|AFR","6p0",2040,0.0888850761260992 -"135|AFR","6p0",2045,0.107051573018793 -"135|AFR","6p0",2050,0.128985652434821 -"135|AFR","6p0",2055,0.1574016865095 -"135|AFR","6p0",2060,0.195197677178441 -"135|AFR","6p0",2065,0.243195325172612 -"135|AFR","6p0",2070,0.298680980248164 -"135|AFR","6p0",2075,0.37000605100901 -"135|AFR","6p0",2080,0.446413030249546 -"135|AFR","6p0",2085,0.545875996003349 -"135|AFR","6p0",2090,0.660881173064257 -"136|AFR","6p0",2020,0.0631403768394771 -"136|AFR","6p0",2025,0.0640753019436114 -"136|AFR","6p0",2030,0.0697699915481001 -"136|AFR","6p0",2035,0.0843822293243681 -"136|AFR","6p0",2040,0.103380817521208 -"136|AFR","6p0",2045,0.126350148358312 -"136|AFR","6p0",2050,0.158608640858843 -"136|AFR","6p0",2055,0.193068291029168 -"136|AFR","6p0",2060,0.237910178133035 -"136|AFR","6p0",2065,0.295183338659457 -"136|AFR","6p0",2070,0.362324329548881 -"136|AFR","6p0",2075,0.449894186147084 -"136|AFR","6p0",2080,0.557412532830168 -"136|AFR","6p0",2085,0.700727121158895 -"136|AFR","6p0",2090,0.853525606369136 -"137|LAM","6p0",2020,0.0113553000754119 -"137|LAM","6p0",2025,0.011585099787234 -"137|LAM","6p0",2030,0.0120657977364383 -"137|LAM","6p0",2035,0.0133175214598512 -"137|LAM","6p0",2040,0.0148682726089923 -"137|LAM","6p0",2045,0.0169437859957552 -"137|LAM","6p0",2050,0.0201420167661345 -"137|LAM","6p0",2055,0.0243361108843237 -"137|LAM","6p0",2060,0.0301219125012443 -"137|LAM","6p0",2065,0.0377980345906647 -"137|LAM","6p0",2070,0.0477441777146303 -"137|LAM","6p0",2075,0.0620827313560989 -"137|LAM","6p0",2080,0.0810466968236307 -"137|LAM","6p0",2085,0.10866155664052 -"137|LAM","6p0",2090,0.144748533831008 -"139|LAM","6p0",2020,0.0245946419800302 -"139|LAM","6p0",2025,0.0248123920372172 -"139|LAM","6p0",2030,0.0251853838136006 -"139|LAM","6p0",2035,0.0259568204354119 -"139|LAM","6p0",2040,0.0268367149258694 -"139|LAM","6p0",2045,0.0281424870961518 -"139|LAM","6p0",2050,0.0299296653026499 -"139|LAM","6p0",2055,0.0322622061194254 -"139|LAM","6p0",2060,0.0355970429388982 -"139|LAM","6p0",2065,0.0401824913204092 -"139|LAM","6p0",2070,0.046527112492486 -"139|LAM","6p0",2075,0.0562934891277849 -"139|LAM","6p0",2080,0.0687136247271982 -"139|LAM","6p0",2085,0.0845057441580061 -"139|LAM","6p0",2090,0.105044069219469 -"13|AFR","6p0",2020,0.00020233828734811 -"13|AFR","6p0",2025,0.000204209315020792 -"13|AFR","6p0",2030,0.000217993469205853 -"13|AFR","6p0",2035,0.000250076538581198 -"13|AFR","6p0",2040,0.000281588315657872 -"13|AFR","6p0",2045,0.000414208736162482 -"13|AFR","6p0",2050,0.000534913096854685 -"13|AFR","6p0",2055,0.000767407743129044 -"13|AFR","6p0",2060,0.00154523204155218 -"13|AFR","6p0",2065,0.00213664984438547 -"13|AFR","6p0",2070,0.00306956438319966 -"13|AFR","6p0",2075,0.00438270937305679 -"13|AFR","6p0",2080,0.00571106914372255 -"13|AFR","6p0",2085,0.00681759573114951 -"13|AFR","6p0",2090,0.00954880430906312 -"141|SAS","6p0",2020,0.0028251 -"141|SAS","6p0",2025,0.00517540836321409 -"141|SAS","6p0",2030,0.0090670805896732 -"141|SAS","6p0",2035,0.0171993702250083 -"141|SAS","6p0",2040,0.026689909914749 -"141|SAS","6p0",2045,0.0392780208681025 -"141|SAS","6p0",2050,0.0570797553818721 -"141|SAS","6p0",2055,0.0847318418857898 -"141|SAS","6p0",2060,0.125552935238255 -"141|SAS","6p0",2065,0.174409613826757 -"141|SAS","6p0",2070,0.259143524043903 -"141|SAS","6p0",2075,0.359961006319948 -"141|SAS","6p0",2080,0.488608188512679 -"141|SAS","6p0",2085,0.6882820166906 -"141|SAS","6p0",2090,0.886161986407423 -"142|NAM","6p0",2020,0.979242017852461 -"142|NAM","6p0",2025,1.00917060658158 -"142|NAM","6p0",2030,1.02406125889148 -"142|NAM","6p0",2035,1.05038096098253 -"142|NAM","6p0",2040,1.07350586434638 -"142|NAM","6p0",2045,1.09800325252036 -"142|NAM","6p0",2050,1.11530756330111 -"142|NAM","6p0",2055,1.11733041972182 -"142|NAM","6p0",2060,1.12419529071205 -"142|NAM","6p0",2065,1.13399928479338 -"142|NAM","6p0",2070,1.15525202689773 -"142|NAM","6p0",2075,1.18615701801683 -"142|NAM","6p0",2080,1.23157155124847 -"142|NAM","6p0",2085,1.2788283675068 -"142|NAM","6p0",2090,1.31071070022888 -"143|PAS","6p0",2020,0.0910197672679311 -"143|PAS","6p0",2025,0.0985955720365305 -"143|PAS","6p0",2030,0.10756676436792 -"143|PAS","6p0",2035,0.121842237934239 -"143|PAS","6p0",2040,0.135138517254535 -"143|PAS","6p0",2045,0.152085151382221 -"143|PAS","6p0",2050,0.17266527537264 -"143|PAS","6p0",2055,0.204066291380416 -"143|PAS","6p0",2060,0.247962200780866 -"143|PAS","6p0",2065,0.300104511664625 -"143|PAS","6p0",2070,0.372355473822293 -"143|PAS","6p0",2075,0.453620478958917 -"143|PAS","6p0",2080,0.538258907354639 -"143|PAS","6p0",2085,0.644568915203797 -"143|PAS","6p0",2090,0.789120962835258 -"144|PAS","6p0",2020,0.0859701015572485 -"144|PAS","6p0",2025,0.0913102859240461 -"144|PAS","6p0",2030,0.0975754517946643 -"144|PAS","6p0",2035,0.10787619707611 -"144|PAS","6p0",2040,0.118769270368731 -"144|PAS","6p0",2045,0.132814637294334 -"144|PAS","6p0",2050,0.150210103704759 -"144|PAS","6p0",2055,0.174234697073112 -"144|PAS","6p0",2060,0.207547020805241 -"144|PAS","6p0",2065,0.252829187956376 -"144|PAS","6p0",2070,0.31232971966625 -"144|PAS","6p0",2075,0.383098889388834 -"144|PAS","6p0",2080,0.474666874396366 -"144|PAS","6p0",2085,0.564755873333006 -"144|PAS","6p0",2090,0.675893975681671 -"145|WEU","6p0",2020,0.000238397178490678 -"145|WEU","6p0",2025,0.000249687612834273 -"145|WEU","6p0",2030,0.000264500922005486 -"145|WEU","6p0",2035,0.000291321401612928 -"145|WEU","6p0",2040,0.000327131683598205 -"145|WEU","6p0",2045,0.00037407988181696 -"145|WEU","6p0",2050,0.000438297050691086 -"145|WEU","6p0",2055,0.000522633085225481 -"145|WEU","6p0",2060,0.000656648838131646 -"145|WEU","6p0",2065,0.000857479872252532 -"145|WEU","6p0",2070,0.00115294823742289 -"145|WEU","6p0",2075,0.00158969385705732 -"145|WEU","6p0",2080,0.00221312120235689 -"145|WEU","6p0",2085,0.00301893059755319 -"145|WEU","6p0",2090,0.00429283626741587 -"146|FSU","6p0",2020,0.0918254119976614 -"146|FSU","6p0",2025,0.101302658782343 -"146|FSU","6p0",2030,0.117819979390364 -"146|FSU","6p0",2035,0.147219008764893 -"146|FSU","6p0",2040,0.173997024625704 -"146|FSU","6p0",2045,0.191007836872298 -"146|FSU","6p0",2050,0.1987100695694 -"146|FSU","6p0",2055,0.191313760707069 -"146|FSU","6p0",2060,0.183182970851918 -"146|FSU","6p0",2065,0.180633958488329 -"146|FSU","6p0",2070,0.183366832703009 -"146|FSU","6p0",2075,0.189837683004638 -"146|FSU","6p0",2080,0.202806792062967 -"146|FSU","6p0",2085,0.221708005632413 -"146|FSU","6p0",2090,0.245684630260471 -"148|CHN","6p0",2020,1.12040032158681 -"148|CHN","6p0",2025,1.86795210689229 -"148|CHN","6p0",2030,2.84980442117967 -"148|CHN","6p0",2035,4.50509863645983 -"148|CHN","6p0",2040,6.2086422145407 -"148|CHN","6p0",2045,8.21706070825371 -"148|CHN","6p0",2050,10.3469834916995 -"148|CHN","6p0",2055,12.1428254362379 -"148|CHN","6p0",2060,13.9667454147927 -"148|CHN","6p0",2065,15.7647502246801 -"148|CHN","6p0",2070,17.4781689250106 -"148|CHN","6p0",2075,20.2342440528828 -"148|CHN","6p0",2080,23.3237175990121 -"148|CHN","6p0",2085,26.5874460020873 -"148|CHN","6p0",2090,30.688358205428 -"148|FSU","6p0",2020,0.0595746123357163 -"148|FSU","6p0",2025,0.0609926185406009 -"148|FSU","6p0",2030,0.0640658063533931 -"148|FSU","6p0",2035,0.069085520923518 -"148|FSU","6p0",2040,0.073892772938036 -"148|FSU","6p0",2045,0.0783962821305928 -"148|FSU","6p0",2050,0.0807460610459072 -"148|FSU","6p0",2055,0.0786273739115189 -"148|FSU","6p0",2060,0.0764014451675629 -"148|FSU","6p0",2065,0.0734133490144797 -"148|FSU","6p0",2070,0.0701817084274788 -"148|FSU","6p0",2075,0.0701629023503987 -"148|FSU","6p0",2080,0.0711868698675872 -"148|FSU","6p0",2085,0.0726417460278865 -"148|FSU","6p0",2090,0.0746317837460437 -"148|SAS","6p0",2020,0.0371881504831643 -"148|SAS","6p0",2025,0.0373364822861758 -"148|SAS","6p0",2030,0.0375331730707695 -"148|SAS","6p0",2035,0.0379697328494851 -"148|SAS","6p0",2040,0.0386072433862457 -"148|SAS","6p0",2045,0.0395940644733399 -"148|SAS","6p0",2050,0.0411003130061229 -"148|SAS","6p0",2055,0.0427744273384904 -"148|SAS","6p0",2060,0.0449151815129163 -"148|SAS","6p0",2065,0.0479944636298394 -"148|SAS","6p0",2070,0.0519281924339738 -"148|SAS","6p0",2075,0.05926614548677 -"148|SAS","6p0",2080,0.0695074506591157 -"148|SAS","6p0",2085,0.082580018623163 -"148|SAS","6p0",2090,0.100114705814024 -"149|PAO","6p0",2020,0.69380779414294 -"149|PAO","6p0",2025,0.695795090027465 -"149|PAO","6p0",2030,0.697671190287332 -"149|PAO","6p0",2035,0.699995874689158 -"149|PAO","6p0",2040,0.70313968166864 -"149|PAO","6p0",2045,0.705102279652007 -"149|PAO","6p0",2050,0.708175737348095 -"149|PAO","6p0",2055,0.712306372007002 -"149|PAO","6p0",2060,0.714446027696163 -"149|PAO","6p0",2065,0.719354485018394 -"149|PAO","6p0",2070,0.725112254828961 -"149|PAO","6p0",2075,0.730662623161718 -"149|PAO","6p0",2080,0.739772621563848 -"149|PAO","6p0",2085,0.749377376918247 -"149|PAO","6p0",2090,0.757724732303698 -"14|MEA","6p0",2020,3.17092474072563 -"14|MEA","6p0",2025,3.32354651515329 -"14|MEA","6p0",2030,3.5044445902734 -"14|MEA","6p0",2035,3.63304729864846 -"14|MEA","6p0",2040,3.76281838088824 -"14|MEA","6p0",2045,3.88166175134548 -"14|MEA","6p0",2050,4.07788180443013 -"14|MEA","6p0",2055,4.32300778167358 -"14|MEA","6p0",2060,4.44214156484315 -"14|MEA","6p0",2065,4.51232493753033 -"14|MEA","6p0",2070,4.6739174699742 -"14|MEA","6p0",2075,4.83678866758176 -"14|MEA","6p0",2080,5.27744125454972 -"14|MEA","6p0",2085,5.96554347730609 -"14|MEA","6p0",2090,6.76548588503848 -"150|WEU","6p0",2020,0.109800376966448 -"150|WEU","6p0",2025,0.123110561285263 -"150|WEU","6p0",2030,0.135532240096975 -"150|WEU","6p0",2035,0.157771664196935 -"150|WEU","6p0",2040,0.182769936163457 -"150|WEU","6p0",2045,0.215811039111849 -"150|WEU","6p0",2050,0.256479068936635 -"150|WEU","6p0",2055,0.31584129657643 -"150|WEU","6p0",2060,0.393264372134645 -"150|WEU","6p0",2065,0.501708865759752 -"150|WEU","6p0",2070,0.638999791663829 -"150|WEU","6p0",2075,0.833814152054882 -"150|WEU","6p0",2080,1.08444168434785 -"150|WEU","6p0",2085,1.40930890890089 -"150|WEU","6p0",2090,1.83804272654731 -"151|MEA","6p0",2020,0.310961530829189 -"151|MEA","6p0",2025,0.325778225639879 -"151|MEA","6p0",2030,0.356939943985329 -"151|MEA","6p0",2035,0.392893864115896 -"151|MEA","6p0",2040,0.430436328075421 -"151|MEA","6p0",2045,0.485975062978417 -"151|MEA","6p0",2050,0.536332235753711 -"151|MEA","6p0",2055,0.595579113092085 -"151|MEA","6p0",2060,0.649446012400191 -"151|MEA","6p0",2065,0.703536018295043 -"151|MEA","6p0",2070,0.796807193111747 -"151|MEA","6p0",2075,0.919612326676362 -"151|MEA","6p0",2080,1.10926834378624 -"151|MEA","6p0",2085,1.41412660005027 -"151|MEA","6p0",2090,1.79904126320958 -"151|WEU","6p0",2020,0.108483326516266 -"151|WEU","6p0",2025,0.118185512026941 -"151|WEU","6p0",2030,0.131295679782156 -"151|WEU","6p0",2035,0.150874716658967 -"151|WEU","6p0",2040,0.169788321256205 -"151|WEU","6p0",2045,0.19271939207677 -"151|WEU","6p0",2050,0.216246745455927 -"151|WEU","6p0",2055,0.243180220987442 -"151|WEU","6p0",2060,0.267949858554495 -"151|WEU","6p0",2065,0.299776566257744 -"151|WEU","6p0",2070,0.336605064720186 -"151|WEU","6p0",2075,0.370678126670787 -"151|WEU","6p0",2080,0.418766064814069 -"151|WEU","6p0",2085,0.469643497067008 -"151|WEU","6p0",2090,0.51855593440047 -"152|LAM","6p0",2020,0.0173239851219405 -"152|LAM","6p0",2025,0.0173447831949536 -"152|LAM","6p0",2030,0.0173794339532114 -"152|LAM","6p0",2035,0.0174369620897576 -"152|LAM","6p0",2040,0.017502677978236 -"152|LAM","6p0",2045,0.0175875265323246 -"152|LAM","6p0",2050,0.0176987966876136 -"152|LAM","6p0",2055,0.0178300147167275 -"152|LAM","6p0",2060,0.0179803428006377 -"152|LAM","6p0",2065,0.0181587258865798 -"152|LAM","6p0",2070,0.0184012969159586 -"152|LAM","6p0",2075,0.0186416685378467 -"152|LAM","6p0",2080,0.0189787221643604 -"152|LAM","6p0",2085,0.0193148440018376 -"152|LAM","6p0",2090,0.0197219079568224 -"153|NAM","6p0",2020,2.73520124323569 -"153|NAM","6p0",2025,2.84870088951328 -"153|NAM","6p0",2030,2.92249891634579 -"153|NAM","6p0",2035,3.0420918329994 -"153|NAM","6p0",2040,3.14723331729485 -"153|NAM","6p0",2045,3.22324278916102 -"153|NAM","6p0",2050,3.27610100285077 -"153|NAM","6p0",2055,3.2989441087652 -"153|NAM","6p0",2060,3.34892820923413 -"153|NAM","6p0",2065,3.40159169402037 -"153|NAM","6p0",2070,3.49928595597643 -"153|NAM","6p0",2075,3.60664684277353 -"153|NAM","6p0",2080,3.70210074181464 -"153|NAM","6p0",2085,3.8402739447395 -"153|NAM","6p0",2090,3.94699338063218 -"154|FSU","6p0",2020,0.0920331789720148 -"154|FSU","6p0",2025,0.102372294199434 -"154|FSU","6p0",2030,0.119716279310634 -"154|FSU","6p0",2035,0.157278144205424 -"154|FSU","6p0",2040,0.185932534919976 -"154|FSU","6p0",2045,0.204648807758832 -"154|FSU","6p0",2050,0.217437118779105 -"154|FSU","6p0",2055,0.211661285696528 -"154|FSU","6p0",2060,0.211480375800303 -"154|FSU","6p0",2065,0.219404303280491 -"154|FSU","6p0",2070,0.225504509425855 -"154|FSU","6p0",2075,0.237875659728763 -"154|FSU","6p0",2080,0.25687610227555 -"154|FSU","6p0",2085,0.276668533379607 -"154|FSU","6p0",2090,0.295206756772437 -"155|LAM","6p0",2020,0.0193133561051524 -"155|LAM","6p0",2025,0.0197728763792411 -"155|LAM","6p0",2030,0.0204904621097194 -"155|LAM","6p0",2035,0.0219229904035638 -"155|LAM","6p0",2040,0.0235473425310643 -"155|LAM","6p0",2045,0.0257380486801053 -"155|LAM","6p0",2050,0.0287452637225047 -"155|LAM","6p0",2055,0.0327353484601889 -"155|LAM","6p0",2060,0.0375275251673665 -"155|LAM","6p0",2065,0.0435169552146117 -"155|LAM","6p0",2070,0.0519543637215235 -"155|LAM","6p0",2075,0.05938109307469 -"155|LAM","6p0",2080,0.0694479824133757 -"155|LAM","6p0",2085,0.0807526034623012 -"155|LAM","6p0",2090,0.0947899658945552 -"156|RCPA","6p0",2020,0.0133237731286374 -"156|RCPA","6p0",2025,0.0173876942584541 -"156|RCPA","6p0",2030,0.0216974612815554 -"156|RCPA","6p0",2035,0.0282496652562701 -"156|RCPA","6p0",2040,0.0352331818481641 -"156|RCPA","6p0",2045,0.0444430324432906 -"156|RCPA","6p0",2050,0.0567029306635838 -"156|RCPA","6p0",2055,0.0728726693354607 -"156|RCPA","6p0",2060,0.0927969427366259 -"156|RCPA","6p0",2065,0.120648075626629 -"156|RCPA","6p0",2070,0.150585424463408 -"156|RCPA","6p0",2075,0.184264296844512 -"156|RCPA","6p0",2080,0.225958818748924 -"156|RCPA","6p0",2085,0.27113315378218 -"156|RCPA","6p0",2090,0.337050025869414 -"157|FSU","6p0",2020,0.0803215301639617 -"157|FSU","6p0",2025,0.087286211631236 -"157|FSU","6p0",2030,0.10035535092217 -"157|FSU","6p0",2035,0.131003788629496 -"157|FSU","6p0",2040,0.151566578808852 -"157|FSU","6p0",2045,0.168795799553004 -"157|FSU","6p0",2050,0.183187305617101 -"157|FSU","6p0",2055,0.179918754694554 -"157|FSU","6p0",2060,0.180638493963961 -"157|FSU","6p0",2065,0.180947507315085 -"157|FSU","6p0",2070,0.17461943858963 -"157|FSU","6p0",2075,0.182240478713783 -"157|FSU","6p0",2080,0.197133735898917 -"157|FSU","6p0",2085,0.20607720331215 -"157|FSU","6p0",2090,0.215310514011864 -"158|AFR","6p0",2020,0.0329480951007865 -"158|AFR","6p0",2025,0.0340689597789305 -"158|AFR","6p0",2030,0.0369009425776825 -"158|AFR","6p0",2035,0.0441981949205085 -"158|AFR","6p0",2040,0.0532085724445166 -"158|AFR","6p0",2045,0.068944235003276 -"158|AFR","6p0",2050,0.0950384838609529 -"158|AFR","6p0",2055,0.150595793278215 -"158|AFR","6p0",2060,0.240211402227549 -"158|AFR","6p0",2065,0.36530051925177 -"158|AFR","6p0",2070,0.551878864901589 -"158|AFR","6p0",2075,0.810373437403883 -"158|AFR","6p0",2080,1.15747906817931 -"158|AFR","6p0",2085,1.71898384465849 -"158|AFR","6p0",2090,2.38024485034338 -"159|CHN","6p0",2020,0.517290863913048 -"159|CHN","6p0",2025,0.903440987841371 -"159|CHN","6p0",2030,1.39892014494739 -"159|CHN","6p0",2035,2.19851752456837 -"159|CHN","6p0",2040,3.06465548606045 -"159|CHN","6p0",2045,4.08451240843301 -"159|CHN","6p0",2050,5.17838061851884 -"159|CHN","6p0",2055,6.39616960464089 -"159|CHN","6p0",2060,7.77974797150547 -"159|CHN","6p0",2065,9.20704604598661 -"159|CHN","6p0",2070,10.9512803494552 -"159|CHN","6p0",2075,12.8854597633543 -"159|CHN","6p0",2080,14.733265537008 -"159|CHN","6p0",2085,16.9659340580189 -"159|CHN","6p0",2090,19.3241192932388 -"15|SAS","6p0",2020,0.0667601796527165 -"15|SAS","6p0",2025,0.0741100010449973 -"15|SAS","6p0",2030,0.0835194150361556 -"15|SAS","6p0",2035,0.0989485945334138 -"15|SAS","6p0",2040,0.121278142377442 -"15|SAS","6p0",2045,0.152030130825509 -"15|SAS","6p0",2050,0.206829535592512 -"15|SAS","6p0",2055,0.287129748719121 -"15|SAS","6p0",2060,0.397782429135548 -"15|SAS","6p0",2065,0.543507631811748 -"15|SAS","6p0",2070,0.755985237317971 -"15|SAS","6p0",2075,1.00994579284883 -"15|SAS","6p0",2080,1.37440844971992 -"15|SAS","6p0",2085,1.82588019464395 -"15|SAS","6p0",2090,2.51553761902209 -"160|FSU","6p0",2020,0.0604904413356021 -"160|FSU","6p0",2025,0.0612705776621886 -"160|FSU","6p0",2030,0.0629111978214685 -"160|FSU","6p0",2035,0.0664428761218184 -"160|FSU","6p0",2040,0.0690925146449047 -"160|FSU","6p0",2045,0.0712066237250224 -"160|FSU","6p0",2050,0.0727272474909887 -"160|FSU","6p0",2055,0.0722475807426635 -"160|FSU","6p0",2060,0.0718794089408438 -"160|FSU","6p0",2065,0.0714700451007488 -"160|FSU","6p0",2070,0.0705004584214873 -"160|FSU","6p0",2075,0.0712528544249619 -"160|FSU","6p0",2080,0.0724239238035253 -"160|FSU","6p0",2085,0.0733930687602729 -"160|FSU","6p0",2090,0.0743074348599688 -"160|RCPA","6p0",2020,0.0581583114930355 -"160|RCPA","6p0",2025,0.0583035706967752 -"160|RCPA","6p0",2030,0.0586309442123138 -"160|RCPA","6p0",2035,0.0593388076630425 -"160|RCPA","6p0",2040,0.0599477994347069 -"160|RCPA","6p0",2045,0.0604862883216133 -"160|RCPA","6p0",2050,0.0609446435174953 -"160|RCPA","6p0",2055,0.060782730436662 -"160|RCPA","6p0",2060,0.0605657314976241 -"160|RCPA","6p0",2065,0.0602184890042249 -"160|RCPA","6p0",2070,0.0596185453508911 -"160|RCPA","6p0",2075,0.0595641282996413 -"160|RCPA","6p0",2080,0.0596866027910144 -"160|RCPA","6p0",2085,0.0598135619353722 -"160|RCPA","6p0",2090,0.0598989810416688 -"161|AFR","6p0",2020,0.000121576021976397 -"161|AFR","6p0",2025,0.000137281954323692 -"161|AFR","6p0",2030,0.000179114966934587 -"161|AFR","6p0",2035,0.000279410512632738 -"161|AFR","6p0",2040,0.000437292766137462 -"161|AFR","6p0",2045,0.00073277298743383 -"161|AFR","6p0",2050,0.00126308957322486 -"161|AFR","6p0",2055,0.00221900406697446 -"161|AFR","6p0",2060,0.0039513698598175 -"161|AFR","6p0",2065,0.00729968641344286 -"161|AFR","6p0",2070,0.0134806769768382 -"161|AFR","6p0",2075,0.0243062891118184 -"161|AFR","6p0",2080,0.0428652199775066 -"161|AFR","6p0",2085,0.0700384206036858 -"161|AFR","6p0",2090,0.0995089570134266 -"162|CHN","6p0",2020,2.10601408236296 -"162|CHN","6p0",2025,3.37177042769016 -"162|CHN","6p0",2030,4.82921160740403 -"162|CHN","6p0",2035,7.33394579751912 -"162|CHN","6p0",2040,9.9991328313615 -"162|CHN","6p0",2045,12.8286618675896 -"162|CHN","6p0",2050,16.3025400557257 -"162|CHN","6p0",2055,19.6778677467225 -"162|CHN","6p0",2060,23.9337128914997 -"162|CHN","6p0",2065,28.7751686723699 -"162|CHN","6p0",2070,33.4225072423229 -"162|CHN","6p0",2075,38.9163007423601 -"162|CHN","6p0",2080,44.6231962860388 -"162|CHN","6p0",2085,50.9663006608521 -"162|CHN","6p0",2090,57.6694935109815 -"16|FSU","6p0",2020,0.0577936181234935 -"16|FSU","6p0",2025,0.0577970891183277 -"16|FSU","6p0",2030,0.0578043468967206 -"16|FSU","6p0",2035,0.0578205212810831 -"16|FSU","6p0",2040,0.0578323752843483 -"16|FSU","6p0",2045,0.0578417258011827 -"16|FSU","6p0",2050,0.0578489432099883 -"16|FSU","6p0",2055,0.0578444800373769 -"16|FSU","6p0",2060,0.0578381040564372 -"16|FSU","6p0",2065,0.0578286508873823 -"16|FSU","6p0",2070,0.0578154716794346 -"16|FSU","6p0",2075,0.0578139215257577 -"16|FSU","6p0",2080,0.0578156102854411 -"16|FSU","6p0",2085,0.0578173070766691 -"16|FSU","6p0",2090,0.0578191996742611 -"17|NAM","6p0",2020,0.111555427155656 -"17|NAM","6p0",2025,0.111692388045644 -"17|NAM","6p0",2030,0.111795205516188 -"17|NAM","6p0",2035,0.111992232454381 -"17|NAM","6p0",2040,0.112213390186306 -"17|NAM","6p0",2045,0.112463714650168 -"17|NAM","6p0",2050,0.112744637609515 -"17|NAM","6p0",2055,0.112910636840773 -"17|NAM","6p0",2060,0.113128511921843 -"17|NAM","6p0",2065,0.113415213723179 -"17|NAM","6p0",2070,0.113813099091093 -"17|NAM","6p0",2075,0.114579072091115 -"17|NAM","6p0",2080,0.115655515009582 -"17|NAM","6p0",2085,0.117024730530678 -"17|NAM","6p0",2090,0.118830508806492 -"18|PAO","6p0",2020,0.758563593577398 -"18|PAO","6p0",2025,0.769666631887237 -"18|PAO","6p0",2030,0.783803349516308 -"18|PAO","6p0",2035,0.801942420040991 -"18|PAO","6p0",2040,0.81468101328112 -"18|PAO","6p0",2045,0.841024704071821 -"18|PAO","6p0",2050,0.857924410830034 -"18|PAO","6p0",2055,0.886678580225459 -"18|PAO","6p0",2060,0.920805060149317 -"18|PAO","6p0",2065,0.96085033327742 -"18|PAO","6p0",2070,1.00344538003271 -"18|PAO","6p0",2075,1.06299626270036 -"18|PAO","6p0",2080,1.12170446014247 -"18|PAO","6p0",2085,1.19228963970866 -"18|PAO","6p0",2090,1.24994469081578 -"19|PAO","6p0",2020,0.688140251917134 -"19|PAO","6p0",2025,0.688971150937231 -"19|PAO","6p0",2030,0.690108708704814 -"19|PAO","6p0",2035,0.691996799760243 -"19|PAO","6p0",2040,0.6930280141425 -"19|PAO","6p0",2045,0.694666102162168 -"19|PAO","6p0",2050,0.696461011930773 -"19|PAO","6p0",2055,0.699059713519309 -"19|PAO","6p0",2060,0.701652148176614 -"19|PAO","6p0",2065,0.70536395727487 -"19|PAO","6p0",2070,0.709146811587786 -"19|PAO","6p0",2075,0.712709788990345 -"19|PAO","6p0",2080,0.716254369915973 -"19|PAO","6p0",2085,0.720752715248152 -"19|PAO","6p0",2090,0.725238147930037 -"1|AFR","6p0",2020,0.00587883274013346 -"1|AFR","6p0",2025,0.00611069304848469 -"1|AFR","6p0",2030,0.00648608069174534 -"1|AFR","6p0",2035,0.00724261164057464 -"1|AFR","6p0",2040,0.00828163323796381 -"1|AFR","6p0",2045,0.0101239316443453 -"1|AFR","6p0",2050,0.0128930729810429 -"1|AFR","6p0",2055,0.0186659478340948 -"1|AFR","6p0",2060,0.0275757198414488 -"1|AFR","6p0",2065,0.0407484605813445 -"1|AFR","6p0",2070,0.0650575712901085 -"1|AFR","6p0",2075,0.0983763887084827 -"1|AFR","6p0",2080,0.151414975253025 -"1|AFR","6p0",2085,0.235966672355775 -"1|AFR","6p0",2090,0.327019918383365 -"20|PAO","6p0",2020,0.685793221514779 -"20|PAO","6p0",2025,0.68617390833341 -"20|PAO","6p0",2030,0.686797782028423 -"20|PAO","6p0",2035,0.687593324674818 -"20|PAO","6p0",2040,0.688145273039852 -"20|PAO","6p0",2045,0.689013062683312 -"20|PAO","6p0",2050,0.690191179617631 -"20|PAO","6p0",2055,0.691714550019679 -"20|PAO","6p0",2060,0.693218798609394 -"20|PAO","6p0",2065,0.694902855892008 -"20|PAO","6p0",2070,0.695347732621924 -"20|PAO","6p0",2075,0.697212306863789 -"20|PAO","6p0",2080,0.699613038835652 -"20|PAO","6p0",2085,0.703308211549064 -"20|PAO","6p0",2090,0.70589796217561 -"21|PAO","6p0",2020,0.700970097460145 -"21|PAO","6p0",2025,0.704565345536068 -"21|PAO","6p0",2030,0.709673397707206 -"21|PAO","6p0",2035,0.715218858080079 -"21|PAO","6p0",2040,0.720491022648447 -"21|PAO","6p0",2045,0.725312721422499 -"21|PAO","6p0",2050,0.732541866137876 -"21|PAO","6p0",2055,0.741502186047706 -"21|PAO","6p0",2060,0.750933470895141 -"21|PAO","6p0",2065,0.761218364842107 -"21|PAO","6p0",2070,0.771353322423572 -"21|PAO","6p0",2075,0.783763864274011 -"21|PAO","6p0",2080,0.800703967906647 -"21|PAO","6p0",2085,0.816149150684403 -"21|PAO","6p0",2090,0.841982645579374 -"22|PAO","6p0",2020,0.690186369180104 -"22|PAO","6p0",2025,0.691882548721895 -"22|PAO","6p0",2030,0.694221210996727 -"22|PAO","6p0",2035,0.697015807400027 -"22|PAO","6p0",2040,0.700796544637632 -"22|PAO","6p0",2045,0.704232792811039 -"22|PAO","6p0",2050,0.707618820193316 -"22|PAO","6p0",2055,0.711077945669529 -"22|PAO","6p0",2060,0.713302160044107 -"22|PAO","6p0",2065,0.716259496447857 -"22|PAO","6p0",2070,0.723636492998719 -"22|PAO","6p0",2075,0.730919369405282 -"22|PAO","6p0",2080,0.742164002523212 -"22|PAO","6p0",2085,0.753546573133974 -"22|PAO","6p0",2090,0.76429214653209 -"23|FSU","6p0",2020,0.0593337666253726 -"23|FSU","6p0",2025,0.0598515095517839 -"23|FSU","6p0",2030,0.0608822773585355 -"23|FSU","6p0",2035,0.0632411221443771 -"23|FSU","6p0",2040,0.0650146545110599 -"23|FSU","6p0",2045,0.0665293608872286 -"23|FSU","6p0",2050,0.0675152466754759 -"23|FSU","6p0",2055,0.0666770258587195 -"23|FSU","6p0",2060,0.0658484812770171 -"23|FSU","6p0",2065,0.064464731113517 -"23|FSU","6p0",2070,0.062621099046026 -"23|FSU","6p0",2075,0.0624719887222771 -"23|FSU","6p0",2080,0.0629521108496095 -"23|FSU","6p0",2085,0.0632431903475846 -"23|FSU","6p0",2090,0.0635414606018044 -"24|SAS","6p0",2020,0.0543980655418622 -"24|SAS","6p0",2025,0.0565744019116884 -"24|SAS","6p0",2030,0.058984685584912 -"24|SAS","6p0",2035,0.0636360772505087 -"24|SAS","6p0",2040,0.0694131889144712 -"24|SAS","6p0",2045,0.0774826722121614 -"24|SAS","6p0",2050,0.0864081042031003 -"24|SAS","6p0",2055,0.100272453070884 -"24|SAS","6p0",2060,0.120001810389708 -"24|SAS","6p0",2065,0.148510039614805 -"24|SAS","6p0",2070,0.188933489895702 -"24|SAS","6p0",2075,0.239834998557961 -"24|SAS","6p0",2080,0.303338197010908 -"24|SAS","6p0",2085,0.374489484579787 -"24|SAS","6p0",2090,0.463771194678104 -"25|FSU","6p0",2020,0.0528531947687088 -"25|FSU","6p0",2025,0.059551722343809 -"25|FSU","6p0",2030,0.0718504317992208 -"25|FSU","6p0",2035,0.10006090236232 -"25|FSU","6p0",2040,0.122868494864557 -"25|FSU","6p0",2045,0.144468448204997 -"25|FSU","6p0",2050,0.168101499062837 -"25|FSU","6p0",2055,0.181325118085601 -"25|FSU","6p0",2060,0.207649951734876 -"25|FSU","6p0",2065,0.238875078519029 -"25|FSU","6p0",2070,0.274986993194932 -"25|FSU","6p0",2075,0.342302275239501 -"25|FSU","6p0",2080,0.424909585038689 -"25|FSU","6p0",2085,0.534045038634846 -"25|FSU","6p0",2090,0.648112053120491 -"26|WEU","6p0",2020,0.113117951573719 -"26|WEU","6p0",2025,0.124368352511772 -"26|WEU","6p0",2030,0.139037405710509 -"26|WEU","6p0",2035,0.159890181702473 -"26|WEU","6p0",2040,0.180301223610812 -"26|WEU","6p0",2045,0.204156146236314 -"26|WEU","6p0",2050,0.227003888358027 -"26|WEU","6p0",2055,0.254758926777937 -"26|WEU","6p0",2060,0.28151542218587 -"26|WEU","6p0",2065,0.315779439259094 -"26|WEU","6p0",2070,0.3531786342961 -"26|WEU","6p0",2075,0.392978024878807 -"26|WEU","6p0",2080,0.446211345533009 -"26|WEU","6p0",2085,0.508170786528012 -"26|WEU","6p0",2090,0.562925485152033 -"27|LAM","6p0",2020,0.191718412541578 -"27|LAM","6p0",2025,0.207155238337161 -"27|LAM","6p0",2030,0.233672643563081 -"27|LAM","6p0",2035,0.289193181773217 -"27|LAM","6p0",2040,0.341267581239191 -"27|LAM","6p0",2045,0.40002881944989 -"27|LAM","6p0",2050,0.483519309935432 -"27|LAM","6p0",2055,0.589841499140705 -"27|LAM","6p0",2060,0.711310416242796 -"27|LAM","6p0",2065,0.859482459158517 -"27|LAM","6p0",2070,1.02679249203107 -"27|LAM","6p0",2075,1.24642523217504 -"27|LAM","6p0",2080,1.49599842633756 -"27|LAM","6p0",2085,1.79994320763065 -"27|LAM","6p0",2090,2.14576027920475 -"27|NAM","6p0",2020,4.86786003761463 -"27|NAM","6p0",2025,5.32953285759884 -"27|NAM","6p0",2030,5.7082967831487 -"27|NAM","6p0",2035,6.25435361735102 -"27|NAM","6p0",2040,6.81583745322733 -"27|NAM","6p0",2045,7.128876982331 -"27|NAM","6p0",2050,7.42258789920498 -"27|NAM","6p0",2055,7.73170651003107 -"27|NAM","6p0",2060,8.02031236723331 -"27|NAM","6p0",2065,8.42505284432336 -"27|NAM","6p0",2070,8.91325859207529 -"27|NAM","6p0",2075,9.21431869138057 -"27|NAM","6p0",2080,9.66217342291099 -"27|NAM","6p0",2085,10.0608741864857 -"27|NAM","6p0",2090,10.3957064504879 -"28|LAM","6p0",2020,0.00125556779411765 -"28|LAM","6p0",2025,0.00245537738059507 -"28|LAM","6p0",2030,0.00369458377752795 -"28|LAM","6p0",2035,0.00561836940196543 -"28|LAM","6p0",2040,0.00789807189201444 -"28|LAM","6p0",2045,0.0118703481302384 -"28|LAM","6p0",2050,0.0182358953284978 -"28|LAM","6p0",2055,0.0268984476939072 -"28|LAM","6p0",2060,0.039746370614627 -"28|LAM","6p0",2065,0.0570325342363266 -"28|LAM","6p0",2070,0.0828842978045586 -"28|LAM","6p0",2075,0.125465105025276 -"28|LAM","6p0",2080,0.181269360178146 -"28|LAM","6p0",2085,0.258350177934603 -"28|LAM","6p0",2090,0.350171132420635 -"29|LAM","6p0",2020,0.00758330821204704 -"29|LAM","6p0",2025,0.00889224006078925 -"29|LAM","6p0",2030,0.0100669462552919 -"29|LAM","6p0",2035,0.0124258113516972 -"29|LAM","6p0",2040,0.0151893784122296 -"29|LAM","6p0",2045,0.0193437045182888 -"29|LAM","6p0",2050,0.0255854592628272 -"29|LAM","6p0",2055,0.0332451978268787 -"29|LAM","6p0",2060,0.040667337536451 -"29|LAM","6p0",2065,0.0534790000179478 -"29|LAM","6p0",2070,0.0667925112572167 -"29|LAM","6p0",2075,0.0893837400366955 -"29|LAM","6p0",2080,0.119440124144725 -"29|LAM","6p0",2085,0.148781387222361 -"29|LAM","6p0",2090,0.18782870444629 -"30|FSU","6p0",2020,0.10019291894985 -"30|FSU","6p0",2025,0.112793320371682 -"30|FSU","6p0",2030,0.136440501863281 -"30|FSU","6p0",2035,0.171402955170138 -"30|FSU","6p0",2040,0.204000899318113 -"30|FSU","6p0",2045,0.236145761872865 -"30|FSU","6p0",2050,0.247572216560027 -"30|FSU","6p0",2055,0.251788912875694 -"30|FSU","6p0",2060,0.256608818869273 -"30|FSU","6p0",2065,0.259119459767089 -"30|FSU","6p0",2070,0.271770956210324 -"30|FSU","6p0",2075,0.292604942153969 -"30|FSU","6p0",2080,0.324692785428016 -"30|FSU","6p0",2085,0.369606059792424 -"30|FSU","6p0",2090,0.422419625196921 -"30|MEA","6p0",2020,0.180626413547295 -"30|MEA","6p0",2025,0.190600166777887 -"30|MEA","6p0",2030,0.214037947958524 -"30|MEA","6p0",2035,0.257901828387039 -"30|MEA","6p0",2040,0.319570679753288 -"30|MEA","6p0",2045,0.3923749039367 -"30|MEA","6p0",2050,0.473253251140424 -"30|MEA","6p0",2055,0.575090801055536 -"30|MEA","6p0",2060,0.698175531214269 -"30|MEA","6p0",2065,0.853316230332407 -"30|MEA","6p0",2070,1.06730545552426 -"30|MEA","6p0",2075,1.34645965368039 -"30|MEA","6p0",2080,1.68107093177691 -"30|MEA","6p0",2085,2.13952086318622 -"30|MEA","6p0",2090,2.72841104515832 -"31|FSU","6p0",2020,0.0736999151137129 -"31|FSU","6p0",2025,0.0844244375245657 -"31|FSU","6p0",2030,0.102292089547884 -"31|FSU","6p0",2035,0.143771683192389 -"31|FSU","6p0",2040,0.17469855351772 -"31|FSU","6p0",2045,0.19696149088602 -"31|FSU","6p0",2050,0.215217105874508 -"31|FSU","6p0",2055,0.219922883763506 -"31|FSU","6p0",2060,0.231402024046406 -"31|FSU","6p0",2065,0.249835235494507 -"31|FSU","6p0",2070,0.268990669427566 -"31|FSU","6p0",2075,0.295227865034571 -"31|FSU","6p0",2080,0.329044491032998 -"31|FSU","6p0",2085,0.361148611983846 -"31|FSU","6p0",2090,0.384154811610763 -"31|MEA","6p0",2020,0.153731075366543 -"31|MEA","6p0",2025,0.160695279450667 -"31|MEA","6p0",2030,0.181066185142932 -"31|MEA","6p0",2035,0.215719889842042 -"31|MEA","6p0",2040,0.264417635765198 -"31|MEA","6p0",2045,0.328369533481093 -"31|MEA","6p0",2050,0.393709232861004 -"31|MEA","6p0",2055,0.476732705799372 -"31|MEA","6p0",2060,0.576907790821457 -"31|MEA","6p0",2065,0.698587005060057 -"31|MEA","6p0",2070,0.899686282846483 -"31|MEA","6p0",2075,1.13206078841562 -"31|MEA","6p0",2080,1.42490099460842 -"31|MEA","6p0",2085,1.81582096782521 -"31|MEA","6p0",2090,2.30783922190731 -"31|WEU","6p0",2020,0.124740941038581 -"31|WEU","6p0",2025,0.138645823747585 -"31|WEU","6p0",2030,0.15649425640605 -"31|WEU","6p0",2035,0.18338542443008 -"31|WEU","6p0",2040,0.206629724113813 -"31|WEU","6p0",2045,0.23334139216613 -"31|WEU","6p0",2050,0.262786948266324 -"31|WEU","6p0",2055,0.294167383047042 -"31|WEU","6p0",2060,0.328907919359673 -"31|WEU","6p0",2065,0.36800549812985 -"31|WEU","6p0",2070,0.414664540040634 -"31|WEU","6p0",2075,0.462816781608564 -"31|WEU","6p0",2080,0.523164614416783 -"31|WEU","6p0",2085,0.59599206743695 -"31|WEU","6p0",2090,0.665158568043882 -"32|LAM","6p0",2020,0.0958953211363733 -"32|LAM","6p0",2025,0.0994531945730305 -"32|LAM","6p0",2030,0.104765433891383 -"32|LAM","6p0",2035,0.11714775240689 -"32|LAM","6p0",2040,0.131309317521167 -"32|LAM","6p0",2045,0.14738624008309 -"32|LAM","6p0",2050,0.168773471090381 -"32|LAM","6p0",2055,0.19862135204532 -"32|LAM","6p0",2060,0.227622542569042 -"32|LAM","6p0",2065,0.267937830367585 -"32|LAM","6p0",2070,0.31795811489558 -"32|LAM","6p0",2075,0.384281107531587 -"32|LAM","6p0",2080,0.477909759094847 -"32|LAM","6p0",2085,0.578643590121776 -"32|LAM","6p0",2090,0.689862793742624 -"33|LAM","6p0",2020,0.133612507971118 -"33|LAM","6p0",2025,0.140003186340221 -"33|LAM","6p0",2030,0.150495961659684 -"33|LAM","6p0",2035,0.174021475550411 -"33|LAM","6p0",2040,0.198286244283033 -"33|LAM","6p0",2045,0.226385852189759 -"33|LAM","6p0",2050,0.264051846683487 -"33|LAM","6p0",2055,0.313780968640947 -"33|LAM","6p0",2060,0.365913674681962 -"33|LAM","6p0",2065,0.437968417554884 -"33|LAM","6p0",2070,0.52796871988022 -"33|LAM","6p0",2075,0.641087516252983 -"33|LAM","6p0",2080,0.780865408422928 -"33|LAM","6p0",2085,0.934515990255845 -"33|LAM","6p0",2090,1.10388384742096 -"33|NAM","6p0",2020,6.31387050326581 -"33|NAM","6p0",2025,6.96470998811467 -"33|NAM","6p0",2030,7.55675436047726 -"33|NAM","6p0",2035,8.28105476862641 -"33|NAM","6p0",2040,8.76574071387243 -"33|NAM","6p0",2045,9.15232930798904 -"33|NAM","6p0",2050,9.68062794254345 -"33|NAM","6p0",2055,10.3489630520593 -"33|NAM","6p0",2060,10.6283308235843 -"33|NAM","6p0",2065,11.2981444575407 -"33|NAM","6p0",2070,11.6075221288001 -"33|NAM","6p0",2075,12.2242513309099 -"33|NAM","6p0",2080,12.9131349033191 -"33|NAM","6p0",2085,13.6314829933511 -"33|NAM","6p0",2090,14.4727743901223 -"34|MEA","6p0",2020,0.144492367177246 -"34|MEA","6p0",2025,0.150695146101044 -"34|MEA","6p0",2030,0.164110194158053 -"34|MEA","6p0",2035,0.192928072099917 -"34|MEA","6p0",2040,0.233723210402438 -"34|MEA","6p0",2045,0.283174975043336 -"34|MEA","6p0",2050,0.345387920236517 -"34|MEA","6p0",2055,0.420057836063001 -"34|MEA","6p0",2060,0.507873132350185 -"34|MEA","6p0",2065,0.613648538480218 -"34|MEA","6p0",2070,0.757029342592495 -"34|MEA","6p0",2075,0.936203838548667 -"34|MEA","6p0",2080,1.17841804245142 -"34|MEA","6p0",2085,1.50850434064611 -"34|MEA","6p0",2090,1.9404672499308 -"35|CHN","6p0",2020,1.78077216046252 -"35|CHN","6p0",2025,2.85233541246099 -"35|CHN","6p0",2030,4.18186739445532 -"35|CHN","6p0",2035,6.39395879783345 -"35|CHN","6p0",2040,8.77480507832931 -"35|CHN","6p0",2045,11.5584339707921 -"35|CHN","6p0",2050,14.4746854405805 -"35|CHN","6p0",2055,17.6325526841371 -"35|CHN","6p0",2060,21.4499832111574 -"35|CHN","6p0",2065,25.3416997821896 -"35|CHN","6p0",2070,30.3784270178438 -"35|CHN","6p0",2075,35.6477812934578 -"35|CHN","6p0",2080,40.8747543884726 -"35|CHN","6p0",2085,47.3015848941329 -"35|CHN","6p0",2090,54.1860116643572 -"36|NAM","6p0",2020,2.57300596417689 -"36|NAM","6p0",2025,2.70232858353236 -"36|NAM","6p0",2030,2.81132603930659 -"36|NAM","6p0",2035,2.96379406878018 -"36|NAM","6p0",2040,3.09065409620613 -"36|NAM","6p0",2045,3.22881155444166 -"36|NAM","6p0",2050,3.3346092752583 -"36|NAM","6p0",2055,3.43127437788771 -"36|NAM","6p0",2060,3.56129053147447 -"36|NAM","6p0",2065,3.66820030579846 -"36|NAM","6p0",2070,3.826945420369 -"36|NAM","6p0",2075,3.92406513858149 -"36|NAM","6p0",2080,4.0621044332153 -"36|NAM","6p0",2085,4.19978218093779 -"36|NAM","6p0",2090,4.32623363133156 -"37|LAM","6p0",2020,0.00219463079472335 -"37|LAM","6p0",2025,0.00234451790223321 -"37|LAM","6p0",2030,0.0025894458317602 -"37|LAM","6p0",2035,0.00309282879173313 -"37|LAM","6p0",2040,0.00379361841987881 -"37|LAM","6p0",2045,0.0048217482976128 -"37|LAM","6p0",2050,0.00630228892023621 -"37|LAM","6p0",2055,0.00849431035641128 -"37|LAM","6p0",2060,0.0114628839187059 -"37|LAM","6p0",2065,0.015537714496786 -"37|LAM","6p0",2070,0.0217884368718699 -"37|LAM","6p0",2075,0.0309028281959998 -"37|LAM","6p0",2080,0.0444945643213874 -"37|LAM","6p0",2085,0.0628704881822149 -"37|LAM","6p0",2090,0.0875379855035827 -"38|AFR","6p0",2020,5.69330073801738e-05 -"38|AFR","6p0",2025,7.81869547297246e-05 -"38|AFR","6p0",2030,0.000128075565758171 -"38|AFR","6p0",2035,0.000244195781409209 -"38|AFR","6p0",2040,0.000431714392791216 -"38|AFR","6p0",2045,0.00074509963943246 -"38|AFR","6p0",2050,0.00135556689026043 -"38|AFR","6p0",2055,0.00259314931586365 -"38|AFR","6p0",2060,0.00486225742947438 -"38|AFR","6p0",2065,0.0095137911510512 -"38|AFR","6p0",2070,0.0175068348626976 -"38|AFR","6p0",2075,0.0310991375921398 -"38|AFR","6p0",2080,0.0531116767841953 -"38|AFR","6p0",2085,0.084445233347044 -"38|AFR","6p0",2090,0.125062813828378 -"39|EEU","6p0",2020,0.000263816096786059 -"39|EEU","6p0",2025,0.000552474313465196 -"39|EEU","6p0",2030,0.000998197936995446 -"39|EEU","6p0",2035,0.00183756659024871 -"39|EEU","6p0",2040,0.00289531836547257 -"39|EEU","6p0",2045,0.00425701907571207 -"39|EEU","6p0",2050,0.00598130727094273 -"39|EEU","6p0",2055,0.00712632265170255 -"39|EEU","6p0",2060,0.0080847212240945 -"39|EEU","6p0",2065,0.00873909968004982 -"39|EEU","6p0",2070,0.00835313220641063 -"39|EEU","6p0",2075,0.0109937505819739 -"39|EEU","6p0",2080,0.0154049735351944 -"39|EEU","6p0",2085,0.0217797878360616 -"39|EEU","6p0",2090,0.0296407341388077 -"39|FSU","6p0",2020,0.00496822689571456 -"39|FSU","6p0",2025,0.00561027392371846 -"39|FSU","6p0",2030,0.00675971634376638 -"39|FSU","6p0",2035,0.00965940644921248 -"39|FSU","6p0",2040,0.0134418343767379 -"39|FSU","6p0",2045,0.0190118691378594 -"39|FSU","6p0",2050,0.026462443005068 -"39|FSU","6p0",2055,0.0344097566012622 -"39|FSU","6p0",2060,0.0453628838493398 -"39|FSU","6p0",2065,0.0582864381771739 -"39|FSU","6p0",2070,0.0742380107436341 -"39|FSU","6p0",2075,0.103981418266249 -"39|FSU","6p0",2080,0.142367262552373 -"39|FSU","6p0",2085,0.192825042050109 -"39|FSU","6p0",2090,0.251689346534752 -"39|WEU","6p0",2020,0.0166771783054075 -"39|WEU","6p0",2025,0.0184338510600381 -"39|WEU","6p0",2030,0.0196567942019225 -"39|WEU","6p0",2035,0.0219824432623796 -"39|WEU","6p0",2040,0.0249797420173501 -"39|WEU","6p0",2045,0.0289010254541543 -"39|WEU","6p0",2050,0.0340069390791072 -"39|WEU","6p0",2055,0.0390913057296265 -"39|WEU","6p0",2060,0.0467481886469857 -"39|WEU","6p0",2065,0.0565499578317601 -"39|WEU","6p0",2070,0.067658656168658 -"39|WEU","6p0",2075,0.0872079995597218 -"39|WEU","6p0",2080,0.112877540430839 -"39|WEU","6p0",2085,0.14474546190396 -"39|WEU","6p0",2090,0.185918421202241 -"3|MEA","6p0",2020,0.568309320349596 -"3|MEA","6p0",2025,0.639126236713779 -"3|MEA","6p0",2030,0.715535631523513 -"3|MEA","6p0",2035,0.853869526675523 -"3|MEA","6p0",2040,1.01111636032585 -"3|MEA","6p0",2045,1.20816333904911 -"3|MEA","6p0",2050,1.44120402614422 -"3|MEA","6p0",2055,1.75714524640133 -"3|MEA","6p0",2060,2.16512653256798 -"3|MEA","6p0",2065,2.73088407135096 -"3|MEA","6p0",2070,3.43614384091768 -"3|MEA","6p0",2075,4.31626065401257 -"3|MEA","6p0",2080,5.42621115390763 -"3|MEA","6p0",2085,6.78541092897769 -"3|MEA","6p0",2090,8.50867784209079 -"40|MEA","6p0",2020,3.03275358954709 -"40|MEA","6p0",2025,3.22832851644391 -"40|MEA","6p0",2030,3.51589597391376 -"40|MEA","6p0",2035,3.78843042074562 -"40|MEA","6p0",2040,3.92692284503647 -"40|MEA","6p0",2045,4.11273261507008 -"40|MEA","6p0",2050,4.23165196984864 -"40|MEA","6p0",2055,4.49968584264448 -"40|MEA","6p0",2060,4.74508138603472 -"40|MEA","6p0",2065,5.1249265303617 -"40|MEA","6p0",2070,5.71768501726738 -"40|MEA","6p0",2075,6.3281482385687 -"40|MEA","6p0",2080,7.21807148205753 -"40|MEA","6p0",2085,8.25643866973181 -"40|MEA","6p0",2090,9.40711772455441 -"41|WEU","6p0",2020,0.0211403242082596 -"41|WEU","6p0",2025,0.0245991072438415 -"41|WEU","6p0",2030,0.0271320005195873 -"41|WEU","6p0",2035,0.0316148992250169 -"41|WEU","6p0",2040,0.0371157165911365 -"41|WEU","6p0",2045,0.0436798082572037 -"41|WEU","6p0",2050,0.052835471908632 -"41|WEU","6p0",2055,0.0605792082391057 -"41|WEU","6p0",2060,0.0724812221059344 -"41|WEU","6p0",2065,0.087408337582347 -"41|WEU","6p0",2070,0.104317946179305 -"41|WEU","6p0",2075,0.132179622020106 -"41|WEU","6p0",2080,0.171095326952311 -"41|WEU","6p0",2085,0.214716659413344 -"41|WEU","6p0",2090,0.273384946417078 -"42|FSU","6p0",2020,0.0269369576868714 -"42|FSU","6p0",2025,0.0298903648608786 -"42|FSU","6p0",2030,0.0350412839241017 -"42|FSU","6p0",2035,0.0476603474870443 -"42|FSU","6p0",2040,0.0580485709640966 -"42|FSU","6p0",2045,0.069656052306609 -"42|FSU","6p0",2050,0.0810704524201798 -"42|FSU","6p0",2055,0.0851254851452831 -"42|FSU","6p0",2060,0.0920672564385434 -"42|FSU","6p0",2065,0.0959882348659675 -"42|FSU","6p0",2070,0.0999011688669254 -"42|FSU","6p0",2075,0.120479084381051 -"42|FSU","6p0",2080,0.149301733783549 -"42|FSU","6p0",2085,0.183653704999142 -"42|FSU","6p0",2090,0.220119048740792 -"43|FSU","6p0",2020,0.00498269715981773 -"43|FSU","6p0",2025,0.00567377356526281 -"43|FSU","6p0",2030,0.00689040894560505 -"43|FSU","6p0",2035,0.0101646585114763 -"43|FSU","6p0",2040,0.0146961845741043 -"43|FSU","6p0",2045,0.0219102247588014 -"43|FSU","6p0",2050,0.0316979882602103 -"43|FSU","6p0",2055,0.039970576710486 -"43|FSU","6p0",2060,0.0500206673239628 -"43|FSU","6p0",2065,0.058311435406178 -"43|FSU","6p0",2070,0.0670002374038212 -"43|FSU","6p0",2075,0.0944406054396023 -"43|FSU","6p0",2080,0.130710211981429 -"43|FSU","6p0",2085,0.179915783554218 -"43|FSU","6p0",2090,0.234592511975394 -"44|FSU","6p0",2020,0.0799324692835826 -"44|FSU","6p0",2025,0.0891468278172585 -"44|FSU","6p0",2030,0.104762242548459 -"44|FSU","6p0",2035,0.142458656964893 -"44|FSU","6p0",2040,0.168914868012153 -"44|FSU","6p0",2045,0.190939422668752 -"44|FSU","6p0",2050,0.21078771593702 -"44|FSU","6p0",2055,0.210645903833078 -"44|FSU","6p0",2060,0.217180836220262 -"44|FSU","6p0",2065,0.222936237024359 -"44|FSU","6p0",2070,0.225395360050541 -"44|FSU","6p0",2075,0.246409403656795 -"44|FSU","6p0",2080,0.274993390534351 -"44|FSU","6p0",2085,0.303472471943234 -"44|FSU","6p0",2090,0.32425118611684 -"45|WEU","6p0",2020,1.4225694937682 -"45|WEU","6p0",2025,1.52883388760096 -"45|WEU","6p0",2030,1.59290287063112 -"45|WEU","6p0",2035,1.68038815981493 -"45|WEU","6p0",2040,1.73394900268313 -"45|WEU","6p0",2045,1.80211257976036 -"45|WEU","6p0",2050,1.86707357251382 -"45|WEU","6p0",2055,1.96903197293266 -"45|WEU","6p0",2060,2.12484791331499 -"45|WEU","6p0",2065,2.33269799747254 -"45|WEU","6p0",2070,2.61378783397703 -"45|WEU","6p0",2075,3.00123888620256 -"45|WEU","6p0",2080,3.3708198199779 -"45|WEU","6p0",2085,3.88356175772716 -"45|WEU","6p0",2090,4.37890583855729 -"46|LAM","6p0",2020,0.0223840075942231 -"46|LAM","6p0",2025,0.0230975918030641 -"46|LAM","6p0",2030,0.0247567262245908 -"46|LAM","6p0",2035,0.02775557816365 -"46|LAM","6p0",2040,0.0309480955489398 -"46|LAM","6p0",2045,0.0361429216993634 -"46|LAM","6p0",2050,0.043149109899218 -"46|LAM","6p0",2055,0.0517209063115772 -"46|LAM","6p0",2060,0.0636022140484731 -"46|LAM","6p0",2065,0.0753704182510952 -"46|LAM","6p0",2070,0.0891885442449782 -"46|LAM","6p0",2075,0.105601280580769 -"46|LAM","6p0",2080,0.126981194748414 -"46|LAM","6p0",2085,0.151734616621387 -"46|LAM","6p0",2090,0.18376901837908 -"47|WEU","6p0",2020,1.29019167232257 -"47|WEU","6p0",2025,1.40538313082465 -"47|WEU","6p0",2030,1.47092807871924 -"47|WEU","6p0",2035,1.56331684821558 -"47|WEU","6p0",2040,1.61894402854376 -"47|WEU","6p0",2045,1.69292476615412 -"47|WEU","6p0",2050,1.76404312470983 -"47|WEU","6p0",2055,1.87794173264752 -"47|WEU","6p0",2060,2.04094541466536 -"47|WEU","6p0",2065,2.2502500257638 -"47|WEU","6p0",2070,2.52434339917977 -"47|WEU","6p0",2075,2.8896507458966 -"47|WEU","6p0",2080,3.23978161286086 -"47|WEU","6p0",2085,3.70709655696578 -"47|WEU","6p0",2090,4.21305289354963 -"48|WEU","6p0",2020,0.0719101070285133 -"48|WEU","6p0",2025,0.0782734186233036 -"48|WEU","6p0",2030,0.0819153017849602 -"48|WEU","6p0",2035,0.0902612972140211 -"48|WEU","6p0",2040,0.0993365567215862 -"48|WEU","6p0",2045,0.109941867003855 -"48|WEU","6p0",2050,0.123329449097675 -"48|WEU","6p0",2055,0.134881099972702 -"48|WEU","6p0",2060,0.154066324534333 -"48|WEU","6p0",2065,0.176156211929749 -"48|WEU","6p0",2070,0.201683397400349 -"48|WEU","6p0",2075,0.242954622040332 -"48|WEU","6p0",2080,0.295994407598401 -"48|WEU","6p0",2085,0.354409796234338 -"48|WEU","6p0",2090,0.429178778824604 -"49|WEU","6p0",2020,0.109924419674352 -"49|WEU","6p0",2025,0.115161989451339 -"49|WEU","6p0",2030,0.117880328609239 -"49|WEU","6p0",2035,0.124966375664822 -"49|WEU","6p0",2040,0.131368312516864 -"49|WEU","6p0",2045,0.137983673944397 -"49|WEU","6p0",2050,0.144970869855056 -"49|WEU","6p0",2055,0.152039902017824 -"49|WEU","6p0",2060,0.16239241083783 -"49|WEU","6p0",2065,0.17531131128887 -"49|WEU","6p0",2070,0.192233518958461 -"49|WEU","6p0",2075,0.211068959022702 -"49|WEU","6p0",2080,0.236929604252214 -"49|WEU","6p0",2085,0.262505194756327 -"49|WEU","6p0",2090,0.290612456123849 -"4|MEA","6p0",2020,0.112147458160782 -"4|MEA","6p0",2025,0.119284839405542 -"4|MEA","6p0",2030,0.137615762244329 -"4|MEA","6p0",2035,0.181152984737925 -"4|MEA","6p0",2040,0.243185639212703 -"4|MEA","6p0",2045,0.344425433662503 -"4|MEA","6p0",2050,0.463852211800649 -"4|MEA","6p0",2055,0.636847424365109 -"4|MEA","6p0",2060,0.848301371283654 -"4|MEA","6p0",2065,1.11384166665013 -"4|MEA","6p0",2070,1.52587394571762 -"4|MEA","6p0",2075,2.08787349090553 -"4|MEA","6p0",2080,2.83977686765062 -"4|MEA","6p0",2085,3.80647820722032 -"4|MEA","6p0",2090,4.93884899202347 -"4|WEU","6p0",2020,1.73413834114386 -"4|WEU","6p0",2025,1.94603863454535 -"4|WEU","6p0",2030,2.13155116942873 -"4|WEU","6p0",2035,2.31837535297471 -"4|WEU","6p0",2040,2.45020130985783 -"4|WEU","6p0",2045,2.64644659933312 -"4|WEU","6p0",2050,2.72325579056145 -"4|WEU","6p0",2055,3.02571048124984 -"4|WEU","6p0",2060,3.39994575299722 -"4|WEU","6p0",2065,3.79412047879884 -"4|WEU","6p0",2070,4.47620993371052 -"4|WEU","6p0",2075,5.17853514826808 -"4|WEU","6p0",2080,5.81910191685624 -"4|WEU","6p0",2085,6.63159824195005 -"4|WEU","6p0",2090,7.73708699224075 -"50|MEA","6p0",2020,0.125268539237754 -"50|MEA","6p0",2025,0.130226030232199 -"50|MEA","6p0",2030,0.138156817658597 -"50|MEA","6p0",2035,0.16064712539715 -"50|MEA","6p0",2040,0.191483240304319 -"50|MEA","6p0",2045,0.228248562275833 -"50|MEA","6p0",2050,0.282527438862806 -"50|MEA","6p0",2055,0.345020764371835 -"50|MEA","6p0",2060,0.414616677593272 -"50|MEA","6p0",2065,0.500440393571082 -"50|MEA","6p0",2070,0.608751653560656 -"50|MEA","6p0",2075,0.753171490911532 -"50|MEA","6p0",2080,0.95220374622337 -"50|MEA","6p0",2085,1.22287751990569 -"50|MEA","6p0",2090,1.58544247960515 -"50|SAS","6p0",2020,0.0549106369537663 -"50|SAS","6p0",2025,0.0587405753659065 -"50|SAS","6p0",2030,0.0625084908873949 -"50|SAS","6p0",2035,0.0716300169765599 -"50|SAS","6p0",2040,0.0836975037815558 -"50|SAS","6p0",2045,0.10237703468777 -"50|SAS","6p0",2050,0.134176215840997 -"50|SAS","6p0",2055,0.183220355688925 -"50|SAS","6p0",2060,0.255822312268733 -"50|SAS","6p0",2065,0.349482597985463 -"50|SAS","6p0",2070,0.481515551576165 -"50|SAS","6p0",2075,0.662790727145271 -"50|SAS","6p0",2080,0.894616059968521 -"50|SAS","6p0",2085,1.24387630928607 -"50|SAS","6p0",2090,1.73260431102216 -"51|FSU","6p0",2020,0.0746488464884602 -"51|FSU","6p0",2025,0.0794536117976585 -"51|FSU","6p0",2030,0.0887337557811293 -"51|FSU","6p0",2035,0.109243724848956 -"51|FSU","6p0",2040,0.124427087745082 -"51|FSU","6p0",2045,0.136665519880408 -"51|FSU","6p0",2050,0.145405623896746 -"51|FSU","6p0",2055,0.144565288505593 -"51|FSU","6p0",2060,0.144491517799326 -"51|FSU","6p0",2065,0.142508914354527 -"51|FSU","6p0",2070,0.137957838484122 -"51|FSU","6p0",2075,0.143930989583215 -"51|FSU","6p0",2080,0.1530040895535 -"51|FSU","6p0",2085,0.158741265500277 -"51|FSU","6p0",2090,0.165940088908003 -"51|WEU","6p0",2020,0.000500100302829146 -"51|WEU","6p0",2025,0.000504652600175231 -"51|WEU","6p0",2030,0.000510023594464587 -"51|WEU","6p0",2035,0.000520299897748037 -"51|WEU","6p0",2040,0.000534885997624234 -"51|WEU","6p0",2045,0.000555481015071759 -"51|WEU","6p0",2050,0.000583647156000697 -"51|WEU","6p0",2055,0.000622290690890989 -"51|WEU","6p0",2060,0.000673521579635402 -"51|WEU","6p0",2065,0.000750093080006713 -"51|WEU","6p0",2070,0.000858743900715483 -"51|WEU","6p0",2075,0.00103373412475711 -"51|WEU","6p0",2080,0.00131402445150295 -"51|WEU","6p0",2085,0.00166336893866833 -"51|WEU","6p0",2090,0.00221005291294571 -"52|NAM","6p0",2020,0.465428038511642 -"52|NAM","6p0",2025,0.467107586681561 -"52|NAM","6p0",2030,0.468820326708544 -"52|NAM","6p0",2035,0.471180472209845 -"52|NAM","6p0",2040,0.472841624150281 -"52|NAM","6p0",2045,0.475522479193249 -"52|NAM","6p0",2050,0.477187915792609 -"52|NAM","6p0",2055,0.478324578744789 -"52|NAM","6p0",2060,0.480300941142662 -"52|NAM","6p0",2065,0.481738340495095 -"52|NAM","6p0",2070,0.483917134604494 -"52|NAM","6p0",2075,0.482051573956631 -"52|NAM","6p0",2080,0.485412500403545 -"52|NAM","6p0",2085,0.488995709265887 -"52|NAM","6p0",2090,0.49265727638757 -"53|CHN","6p0",2020,0 -"53|CHN","6p0",2025,0 -"53|CHN","6p0",2030,0 -"53|CHN","6p0",2035,0 -"53|CHN","6p0",2040,0 -"53|CHN","6p0",2045,0.00521753122539164 -"53|CHN","6p0",2050,0.0462579463535085 -"53|CHN","6p0",2055,0.0757575390199121 -"53|CHN","6p0",2060,0.115906170327452 -"53|CHN","6p0",2065,0.152976339160197 -"53|CHN","6p0",2070,0.189123951078768 -"53|CHN","6p0",2075,0.231844420433603 -"53|CHN","6p0",2080,0.286100351656562 -"53|CHN","6p0",2085,0.330515803086383 -"53|CHN","6p0",2090,0.384325190207513 -"53|SAS","6p0",2020,0.306236370632862 -"53|SAS","6p0",2025,0.436040536817172 -"53|SAS","6p0",2030,0.5700434865516 -"53|SAS","6p0",2035,0.803916364225496 -"53|SAS","6p0",2040,1.08767346663372 -"53|SAS","6p0",2045,1.46437964420853 -"53|SAS","6p0",2050,1.94607797843082 -"53|SAS","6p0",2055,2.56914128040657 -"53|SAS","6p0",2060,3.45474015275653 -"53|SAS","6p0",2065,4.48123821590069 -"53|SAS","6p0",2070,5.87498127095647 -"53|SAS","6p0",2075,7.48130138428862 -"53|SAS","6p0",2080,9.54060119339855 -"53|SAS","6p0",2085,12.2770747106688 -"53|SAS","6p0",2090,15.3496782875665 -"54|CHN","6p0",2020,1.24974385853273 -"54|CHN","6p0",2025,2.03778452449343 -"54|CHN","6p0",2030,3.04100117645757 -"54|CHN","6p0",2035,4.71346207974964 -"54|CHN","6p0",2040,6.45682664933293 -"54|CHN","6p0",2045,8.42859747639568 -"54|CHN","6p0",2050,10.6150302538952 -"54|CHN","6p0",2055,12.4339815526312 -"54|CHN","6p0",2060,14.4703081523057 -"54|CHN","6p0",2065,16.5719526181687 -"54|CHN","6p0",2070,18.6848834291823 -"54|CHN","6p0",2075,21.6652877637572 -"54|CHN","6p0",2080,24.959699520326 -"54|CHN","6p0",2085,28.3548764003506 -"54|CHN","6p0",2090,32.2202878752793 -"54|FSU","6p0",2020,0.074893065512751 -"54|FSU","6p0",2025,0.0795209151159297 -"54|FSU","6p0",2030,0.0888787696379346 -"54|FSU","6p0",2035,0.110130849176436 -"54|FSU","6p0",2040,0.127429893881879 -"54|FSU","6p0",2045,0.142369744402141 -"54|FSU","6p0",2050,0.155319728981615 -"54|FSU","6p0",2055,0.162225822960553 -"54|FSU","6p0",2060,0.169083670447589 -"54|FSU","6p0",2065,0.181849478551644 -"54|FSU","6p0",2070,0.196903468818659 -"54|FSU","6p0",2075,0.218613991935903 -"54|FSU","6p0",2080,0.236047343508404 -"54|FSU","6p0",2085,0.244568006176139 -"54|FSU","6p0",2090,0.248207527182352 -"55|NAM","6p0",2020,3.77450854399706 -"55|NAM","6p0",2025,4.06814911784786 -"55|NAM","6p0",2030,4.29998291666461 -"55|NAM","6p0",2035,4.63014734780394 -"55|NAM","6p0",2040,5.01438238566165 -"55|NAM","6p0",2045,5.22985890937021 -"55|NAM","6p0",2050,5.41902687545907 -"55|NAM","6p0",2055,5.64756539749638 -"55|NAM","6p0",2060,5.83079187887666 -"55|NAM","6p0",2065,6.10877361583435 -"55|NAM","6p0",2070,6.48549328017099 -"55|NAM","6p0",2075,6.70198860766797 -"55|NAM","6p0",2080,6.94440978740038 -"55|NAM","6p0",2085,7.17654307761889 -"55|NAM","6p0",2090,7.31773076181905 -"56|NAM","6p0",2020,4.02700181990485 -"56|NAM","6p0",2025,4.34236552646016 -"56|NAM","6p0",2030,4.5621380265754 -"56|NAM","6p0",2035,4.90311759048739 -"56|NAM","6p0",2040,5.19545050123018 -"56|NAM","6p0",2045,5.36460440058677 -"56|NAM","6p0",2050,5.59637852006866 -"56|NAM","6p0",2055,5.86194882045479 -"56|NAM","6p0",2060,6.06360424203716 -"56|NAM","6p0",2065,6.30300333571964 -"56|NAM","6p0",2070,6.548282293565 -"56|NAM","6p0",2075,6.82228052093167 -"56|NAM","6p0",2080,7.1367896502711 -"56|NAM","6p0",2085,7.68352552520896 -"56|NAM","6p0",2090,8.09472523706147 -"57|AFR","6p0",2020,0.0015948285342423 -"57|AFR","6p0",2025,0.00172968668342145 -"57|AFR","6p0",2030,0.00234250246510946 -"57|AFR","6p0",2035,0.00379603429600773 -"57|AFR","6p0",2040,0.00632397741233099 -"57|AFR","6p0",2045,0.0112979287907775 -"57|AFR","6p0",2050,0.0201490243320435 -"57|AFR","6p0",2055,0.0414176786310292 -"57|AFR","6p0",2060,0.0809394531302428 -"57|AFR","6p0",2065,0.151391389559807 -"57|AFR","6p0",2070,0.279416167365716 -"57|AFR","6p0",2075,0.49256465186311 -"57|AFR","6p0",2080,0.841606643743724 -"57|AFR","6p0",2085,1.39909220842597 -"57|AFR","6p0",2090,2.25423857667117 -"58|NAM","6p0",2020,2.94839504189904 -"58|NAM","6p0",2025,3.07781862714988 -"58|NAM","6p0",2030,3.15686837772887 -"58|NAM","6p0",2035,3.31998271844963 -"58|NAM","6p0",2040,3.48132081455483 -"58|NAM","6p0",2045,3.56549387067685 -"58|NAM","6p0",2050,3.64781768839221 -"58|NAM","6p0",2055,3.69619987286156 -"58|NAM","6p0",2060,3.73270206852927 -"58|NAM","6p0",2065,3.8272016727791 -"58|NAM","6p0",2070,4.00978144769466 -"58|NAM","6p0",2075,4.2129431996085 -"58|NAM","6p0",2080,4.37968932158531 -"58|NAM","6p0",2085,4.62877648930016 -"58|NAM","6p0",2090,4.77581205932895 -"59|PAS","6p0",2020,0.0393710697291899 -"59|PAS","6p0",2025,0.0471539874957968 -"59|PAS","6p0",2030,0.0578624255712021 -"59|PAS","6p0",2035,0.0754261040264438 -"59|PAS","6p0",2040,0.0956723624323419 -"59|PAS","6p0",2045,0.120485156647322 -"59|PAS","6p0",2050,0.148126513115576 -"59|PAS","6p0",2055,0.186522224951219 -"59|PAS","6p0",2060,0.231973058952791 -"59|PAS","6p0",2065,0.290554193386528 -"59|PAS","6p0",2070,0.365777365275805 -"59|PAS","6p0",2075,0.446928819345562 -"59|PAS","6p0",2080,0.533326959871369 -"59|PAS","6p0",2085,0.636142897625632 -"59|PAS","6p0",2090,0.758172534362781 -"59|RCPA","6p0",2020,0.0359525156666296 -"59|RCPA","6p0",2025,0.0529153540315809 -"59|RCPA","6p0",2030,0.0690152462753609 -"59|RCPA","6p0",2035,0.0959609805091942 -"59|RCPA","6p0",2040,0.122865616868484 -"59|RCPA","6p0",2045,0.158753841565885 -"59|RCPA","6p0",2050,0.204603808019226 -"59|RCPA","6p0",2055,0.260370479470303 -"59|RCPA","6p0",2060,0.338356409964519 -"59|RCPA","6p0",2065,0.453521176727343 -"59|RCPA","6p0",2070,0.577769638858437 -"59|RCPA","6p0",2075,0.735495834511103 -"59|RCPA","6p0",2080,0.909353633092615 -"59|RCPA","6p0",2085,1.08195438573231 -"59|RCPA","6p0",2090,1.32943096152256 -"5|AFR","6p0",2020,0.00120442004141422 -"5|AFR","6p0",2025,0.00265193628949565 -"5|AFR","6p0",2030,0.00495681337523501 -"5|AFR","6p0",2035,0.0105156574759201 -"5|AFR","6p0",2040,0.021508279601006 -"5|AFR","6p0",2045,0.0389809397623181 -"5|AFR","6p0",2050,0.0701268130213037 -"5|AFR","6p0",2055,0.129638692990257 -"5|AFR","6p0",2060,0.232623489709132 -"5|AFR","6p0",2065,0.399245591246754 -"5|AFR","6p0",2070,0.659325354177081 -"5|AFR","6p0",2075,0.993473548194522 -"5|AFR","6p0",2080,1.29255605816601 -"5|AFR","6p0",2085,1.85514605195144 -"5|AFR","6p0",2090,2.54946759253771 -"5|MEA","6p0",2020,0.145381445223126 -"5|MEA","6p0",2025,0.205124981215205 -"5|MEA","6p0",2030,0.286861509831929 -"5|MEA","6p0",2035,0.453219562374898 -"5|MEA","6p0",2040,0.630690698620491 -"5|MEA","6p0",2045,0.855676328965976 -"5|MEA","6p0",2050,1.14144919082389 -"5|MEA","6p0",2055,1.48500196298063 -"5|MEA","6p0",2060,1.92512144309862 -"5|MEA","6p0",2065,2.47442839525484 -"5|MEA","6p0",2070,3.20207957410353 -"5|MEA","6p0",2075,4.06427599150669 -"5|MEA","6p0",2080,5.11757137373731 -"5|MEA","6p0",2085,6.3785318143881 -"5|MEA","6p0",2090,7.89701992820211 -"60|CHN","6p0",2020,0.676002388319727 -"60|CHN","6p0",2025,1.08623544685392 -"60|CHN","6p0",2030,1.68997810497114 -"60|CHN","6p0",2035,2.62914500345633 -"60|CHN","6p0",2040,3.63609707494066 -"60|CHN","6p0",2045,4.86893370840421 -"60|CHN","6p0",2050,6.11161918692283 -"60|CHN","6p0",2055,7.57048267880688 -"60|CHN","6p0",2060,9.23815449201345 -"60|CHN","6p0",2065,10.6540564141283 -"60|CHN","6p0",2070,12.0712913475102 -"60|CHN","6p0",2075,13.4224833843152 -"60|CHN","6p0",2080,14.8279943639415 -"60|CHN","6p0",2085,17.2827195141833 -"60|CHN","6p0",2090,19.8569853606631 -"61|CHN","6p0",2020,0.535352656812263 -"61|CHN","6p0",2025,0.909838510692483 -"61|CHN","6p0",2030,1.40266383839022 -"61|CHN","6p0",2035,2.22197675627593 -"61|CHN","6p0",2040,3.04929856080924 -"61|CHN","6p0",2045,4.14015757999986 -"61|CHN","6p0",2050,5.2072531472989 -"61|CHN","6p0",2055,6.31669400417818 -"61|CHN","6p0",2060,7.83345027750946 -"61|CHN","6p0",2065,9.28356636778471 -"61|CHN","6p0",2070,10.6142768202144 -"61|CHN","6p0",2075,12.2440725277339 -"61|CHN","6p0",2080,13.8186219216888 -"61|CHN","6p0",2085,15.4932984559379 -"61|CHN","6p0",2090,17.7440964429614 -"61|RCPA","6p0",2020,0.0160825385639592 -"61|RCPA","6p0",2025,0.0213442721557301 -"61|RCPA","6p0",2030,0.0273517987369316 -"61|RCPA","6p0",2035,0.036768705657738 -"61|RCPA","6p0",2040,0.0460981365772916 -"61|RCPA","6p0",2045,0.0612391279619978 -"61|RCPA","6p0",2050,0.0790569434811801 -"61|RCPA","6p0",2055,0.104216375805411 -"61|RCPA","6p0",2060,0.137850695494632 -"61|RCPA","6p0",2065,0.180803869471593 -"61|RCPA","6p0",2070,0.228626473118468 -"61|RCPA","6p0",2075,0.282699180994133 -"61|RCPA","6p0",2080,0.344467129165189 -"61|RCPA","6p0",2085,0.407040853441541 -"61|RCPA","6p0",2090,0.502151080087295 -"62|CHN","6p0",2020,0.965154826241596 -"62|CHN","6p0",2025,1.62547969966534 -"62|CHN","6p0",2030,2.45164652332621 -"62|CHN","6p0",2035,3.79371433737476 -"62|CHN","6p0",2040,5.23609714627892 -"62|CHN","6p0",2045,6.65633779116343 -"62|CHN","6p0",2050,8.66388828190641 -"62|CHN","6p0",2055,10.2904193735833 -"62|CHN","6p0",2060,12.3112444690133 -"62|CHN","6p0",2065,14.6668728116064 -"62|CHN","6p0",2070,16.7444000951151 -"62|CHN","6p0",2075,19.4753553823022 -"62|CHN","6p0",2080,21.9359951742515 -"62|CHN","6p0",2085,24.7731343797892 -"62|CHN","6p0",2090,27.5450722497556 -"63|NAM","6p0",2020,0.0573816064880916 -"63|NAM","6p0",2025,0.0573899714423417 -"63|NAM","6p0",2030,0.0573981570745953 -"63|NAM","6p0",2035,0.0574116795725588 -"63|NAM","6p0",2040,0.0574290017299624 -"63|NAM","6p0",2045,0.0574511785319611 -"63|NAM","6p0",2050,0.0574811885003666 -"63|NAM","6p0",2055,0.0575024333741428 -"63|NAM","6p0",2060,0.0575278878571689 -"63|NAM","6p0",2065,0.057560304791704 -"63|NAM","6p0",2070,0.0575915100501722 -"63|NAM","6p0",2075,0.0576618711900352 -"63|NAM","6p0",2080,0.0577679430191759 -"63|NAM","6p0",2085,0.0578960705814324 -"63|NAM","6p0",2090,0.0580796232076825 -"65|SAS","6p0",2020,0.366989559558185 -"65|SAS","6p0",2025,0.525705297534255 -"65|SAS","6p0",2030,0.686668613844098 -"65|SAS","6p0",2035,0.966060622429227 -"65|SAS","6p0",2040,1.30352216281884 -"65|SAS","6p0",2045,1.73956501198511 -"65|SAS","6p0",2050,2.37452630444261 -"65|SAS","6p0",2055,3.18320393160928 -"65|SAS","6p0",2060,4.22968376453537 -"65|SAS","6p0",2065,5.47437941375246 -"65|SAS","6p0",2070,7.07183300839795 -"65|SAS","6p0",2075,8.99338978408481 -"65|SAS","6p0",2080,11.4535733202739 -"65|SAS","6p0",2085,14.7611207488474 -"65|SAS","6p0",2090,18.6512989168827 -"66|SAS","6p0",2020,0.288868737656208 -"66|SAS","6p0",2025,0.401067243068582 -"66|SAS","6p0",2030,0.527007570781395 -"66|SAS","6p0",2035,0.737932412998721 -"66|SAS","6p0",2040,0.986634831898666 -"66|SAS","6p0",2045,1.32834659871089 -"66|SAS","6p0",2050,1.80402492581158 -"66|SAS","6p0",2055,2.35242100196142 -"66|SAS","6p0",2060,3.14089430032411 -"66|SAS","6p0",2065,3.99807738177819 -"66|SAS","6p0",2070,5.15771389699758 -"66|SAS","6p0",2075,6.53178380521718 -"66|SAS","6p0",2080,8.29671371666787 -"66|SAS","6p0",2085,10.7423808137738 -"66|SAS","6p0",2090,13.5224642311601 -"67|CHN","6p0",2020,0 -"67|CHN","6p0",2025,0 -"67|CHN","6p0",2030,0.083146663465575 -"67|CHN","6p0",2035,0.25292706901484 -"67|CHN","6p0",2040,0.439983868481743 -"67|CHN","6p0",2045,0.656878279292182 -"67|CHN","6p0",2050,0.873752069604911 -"67|CHN","6p0",2055,1.00779314748358 -"67|CHN","6p0",2060,1.13141193538295 -"67|CHN","6p0",2065,1.22348769961794 -"67|CHN","6p0",2070,1.29588401763477 -"67|CHN","6p0",2075,1.47791368067568 -"67|CHN","6p0",2080,1.64623929911656 -"67|CHN","6p0",2085,1.74836012820466 -"67|CHN","6p0",2090,1.86236365507425 -"67|SAS","6p0",2020,0.102379148456279 -"67|SAS","6p0",2025,0.122398753311053 -"67|SAS","6p0",2030,0.142454548594776 -"67|SAS","6p0",2035,0.17975422468248 -"67|SAS","6p0",2040,0.230006387382995 -"67|SAS","6p0",2045,0.297529994133572 -"67|SAS","6p0",2050,0.392028501887707 -"67|SAS","6p0",2055,0.519249685575877 -"67|SAS","6p0",2060,0.680253926064004 -"67|SAS","6p0",2065,0.896522455669972 -"67|SAS","6p0",2070,1.19035587666465 -"67|SAS","6p0",2075,1.57607111612576 -"67|SAS","6p0",2080,2.09545144805113 -"67|SAS","6p0",2085,2.75717894620232 -"67|SAS","6p0",2090,3.54343306755815 -"68|WEU","6p0",2020,0.0161777522398462 -"68|WEU","6p0",2025,0.0166750998031253 -"68|WEU","6p0",2030,0.0169889273299016 -"68|WEU","6p0",2035,0.0176390672708869 -"68|WEU","6p0",2040,0.0182600248768824 -"68|WEU","6p0",2045,0.0189827076917654 -"68|WEU","6p0",2050,0.0198211264912815 -"68|WEU","6p0",2055,0.0206267058690813 -"68|WEU","6p0",2060,0.0217447135610444 -"68|WEU","6p0",2065,0.0233890584801986 -"68|WEU","6p0",2070,0.0253282455416877 -"68|WEU","6p0",2075,0.0276684610652519 -"68|WEU","6p0",2080,0.0311215463691062 -"68|WEU","6p0",2085,0.0349063089024289 -"68|WEU","6p0",2090,0.0398270480969767 -"69|PAS","6p0",2020,0.0747141667140417 -"69|PAS","6p0",2025,0.0750090230806069 -"69|PAS","6p0",2030,0.0754385988863847 -"69|PAS","6p0",2035,0.0761259974782559 -"69|PAS","6p0",2040,0.0769102034891852 -"69|PAS","6p0",2045,0.0778419902914787 -"69|PAS","6p0",2050,0.0788715245015107 -"69|PAS","6p0",2055,0.0805586239291348 -"69|PAS","6p0",2060,0.0828698624760078 -"69|PAS","6p0",2065,0.0859196593387483 -"69|PAS","6p0",2070,0.0897964999406785 -"69|PAS","6p0",2075,0.094285048241733 -"69|PAS","6p0",2080,0.0994722260342302 -"69|PAS","6p0",2085,0.105797366582665 -"69|PAS","6p0",2090,0.11364967799833 -"6|AFR","6p0",2020,0.000284540817011304 -"6|AFR","6p0",2025,0.000300784599518209 -"6|AFR","6p0",2030,0.00036685649196932 -"6|AFR","6p0",2035,0.000571390818042163 -"6|AFR","6p0",2040,0.000883250751662285 -"6|AFR","6p0",2045,0.00170997402309913 -"6|AFR","6p0",2050,0.00304815487854264 -"6|AFR","6p0",2055,0.0048547378666405 -"6|AFR","6p0",2060,0.00951922749279444 -"6|AFR","6p0",2065,0.0145079530801408 -"6|AFR","6p0",2070,0.0199614961544428 -"6|AFR","6p0",2075,0.0293744498884521 -"6|AFR","6p0",2080,0.0412206149886416 -"6|AFR","6p0",2085,0.057603669691023 -"6|AFR","6p0",2090,0.085681080652148 -"70|CHN","6p0",2020,0 -"70|CHN","6p0",2025,0 -"70|CHN","6p0",2030,0 -"70|CHN","6p0",2035,0 -"70|CHN","6p0",2040,0.0322258642755122 -"70|CHN","6p0",2045,0.094160187137634 -"70|CHN","6p0",2050,0.155707870050112 -"70|CHN","6p0",2055,0.217470965526648 -"70|CHN","6p0",2060,0.278707689781565 -"70|CHN","6p0",2065,0.350327757077793 -"70|CHN","6p0",2070,0.41682929569467 -"70|CHN","6p0",2075,0.484350867176514 -"70|CHN","6p0",2080,0.574752811584952 -"70|CHN","6p0",2085,0.641029148810485 -"70|CHN","6p0",2090,0.743466776081594 -"70|PAS","6p0",2020,0.0202141279771139 -"70|PAS","6p0",2025,0.0212125831877139 -"70|PAS","6p0",2030,0.022600563319955 -"70|PAS","6p0",2035,0.0250217361842587 -"70|PAS","6p0",2040,0.0277871990388385 -"70|PAS","6p0",2045,0.0311115491808239 -"70|PAS","6p0",2050,0.0346149498632664 -"70|PAS","6p0",2055,0.0392475713480589 -"70|PAS","6p0",2060,0.0447933741319057 -"70|PAS","6p0",2065,0.0521350805812512 -"70|PAS","6p0",2070,0.0613937120263917 -"70|PAS","6p0",2075,0.0714671712914093 -"70|PAS","6p0",2080,0.0804438177468418 -"70|PAS","6p0",2085,0.0937475207876481 -"70|PAS","6p0",2090,0.109132664988788 -"70|SAS","6p0",2020,0.155807563357859 -"70|SAS","6p0",2025,0.176271350199671 -"70|SAS","6p0",2030,0.196718154309875 -"70|SAS","6p0",2035,0.237514467953751 -"70|SAS","6p0",2040,0.286446457254338 -"70|SAS","6p0",2045,0.354191367991423 -"70|SAS","6p0",2050,0.435113975703869 -"70|SAS","6p0",2055,0.548733957310337 -"70|SAS","6p0",2060,0.68238909829922 -"70|SAS","6p0",2065,0.867595446508966 -"70|SAS","6p0",2070,1.10692414103803 -"70|SAS","6p0",2075,1.36618908730444 -"70|SAS","6p0",2080,1.70718578509316 -"70|SAS","6p0",2085,2.06135722073607 -"70|SAS","6p0",2090,2.48393432351045 -"71|FSU","6p0",2020,0.0579458262410138 -"71|FSU","6p0",2025,0.0579846637988869 -"71|FSU","6p0",2030,0.0580526005185738 -"71|FSU","6p0",2035,0.0582045964756143 -"71|FSU","6p0",2040,0.0583024733040208 -"71|FSU","6p0",2045,0.0583808020204346 -"71|FSU","6p0",2050,0.0584334007850289 -"71|FSU","6p0",2055,0.0585618661998441 -"71|FSU","6p0",2060,0.0587544411154504 -"71|FSU","6p0",2065,0.0589746185327326 -"71|FSU","6p0",2070,0.0592613661928826 -"71|FSU","6p0",2075,0.0594913056880201 -"71|FSU","6p0",2080,0.0597159835939953 -"71|FSU","6p0",2085,0.0599997256546587 -"71|FSU","6p0",2090,0.0602126676243887 -"71|PAO","6p0",2020,0.17806525 -"71|PAO","6p0",2025,0.186767641078545 -"71|PAO","6p0",2030,0.191017853280027 -"71|PAO","6p0",2035,0.201925292048529 -"71|PAO","6p0",2040,0.211866650760367 -"71|PAO","6p0",2045,0.22493753418341 -"71|PAO","6p0",2050,0.241643996180187 -"71|PAO","6p0",2055,0.254584474905565 -"71|PAO","6p0",2060,0.269809523269525 -"71|PAO","6p0",2065,0.286171662515654 -"71|PAO","6p0",2070,0.307812883288226 -"71|PAO","6p0",2075,0.335577442863917 -"71|PAO","6p0",2080,0.373655937939662 -"71|PAO","6p0",2085,0.419897202536606 -"71|PAO","6p0",2090,0.463965080980969 -"72|PAS","6p0",2020,0.2112217371631 -"72|PAS","6p0",2025,0.273151763783985 -"72|PAS","6p0",2030,0.340338278820589 -"72|PAS","6p0",2035,0.450869616021286 -"72|PAS","6p0",2040,0.56784031732671 -"72|PAS","6p0",2045,0.720188615017025 -"72|PAS","6p0",2050,0.947524513877413 -"72|PAS","6p0",2055,1.22419265207359 -"72|PAS","6p0",2060,1.58897473891399 -"72|PAS","6p0",2065,2.04285047355844 -"72|PAS","6p0",2070,2.62388210245616 -"72|PAS","6p0",2075,3.28446700858689 -"72|PAS","6p0",2080,4.14813833082926 -"72|PAS","6p0",2085,5.2015102824591 -"72|PAS","6p0",2090,6.31633041353467 -"73|PAS","6p0",2020,0.0571404155809709 -"73|PAS","6p0",2025,0.057816529430556 -"73|PAS","6p0",2030,0.0586353018814382 -"73|PAS","6p0",2035,0.0599198445709984 -"73|PAS","6p0",2040,0.0613812280877799 -"73|PAS","6p0",2045,0.0632022448536321 -"73|PAS","6p0",2050,0.0653848317213462 -"73|PAS","6p0",2055,0.0690040152934064 -"73|PAS","6p0",2060,0.0737183555013039 -"73|PAS","6p0",2065,0.0798290100173186 -"73|PAS","6p0",2070,0.0886665868439795 -"73|PAS","6p0",2075,0.0993387757755593 -"73|PAS","6p0",2080,0.111609710344347 -"73|PAS","6p0",2085,0.125700719807458 -"73|PAS","6p0",2090,0.14382484476042 -"74|FSU","6p0",2020,0.0580767880493127 -"74|FSU","6p0",2025,0.0581634265286704 -"74|FSU","6p0",2030,0.0583447155062902 -"74|FSU","6p0",2035,0.0587448234099771 -"74|FSU","6p0",2040,0.0590438522667636 -"74|FSU","6p0",2045,0.0592956534113923 -"74|FSU","6p0",2050,0.0594556623593472 -"74|FSU","6p0",2055,0.05941939415169 -"74|FSU","6p0",2060,0.0593907917966255 -"74|FSU","6p0",2065,0.0593248750724025 -"74|FSU","6p0",2070,0.0592308790297149 -"74|FSU","6p0",2075,0.0593535348273987 -"74|FSU","6p0",2080,0.0595494055079 -"74|FSU","6p0",2085,0.0597146516067762 -"74|FSU","6p0",2090,0.059814878845409 -"75|LAM","6p0",2020,0.0138350317779591 -"75|LAM","6p0",2025,0.0139932640164312 -"75|LAM","6p0",2030,0.0142505306450442 -"75|LAM","6p0",2035,0.0147642303353953 -"75|LAM","6p0",2040,0.0153595690866788 -"75|LAM","6p0",2045,0.0161546506317664 -"75|LAM","6p0",2050,0.017273735383806 -"75|LAM","6p0",2055,0.0187653187355698 -"75|LAM","6p0",2060,0.0209497044382475 -"75|LAM","6p0",2065,0.0237902497349983 -"75|LAM","6p0",2070,0.0276283908325373 -"75|LAM","6p0",2075,0.0334303528452889 -"75|LAM","6p0",2080,0.0409460511905903 -"75|LAM","6p0",2085,0.0518398550678725 -"75|LAM","6p0",2090,0.065543343698119 -"76|LAM","6p0",2020,0.016241515033149 -"76|LAM","6p0",2025,0.0190122387146964 -"76|LAM","6p0",2030,0.0239217552750691 -"76|LAM","6p0",2035,0.0347051785880519 -"76|LAM","6p0",2040,0.0478724436905567 -"76|LAM","6p0",2045,0.0669123310844145 -"76|LAM","6p0",2050,0.0925374966227919 -"76|LAM","6p0",2055,0.126922476755639 -"76|LAM","6p0",2060,0.172739432374162 -"76|LAM","6p0",2065,0.23813964539499 -"76|LAM","6p0",2070,0.323847090083374 -"76|LAM","6p0",2075,0.443007378362162 -"76|LAM","6p0",2080,0.60586732503175 -"76|LAM","6p0",2085,0.822850038439625 -"76|LAM","6p0",2090,1.10113351586528 -"77|CHN","6p0",2020,1.32740770537781 -"77|CHN","6p0",2025,2.10056999898396 -"77|CHN","6p0",2030,3.0933015614129 -"77|CHN","6p0",2035,4.71256459100987 -"77|CHN","6p0",2040,6.37491275028771 -"77|CHN","6p0",2045,8.31545952404915 -"77|CHN","6p0",2050,10.347184366772 -"77|CHN","6p0",2055,12.4531598546141 -"77|CHN","6p0",2060,14.6922887850138 -"77|CHN","6p0",2065,17.2599305661333 -"77|CHN","6p0",2070,20.2003468410308 -"77|CHN","6p0",2075,23.7000796437761 -"77|CHN","6p0",2080,27.2989262535477 -"77|CHN","6p0",2085,31.2096192928507 -"77|CHN","6p0",2090,36.4918587773812 -"77|FSU","6p0",2020,0.11253966131433 -"77|FSU","6p0",2025,0.126188262409846 -"77|FSU","6p0",2030,0.149453603966729 -"77|FSU","6p0",2035,0.192063897234015 -"77|FSU","6p0",2040,0.226487516324531 -"77|FSU","6p0",2045,0.252098848568509 -"77|FSU","6p0",2050,0.261402470937259 -"77|FSU","6p0",2055,0.253322180086568 -"77|FSU","6p0",2060,0.247846969554172 -"77|FSU","6p0",2065,0.250127128725083 -"77|FSU","6p0",2070,0.259838539669087 -"77|FSU","6p0",2075,0.273568615722547 -"77|FSU","6p0",2080,0.292852725482611 -"77|FSU","6p0",2085,0.317752663204314 -"77|FSU","6p0",2090,0.348395979036476 -"78|AFR","6p0",2020,0.00531674668954976 -"78|AFR","6p0",2025,0.00539488457965792 -"78|AFR","6p0",2030,0.00711603085929706 -"78|AFR","6p0",2035,0.0106842218771291 -"78|AFR","6p0",2040,0.0164263579476835 -"78|AFR","6p0",2045,0.0277168733942462 -"78|AFR","6p0",2050,0.0481036767787338 -"78|AFR","6p0",2055,0.0900646238713095 -"78|AFR","6p0",2060,0.164857333938625 -"78|AFR","6p0",2065,0.287535188751395 -"78|AFR","6p0",2070,0.463691922302705 -"78|AFR","6p0",2075,0.755253486567825 -"78|AFR","6p0",2080,1.16422709113674 -"78|AFR","6p0",2085,1.85160084361637 -"78|AFR","6p0",2090,2.85085369535878 -"78|MEA","6p0",2020,0.450358447527383 -"78|MEA","6p0",2025,0.486072895648019 -"78|MEA","6p0",2030,0.527244162645972 -"78|MEA","6p0",2035,0.598286094960019 -"78|MEA","6p0",2040,0.678632877763188 -"78|MEA","6p0",2045,0.765417277926944 -"78|MEA","6p0",2050,0.875728104880197 -"78|MEA","6p0",2055,1.03464848658816 -"78|MEA","6p0",2060,1.26074981839597 -"78|MEA","6p0",2065,1.58002002076627 -"78|MEA","6p0",2070,1.97356495107324 -"78|MEA","6p0",2075,2.49026338814696 -"78|MEA","6p0",2080,3.15792521210655 -"78|MEA","6p0",2085,4.00139971634684 -"78|MEA","6p0",2090,5.23007848160691 -"79|FSU","6p0",2020,0.0583575171506303 -"79|FSU","6p0",2025,0.0585431304687383 -"79|FSU","6p0",2030,0.0589244520322733 -"79|FSU","6p0",2035,0.0597471808250337 -"79|FSU","6p0",2040,0.0603414283793901 -"79|FSU","6p0",2045,0.0608109681095084 -"79|FSU","6p0",2050,0.0611510898962562 -"79|FSU","6p0",2055,0.0609084030086408 -"79|FSU","6p0",2060,0.0606380720872433 -"79|FSU","6p0",2065,0.0602222913073555 -"79|FSU","6p0",2070,0.0596181336091519 -"79|FSU","6p0",2075,0.0596347399039585 -"79|FSU","6p0",2080,0.059792491901077 -"79|FSU","6p0",2085,0.0599324736734982 -"79|FSU","6p0",2090,0.0600228472459363 -"7|AFR","6p0",2020,0.0113295364381306 -"7|AFR","6p0",2025,0.0135920798017873 -"7|AFR","6p0",2030,0.019512554824643 -"7|AFR","6p0",2035,0.0346141220461214 -"7|AFR","6p0",2040,0.0541687355949232 -"7|AFR","6p0",2045,0.0873470955144764 -"7|AFR","6p0",2050,0.139108345362656 -"7|AFR","6p0",2055,0.23443462086956 -"7|AFR","6p0",2060,0.375777048715244 -"7|AFR","6p0",2065,0.574599948325861 -"7|AFR","6p0",2070,0.860884549824872 -"7|AFR","6p0",2075,1.22337330393375 -"7|AFR","6p0",2080,1.68420755012974 -"7|AFR","6p0",2085,2.30382654088048 -"7|AFR","6p0",2090,3.10862814865625 -"80|AFR","6p0",2020,0.0648894095998866 -"80|AFR","6p0",2025,0.0661890593846625 -"80|AFR","6p0",2030,0.0735841958917925 -"80|AFR","6p0",2035,0.0906975075998528 -"80|AFR","6p0",2040,0.113938196088532 -"80|AFR","6p0",2045,0.143474713905897 -"80|AFR","6p0",2050,0.180888317712468 -"80|AFR","6p0",2055,0.227898683074887 -"80|AFR","6p0",2060,0.282861288767781 -"80|AFR","6p0",2065,0.363926418890066 -"80|AFR","6p0",2070,0.442359449474572 -"80|AFR","6p0",2075,0.542469858104127 -"80|AFR","6p0",2080,0.66753952598262 -"80|AFR","6p0",2085,0.806783263562026 -"80|AFR","6p0",2090,0.972045300527235 -"81|NAM","6p0",2020,0.0575243794620037 -"81|NAM","6p0",2025,0.0575595209049069 -"81|NAM","6p0",2030,0.0575860625881588 -"81|NAM","6p0",2035,0.0576366293617381 -"81|NAM","6p0",2040,0.0577002342802398 -"81|NAM","6p0",2045,0.0578190166078198 -"81|NAM","6p0",2050,0.0579514213809261 -"81|NAM","6p0",2055,0.0580315430313184 -"81|NAM","6p0",2060,0.0581175730254958 -"81|NAM","6p0",2065,0.0581763771270883 -"81|NAM","6p0",2070,0.0582070514883282 -"81|NAM","6p0",2075,0.0584255139181554 -"81|NAM","6p0",2080,0.0588182885506646 -"81|NAM","6p0",2085,0.0593335702553164 -"81|NAM","6p0",2090,0.0599698442728564 -"82|AFR","6p0",2020,5.84e-06 -"82|AFR","6p0",2025,7.29759336735892e-06 -"82|AFR","6p0",2030,9.79737161020387e-06 -"82|AFR","6p0",2035,1.52102284480631e-05 -"82|AFR","6p0",2040,2.62007059753913e-05 -"82|AFR","6p0",2045,4.62513345456447e-05 -"82|AFR","6p0",2050,9.00945816218192e-05 -"82|AFR","6p0",2055,0.000186278842349495 -"82|AFR","6p0",2060,0.000378784371384618 -"82|AFR","6p0",2065,0.000725072185977265 -"82|AFR","6p0",2070,0.00145382245221397 -"82|AFR","6p0",2075,0.00289474726623757 -"82|AFR","6p0",2080,0.00558864910203437 -"82|AFR","6p0",2085,0.0104273311287504 -"82|AFR","6p0",2090,0.0191748225238428 -"83|LAM","6p0",2020,0.00602730120871597 -"83|LAM","6p0",2025,0.0068339338332323 -"83|LAM","6p0",2030,0.00778756629903559 -"83|LAM","6p0",2035,0.00967294279696517 -"83|LAM","6p0",2040,0.011817338597163 -"83|LAM","6p0",2045,0.0148928861735863 -"83|LAM","6p0",2050,0.0184788688482127 -"83|LAM","6p0",2055,0.0228355965067025 -"83|LAM","6p0",2060,0.0275808070290526 -"83|LAM","6p0",2065,0.0342325572064927 -"83|LAM","6p0",2070,0.0424101774461642 -"83|LAM","6p0",2075,0.0535387304940024 -"83|LAM","6p0",2080,0.0700198491756125 -"83|LAM","6p0",2085,0.0854444188072391 -"83|LAM","6p0",2090,0.105689703383708 -"84|LAM","6p0",2020,0.0115610659860458 -"84|LAM","6p0",2025,0.0118572807129154 -"84|LAM","6p0",2030,0.0124906688652842 -"84|LAM","6p0",2035,0.0140774798800481 -"84|LAM","6p0",2040,0.0160867396502448 -"84|LAM","6p0",2045,0.0189248448744004 -"84|LAM","6p0",2050,0.0225290166391389 -"84|LAM","6p0",2055,0.0271966052763494 -"84|LAM","6p0",2060,0.0337016085740932 -"84|LAM","6p0",2065,0.0424337035333429 -"84|LAM","6p0",2070,0.0552446643131295 -"84|LAM","6p0",2075,0.0760418012884017 -"84|LAM","6p0",2080,0.101772219672887 -"84|LAM","6p0",2085,0.140230890137207 -"84|LAM","6p0",2090,0.186246243417106 -"85|MEA","6p0",2020,0.363409365279235 -"85|MEA","6p0",2025,0.477335569350204 -"85|MEA","6p0",2030,0.638536163081491 -"85|MEA","6p0",2035,0.939262102885334 -"85|MEA","6p0",2040,1.2840723335396 -"85|MEA","6p0",2045,1.72321465299668 -"85|MEA","6p0",2050,2.24119589645604 -"85|MEA","6p0",2055,2.96325529803951 -"85|MEA","6p0",2060,3.77679190574706 -"85|MEA","6p0",2065,4.84355061539461 -"85|MEA","6p0",2070,6.19778811734144 -"85|MEA","6p0",2075,7.73101427959169 -"85|MEA","6p0",2080,9.66614188557054 -"85|MEA","6p0",2085,11.667663551473 -"85|MEA","6p0",2090,14.1706386170205 -"85|WEU","6p0",2020,0.104583383783085 -"85|WEU","6p0",2025,0.113256607317693 -"85|WEU","6p0",2030,0.126014997460495 -"85|WEU","6p0",2035,0.142937157736972 -"85|WEU","6p0",2040,0.159914974210644 -"85|WEU","6p0",2045,0.182238918841609 -"85|WEU","6p0",2050,0.201995989958461 -"85|WEU","6p0",2055,0.230232749656508 -"85|WEU","6p0",2060,0.254732020541563 -"85|WEU","6p0",2065,0.289758982550762 -"85|WEU","6p0",2070,0.323762775317533 -"85|WEU","6p0",2075,0.357999980377928 -"85|WEU","6p0",2080,0.409087274951198 -"85|WEU","6p0",2085,0.46093097160721 -"85|WEU","6p0",2090,0.510747305969561 -"86|WEU","6p0",2020,0.25634787138112 -"86|WEU","6p0",2025,0.290218957613212 -"86|WEU","6p0",2030,0.316255679399096 -"86|WEU","6p0",2035,0.36438024064247 -"86|WEU","6p0",2040,0.413168125780681 -"86|WEU","6p0",2045,0.481696965390335 -"86|WEU","6p0",2050,0.567371114660208 -"86|WEU","6p0",2055,0.691608981578849 -"86|WEU","6p0",2060,0.849684298122532 -"86|WEU","6p0",2065,1.06836940002512 -"86|WEU","6p0",2070,1.3502062872979 -"86|WEU","6p0",2075,1.72049068932144 -"86|WEU","6p0",2080,2.20778409785233 -"86|WEU","6p0",2085,2.8450848871083 -"86|WEU","6p0",2090,3.69793209368011 -"87|MEA","6p0",2020,0.36978078702699 -"87|MEA","6p0",2025,0.399952883717405 -"87|MEA","6p0",2030,0.43643517504848 -"87|MEA","6p0",2035,0.506005308681553 -"87|MEA","6p0",2040,0.585063106700006 -"87|MEA","6p0",2045,0.693883236572613 -"87|MEA","6p0",2050,0.830691423665588 -"87|MEA","6p0",2055,1.00927756178756 -"87|MEA","6p0",2060,1.24193741630278 -"87|MEA","6p0",2065,1.55212101762272 -"87|MEA","6p0",2070,1.92220922300991 -"87|MEA","6p0",2075,2.45521949953325 -"87|MEA","6p0",2080,3.14056921870456 -"87|MEA","6p0",2085,3.974903031502 -"87|MEA","6p0",2090,5.08371785801529 -"88|CHN","6p0",2020,0 -"88|CHN","6p0",2025,0.0737783270517774 -"88|CHN","6p0",2030,0.170265018073709 -"88|CHN","6p0",2035,0.34119810758056 -"88|CHN","6p0",2040,0.520389466627552 -"88|CHN","6p0",2045,0.749431988409128 -"88|CHN","6p0",2050,0.98302046725576 -"88|CHN","6p0",2055,1.22574584621343 -"88|CHN","6p0",2060,1.47686142435397 -"88|CHN","6p0",2065,1.79864733484321 -"88|CHN","6p0",2070,2.0541162979957 -"88|CHN","6p0",2075,2.32244845707578 -"88|CHN","6p0",2080,2.6622966811316 -"88|CHN","6p0",2085,2.88094423091391 -"88|CHN","6p0",2090,3.34974868916093 -"88|PAS","6p0",2020,0.0341579483954577 -"88|PAS","6p0",2025,0.0401337397838656 -"88|PAS","6p0",2030,0.0490780546692822 -"88|PAS","6p0",2035,0.0625670224906554 -"88|PAS","6p0",2040,0.0783846223320088 -"88|PAS","6p0",2045,0.0980886746683313 -"88|PAS","6p0",2050,0.122387941095119 -"88|PAS","6p0",2055,0.153716978184824 -"88|PAS","6p0",2060,0.192627141211601 -"88|PAS","6p0",2065,0.240852069104176 -"88|PAS","6p0",2070,0.302622036208547 -"88|PAS","6p0",2075,0.369638402382691 -"88|PAS","6p0",2080,0.438719142589031 -"88|PAS","6p0",2085,0.52335171953884 -"88|PAS","6p0",2090,0.6248573645088 -"88|RCPA","6p0",2020,0.0106254048161672 -"88|RCPA","6p0",2025,0.0132222931320513 -"88|RCPA","6p0",2030,0.015809074223989 -"88|RCPA","6p0",2035,0.0200601880788189 -"88|RCPA","6p0",2040,0.024500488976522 -"88|RCPA","6p0",2045,0.030297021092392 -"88|RCPA","6p0",2050,0.0380788722225105 -"88|RCPA","6p0",2055,0.0468169725427441 -"88|RCPA","6p0",2060,0.0586668521505814 -"88|RCPA","6p0",2065,0.0752559460557699 -"88|RCPA","6p0",2070,0.0925116461229384 -"88|RCPA","6p0",2075,0.114084265411005 -"88|RCPA","6p0",2080,0.139135657781399 -"88|RCPA","6p0",2085,0.164964057181476 -"88|RCPA","6p0",2090,0.202185358265192 -"8|AFR","6p0",2020,0.00213241094104509 -"8|AFR","6p0",2025,0.00233255312061524 -"8|AFR","6p0",2030,0.00325580560146357 -"8|AFR","6p0",2035,0.00540858487866946 -"8|AFR","6p0",2040,0.00921837609550078 -"8|AFR","6p0",2045,0.0166001008482638 -"8|AFR","6p0",2050,0.0299034356554054 -"8|AFR","6p0",2055,0.0614082716765451 -"8|AFR","6p0",2060,0.120052877303002 -"8|AFR","6p0",2065,0.224012421144855 -"8|AFR","6p0",2070,0.408349120300356 -"8|AFR","6p0",2075,0.705623629124954 -"8|AFR","6p0",2080,1.16587977420415 -"8|AFR","6p0",2085,1.8831831037916 -"8|AFR","6p0",2090,2.93036193552575 -"90|NAM","6p0",2020,3.07463384296512 -"90|NAM","6p0",2025,3.24406546461039 -"90|NAM","6p0",2030,3.35927798352592 -"90|NAM","6p0",2035,3.54193956940728 -"90|NAM","6p0",2040,3.67477717890573 -"90|NAM","6p0",2045,3.78501295617777 -"90|NAM","6p0",2050,3.93303266174648 -"90|NAM","6p0",2055,4.03952076048893 -"90|NAM","6p0",2060,4.18486966617116 -"90|NAM","6p0",2065,4.29377391199724 -"90|NAM","6p0",2070,4.42725686856553 -"90|NAM","6p0",2075,4.60265647404468 -"90|NAM","6p0",2080,4.75543214801306 -"90|NAM","6p0",2085,5.02493422898521 -"90|NAM","6p0",2090,5.19737238755828 -"91|PAO","6p0",2020,0.76122287074116 -"91|PAO","6p0",2025,0.773355971778559 -"91|PAO","6p0",2030,0.785458811861597 -"91|PAO","6p0",2035,0.803518982272506 -"91|PAO","6p0",2040,0.814751416211092 -"91|PAO","6p0",2045,0.833620907535962 -"91|PAO","6p0",2050,0.851404474225932 -"91|PAO","6p0",2055,0.878306717213025 -"91|PAO","6p0",2060,0.914393099299742 -"91|PAO","6p0",2065,0.949272495909644 -"91|PAO","6p0",2070,0.992756295749017 -"91|PAO","6p0",2075,1.04142564263396 -"91|PAO","6p0",2080,1.08419691711578 -"91|PAO","6p0",2085,1.12837276518535 -"91|PAO","6p0",2090,1.18437473627743 -"92|AFR","6p0",2020,0.000680112487024662 -"92|AFR","6p0",2025,0.000754127739184359 -"92|AFR","6p0",2030,0.00104634491387427 -"92|AFR","6p0",2035,0.0018005959860976 -"92|AFR","6p0",2040,0.0029262840986135 -"92|AFR","6p0",2045,0.00485437826973312 -"92|AFR","6p0",2050,0.00788927184720292 -"92|AFR","6p0",2055,0.0124213009263094 -"92|AFR","6p0",2060,0.02054522853844 -"92|AFR","6p0",2065,0.0318737222525421 -"92|AFR","6p0",2070,0.0470345655642499 -"92|AFR","6p0",2075,0.0690818675760846 -"92|AFR","6p0",2080,0.101373597191799 -"92|AFR","6p0",2085,0.144339773150266 -"92|AFR","6p0",2090,0.207577461092243 -"93|LAM","6p0",2020,0.011342301365729 -"93|LAM","6p0",2025,0.0114384307873941 -"93|LAM","6p0",2030,0.0116604338389053 -"93|LAM","6p0",2035,0.0122132507967152 -"93|LAM","6p0",2040,0.0129193310138305 -"93|LAM","6p0",2045,0.0138863678047035 -"93|LAM","6p0",2050,0.0152865819279473 -"93|LAM","6p0",2055,0.0170448077371587 -"93|LAM","6p0",2060,0.0191318125939319 -"93|LAM","6p0",2065,0.0221694786180228 -"93|LAM","6p0",2070,0.0260584528251921 -"93|LAM","6p0",2075,0.0318102841909319 -"93|LAM","6p0",2080,0.040511357750234 -"93|LAM","6p0",2085,0.0526302504435054 -"93|LAM","6p0",2090,0.0686038136445965 -"95|AFR","6p0",2020,0.0025849810587909 -"95|AFR","6p0",2025,0.0026569763971697 -"95|AFR","6p0",2030,0.00348975828848432 -"95|AFR","6p0",2035,0.00529154426558209 -"95|AFR","6p0",2040,0.00824263518539207 -"95|AFR","6p0",2045,0.0138711721385392 -"95|AFR","6p0",2050,0.023474381584869 -"95|AFR","6p0",2055,0.0427101770148746 -"95|AFR","6p0",2060,0.0763302508568289 -"95|AFR","6p0",2065,0.130120334929497 -"95|AFR","6p0",2070,0.212549957252687 -"95|AFR","6p0",2075,0.345721496357766 -"95|AFR","6p0",2080,0.542169931969413 -"95|AFR","6p0",2085,0.861795438564185 -"95|AFR","6p0",2090,1.32027595432904 -"95|MEA","6p0",2020,0.810565605270717 -"95|MEA","6p0",2025,0.805314390722966 -"95|MEA","6p0",2030,0.829784678643669 -"95|MEA","6p0",2035,0.863008327240359 -"95|MEA","6p0",2040,0.892843274946252 -"95|MEA","6p0",2045,0.939927390190134 -"95|MEA","6p0",2050,0.995186355419039 -"95|MEA","6p0",2055,1.07563834234319 -"95|MEA","6p0",2060,1.19954999536191 -"95|MEA","6p0",2065,1.38353608521124 -"95|MEA","6p0",2070,1.61055039374022 -"95|MEA","6p0",2075,2.02330304718418 -"95|MEA","6p0",2080,2.53014479063751 -"95|MEA","6p0",2085,3.17181320446841 -"95|MEA","6p0",2090,4.07956704726135 -"96|AFR","6p0",2020,0.00145775542988856 -"96|AFR","6p0",2025,0.00197943548229322 -"96|AFR","6p0",2030,0.0027150413505722 -"96|AFR","6p0",2035,0.00430505916493085 -"96|AFR","6p0",2040,0.00702936122309036 -"96|AFR","6p0",2045,0.0118439038827998 -"96|AFR","6p0",2050,0.0204190649106811 -"96|AFR","6p0",2055,0.0365619674340624 -"96|AFR","6p0",2060,0.0621045419101145 -"96|AFR","6p0",2065,0.105538961811222 -"96|AFR","6p0",2070,0.174421380459995 -"96|AFR","6p0",2075,0.266146166667258 -"96|AFR","6p0",2080,0.408060797784259 -"96|AFR","6p0",2085,0.606656646827895 -"96|AFR","6p0",2090,0.886556177383102 -"96|MEA","6p0",2020,0.0479788600478204 -"96|MEA","6p0",2025,0.0668858774355414 -"96|MEA","6p0",2030,0.0941466769239361 -"96|MEA","6p0",2035,0.147715704653955 -"96|MEA","6p0",2040,0.209624529414591 -"96|MEA","6p0",2045,0.291484975014976 -"96|MEA","6p0",2050,0.397347512087985 -"96|MEA","6p0",2055,0.541843094012688 -"96|MEA","6p0",2060,0.736847995410274 -"96|MEA","6p0",2065,0.999755246084738 -"96|MEA","6p0",2070,1.35089411631749 -"96|MEA","6p0",2075,1.81058796861417 -"96|MEA","6p0",2080,2.41215016487279 -"96|MEA","6p0",2085,3.20750000328223 -"96|MEA","6p0",2090,4.2925657373229 -"97|LAM","6p0",2020,0.150322835837072 -"97|LAM","6p0",2025,0.160718078451277 -"97|LAM","6p0",2030,0.178540938631742 -"97|LAM","6p0",2035,0.21047844082216 -"97|LAM","6p0",2040,0.247653529032093 -"97|LAM","6p0",2045,0.280984105236389 -"97|LAM","6p0",2050,0.327963026293237 -"97|LAM","6p0",2055,0.401138124838732 -"97|LAM","6p0",2060,0.463420461186781 -"97|LAM","6p0",2065,0.554447338852365 -"97|LAM","6p0",2070,0.652357000907949 -"97|LAM","6p0",2075,0.790918423887289 -"97|LAM","6p0",2080,0.936082891303256 -"97|LAM","6p0",2085,1.11805527933632 -"97|LAM","6p0",2090,1.33432273398079 -"97|NAM","6p0",2020,3.50333812068375 -"97|NAM","6p0",2025,3.74149900849625 -"97|NAM","6p0",2030,3.93568047742499 -"97|NAM","6p0",2035,4.17906879791066 -"97|NAM","6p0",2040,4.42046007158404 -"97|NAM","6p0",2045,4.5579797686785 -"97|NAM","6p0",2050,4.75799506740969 -"97|NAM","6p0",2055,5.0289880309769 -"97|NAM","6p0",2060,5.12953805497389 -"97|NAM","6p0",2065,5.38139178644307 -"97|NAM","6p0",2070,5.59713449613456 -"97|NAM","6p0",2075,5.8014731375409 -"97|NAM","6p0",2080,6.0036944598269 -"97|NAM","6p0",2085,6.23847987659499 -"97|NAM","6p0",2090,6.40487195633889 -"98|CHN","6p0",2020,1.34599447285924 -"98|CHN","6p0",2025,2.21238387854172 -"98|CHN","6p0",2030,3.31316115860957 -"98|CHN","6p0",2035,5.1588108845329 -"98|CHN","6p0",2040,7.17589196500107 -"98|CHN","6p0",2045,9.35116532359177 -"98|CHN","6p0",2050,11.7300573705908 -"98|CHN","6p0",2055,14.1311639131678 -"98|CHN","6p0",2060,17.1318997979069 -"98|CHN","6p0",2065,20.0774435467721 -"98|CHN","6p0",2070,23.3399554943367 -"98|CHN","6p0",2075,26.6727013504532 -"98|CHN","6p0",2080,30.4401638278652 -"98|CHN","6p0",2085,34.2019404079785 -"98|CHN","6p0",2090,38.2201539662811 -"98|PAS","6p0",2020,0.11205865 -"98|PAS","6p0",2025,0.147418507606424 -"98|PAS","6p0",2030,0.196886295503398 -"98|PAS","6p0",2035,0.289043686263821 -"98|PAS","6p0",2040,0.3975489684464 -"98|PAS","6p0",2045,0.527453971488281 -"98|PAS","6p0",2050,0.707665931435374 -"98|PAS","6p0",2055,0.89367489144259 -"98|PAS","6p0",2060,1.14705091706354 -"98|PAS","6p0",2065,1.42063846091604 -"98|PAS","6p0",2070,1.91142545889013 -"98|PAS","6p0",2075,2.5854887204987 -"98|PAS","6p0",2080,3.42991455350124 -"98|PAS","6p0",2085,4.67569894803522 -"98|PAS","6p0",2090,5.94565021450498 -"99|LAM","6p0",2020,0.0173717196543993 -"99|LAM","6p0",2025,0.0174022311416746 -"99|LAM","6p0",2030,0.0174628986890104 -"99|LAM","6p0",2035,0.017562763062062 -"99|LAM","6p0",2040,0.0176920968697957 -"99|LAM","6p0",2045,0.0178396091348976 -"99|LAM","6p0",2050,0.0180405993383877 -"99|LAM","6p0",2055,0.0183056769937995 -"99|LAM","6p0",2060,0.0185790791488204 -"99|LAM","6p0",2065,0.0189658061413693 -"99|LAM","6p0",2070,0.0194242441652661 -"99|LAM","6p0",2075,0.020025259407985 -"99|LAM","6p0",2080,0.020743120814743 -"99|LAM","6p0",2085,0.0215047608211372 -"99|LAM","6p0",2090,0.0223590835984915 -"9|LAM","6p0",2020,0.0124680760733801 -"9|LAM","6p0",2025,0.0124803382161854 -"9|LAM","6p0",2030,0.0125022702492213 -"9|LAM","6p0",2035,0.0125551028474557 -"9|LAM","6p0",2040,0.012628987895278 -"9|LAM","6p0",2045,0.0127460480012055 -"9|LAM","6p0",2050,0.0129329479007046 -"9|LAM","6p0",2055,0.0132137751873667 -"9|LAM","6p0",2060,0.0136240456558893 -"9|LAM","6p0",2065,0.0142431108903038 -"9|LAM","6p0",2070,0.0151569252855209 -"9|LAM","6p0",2075,0.0165241772724223 -"9|LAM","6p0",2080,0.0185160321073307 -"9|LAM","6p0",2085,0.0213654160626754 -"9|LAM","6p0",2090,0.0251713524666107 +"0|EEU","7p0",2020,0.000770369787974928 +"0|EEU","7p0",2025,0.00181980634126776 +"0|EEU","7p0",2030,0.00354058740349036 +"0|EEU","7p0",2035,0.00701838361298046 +"0|EEU","7p0",2040,0.0114807929449322 +"0|EEU","7p0",2045,0.0175605322782623 +"0|EEU","7p0",2050,0.0250530099457705 +"0|EEU","7p0",2055,0.0308947944199912 +"0|EEU","7p0",2060,0.0364356999971388 +"0|EEU","7p0",2065,0.0420934586961256 +"0|EEU","7p0",2070,0.0452892316306283 +"0|EEU","7p0",2075,0.0598604770915547 +"0|EEU","7p0",2080,0.0831949938594963 +"0|EEU","7p0",2085,0.114907360556197 +"0|EEU","7p0",2090,0.152919205601056 +"0|WEU","7p0",2020,0.063119280280433 +"0|WEU","7p0",2025,0.0696039081382802 +"0|WEU","7p0",2030,0.077890485916225 +"0|WEU","7p0",2035,0.092195890170881 +"0|WEU","7p0",2040,0.10788785864666 +"0|WEU","7p0",2045,0.130409216328508 +"0|WEU","7p0",2050,0.15781203828465 +"0|WEU","7p0",2055,0.198495243887982 +"0|WEU","7p0",2060,0.248868162183691 +"0|WEU","7p0",2065,0.321747329473729 +"0|WEU","7p0",2070,0.412515739670669 +"0|WEU","7p0",2075,0.533148804444813 +"0|WEU","7p0",2080,0.696500265640374 +"0|WEU","7p0",2085,0.922129133875154 +"0|WEU","7p0",2090,1.21317665988141 +"100|LAM","7p0",2020,0.0563866295829225 +"100|LAM","7p0",2025,0.067113159274847 +"100|LAM","7p0",2030,0.0853237048188165 +"100|LAM","7p0",2035,0.124697804344412 +"100|LAM","7p0",2040,0.170242230549555 +"100|LAM","7p0",2045,0.234861272651735 +"100|LAM","7p0",2050,0.323119283620502 +"100|LAM","7p0",2055,0.437355724887679 +"100|LAM","7p0",2060,0.590563630286847 +"100|LAM","7p0",2065,0.797402363420372 +"100|LAM","7p0",2070,1.06349708222813 +"100|LAM","7p0",2075,1.42183551208695 +"100|LAM","7p0",2080,1.88018214779325 +"100|LAM","7p0",2085,2.49171198019951 +"100|LAM","7p0",2090,3.28525763991779 +"101|LAM","7p0",2020,0.0172173369550732 +"101|LAM","7p0",2025,0.0172186582995376 +"101|LAM","7p0",2030,0.0172203965914032 +"101|LAM","7p0",2035,0.0172234062461284 +"101|LAM","7p0",2040,0.0172274711933056 +"101|LAM","7p0",2045,0.0172318883592909 +"101|LAM","7p0",2050,0.0172369596209203 +"101|LAM","7p0",2055,0.0172424434348177 +"101|LAM","7p0",2060,0.0172471698970619 +"101|LAM","7p0",2065,0.0172531224880811 +"101|LAM","7p0",2070,0.0172605348300718 +"101|LAM","7p0",2075,0.0172730992548303 +"101|LAM","7p0",2080,0.01729104424695 +"101|LAM","7p0",2085,0.0173087447856411 +"101|LAM","7p0",2090,0.0173297483208161 +"103|NAM","7p0",2020,0.0573753792429438 +"103|NAM","7p0",2025,0.0573814653264432 +"103|NAM","7p0",2030,0.0573864410374558 +"103|NAM","7p0",2035,0.0573957775283307 +"103|NAM","7p0",2040,0.057407151968569 +"103|NAM","7p0",2045,0.0574235149493508 +"103|NAM","7p0",2050,0.0574429896275635 +"103|NAM","7p0",2055,0.0574561257770291 +"103|NAM","7p0",2060,0.0574710925409049 +"103|NAM","7p0",2065,0.0574838127836297 +"103|NAM","7p0",2070,0.0575000892743356 +"103|NAM","7p0",2075,0.0575391566752519 +"103|NAM","7p0",2080,0.0576046780770343 +"103|NAM","7p0",2085,0.0576851124111371 +"103|NAM","7p0",2090,0.0577882472262017 +"104|NAM","7p0",2020,2.23829863260831 +"104|NAM","7p0",2025,2.26711060344692 +"104|NAM","7p0",2030,2.29599748581039 +"104|NAM","7p0",2035,2.34085014065719 +"104|NAM","7p0",2040,2.38207949012962 +"104|NAM","7p0",2045,2.42755768775334 +"104|NAM","7p0",2050,2.45384539989207 +"104|NAM","7p0",2055,2.46955150844563 +"104|NAM","7p0",2060,2.5018884823142 +"104|NAM","7p0",2065,2.53014222343263 +"104|NAM","7p0",2070,2.58446608938566 +"104|NAM","7p0",2075,2.60752062652705 +"104|NAM","7p0",2080,2.65464572089265 +"104|NAM","7p0",2085,2.68915216146568 +"104|NAM","7p0",2090,2.70195591241237 +"105|CHN","7p0",2020,0.662569907974022 +"105|CHN","7p0",2025,1.09190029904704 +"105|CHN","7p0",2030,1.61402892483756 +"105|CHN","7p0",2035,2.59202933566204 +"105|CHN","7p0",2040,3.59555293900328 +"105|CHN","7p0",2045,4.73435354203136 +"105|CHN","7p0",2050,6.05128530970315 +"105|CHN","7p0",2055,7.17499186119268 +"105|CHN","7p0",2060,8.38033504041639 +"105|CHN","7p0",2065,9.85251662148007 +"105|CHN","7p0",2070,11.576206467227 +"105|CHN","7p0",2075,13.3946484784425 +"105|CHN","7p0",2080,15.2303977252738 +"105|CHN","7p0",2085,17.3665505559509 +"105|CHN","7p0",2090,19.9126964957391 +"105|FSU","7p0",2020,0.0733416897024373 +"105|FSU","7p0",2025,0.0777159924832669 +"105|FSU","7p0",2030,0.086601610965077 +"105|FSU","7p0",2035,0.104961974391647 +"105|FSU","7p0",2040,0.119184342456679 +"105|FSU","7p0",2045,0.129029157594833 +"105|FSU","7p0",2050,0.136185999091377 +"105|FSU","7p0",2055,0.129760071348643 +"105|FSU","7p0",2060,0.124847187290782 +"105|FSU","7p0",2065,0.122421548052013 +"105|FSU","7p0",2070,0.118506520145955 +"105|FSU","7p0",2075,0.11926560672986 +"105|FSU","7p0",2080,0.124587687697589 +"105|FSU","7p0",2085,0.129899143736446 +"105|FSU","7p0",2090,0.136304267315551 +"106|EEU","7p0",2020,0.00357380625 +"106|EEU","7p0",2025,0.00553777268508564 +"106|EEU","7p0",2030,0.00770161320578731 +"106|EEU","7p0",2035,0.0116056064537624 +"106|EEU","7p0",2040,0.0158707636346966 +"106|EEU","7p0",2045,0.020812907942641 +"106|EEU","7p0",2050,0.0271268970167797 +"106|EEU","7p0",2055,0.0312031056101253 +"106|EEU","7p0",2060,0.0369362325469143 +"106|EEU","7p0",2065,0.0431653919199874 +"106|EEU","7p0",2070,0.0498835853565054 +"106|EEU","7p0",2075,0.0659101582279557 +"106|EEU","7p0",2080,0.0862377057896713 +"106|EEU","7p0",2085,0.11123854260155 +"106|EEU","7p0",2090,0.142681105694534 +"106|FSU","7p0",2020,0.0603339107250931 +"106|FSU","7p0",2025,0.0632462000893907 +"106|FSU","7p0",2030,0.0687062324953408 +"106|FSU","7p0",2035,0.0808895246246561 +"106|FSU","7p0",2040,0.0904139697430482 +"106|FSU","7p0",2045,0.09810665457783 +"106|FSU","7p0",2050,0.104231818153122 +"106|FSU","7p0",2055,0.101740565474111 +"106|FSU","7p0",2060,0.0997809004247827 +"106|FSU","7p0",2065,0.0952596873059937 +"106|FSU","7p0",2070,0.0880725216354386 +"106|FSU","7p0",2075,0.0924293449296204 +"106|FSU","7p0",2080,0.100237464227229 +"106|FSU","7p0",2085,0.108245526438737 +"106|FSU","7p0",2090,0.118057563710935 +"106|WEU","7p0",2020,0.0693680017289847 +"106|WEU","7p0",2025,0.0832848843359136 +"106|WEU","7p0",2030,0.0931516808464657 +"106|WEU","7p0",2035,0.11185105908143 +"106|WEU","7p0",2040,0.134694939625442 +"106|WEU","7p0",2045,0.161943838465134 +"106|WEU","7p0",2050,0.199439503896551 +"106|WEU","7p0",2055,0.22962381683916 +"106|WEU","7p0",2060,0.274940307445397 +"106|WEU","7p0",2065,0.334205279268721 +"106|WEU","7p0",2070,0.400589556284618 +"106|WEU","7p0",2075,0.523107954484997 +"106|WEU","7p0",2080,0.685452776361424 +"106|WEU","7p0",2085,0.860773239826445 +"106|WEU","7p0",2090,1.09149375026897 +"107|AFR","7p0",2020,0.0391132342656112 +"107|AFR","7p0",2025,0.0394383720348599 +"107|AFR","7p0",2030,0.0414890784206211 +"107|AFR","7p0",2035,0.0463230345169697 +"107|AFR","7p0",2040,0.0526158382797821 +"107|AFR","7p0",2045,0.0615333557178777 +"107|AFR","7p0",2050,0.0724643408752832 +"107|AFR","7p0",2055,0.0854230434471005 +"107|AFR","7p0",2060,0.104330929116325 +"107|AFR","7p0",2065,0.129595785163495 +"107|AFR","7p0",2070,0.153767899672943 +"107|AFR","7p0",2075,0.188296847554645 +"107|AFR","7p0",2080,0.227054439005142 +"107|AFR","7p0",2085,0.274443711894301 +"107|AFR","7p0",2090,0.332659638900644 +"108|LAM","7p0",2020,0.00397382019693143 +"108|LAM","7p0",2025,0.00403559155077912 +"108|LAM","7p0",2030,0.00411223666583721 +"108|LAM","7p0",2035,0.00425988990496796 +"108|LAM","7p0",2040,0.00442925008825347 +"108|LAM","7p0",2045,0.00467240826960913 +"108|LAM","7p0",2050,0.00495367059309343 +"108|LAM","7p0",2055,0.00523716235415962 +"108|LAM","7p0",2060,0.00554780844651607 +"108|LAM","7p0",2065,0.00590330267806557 +"108|LAM","7p0",2070,0.00637079721499963 +"108|LAM","7p0",2075,0.00702318783608822 +"108|LAM","7p0",2080,0.00797107735924993 +"108|LAM","7p0",2085,0.00894939979307839 +"108|LAM","7p0",2090,0.0101378144266847 +"109|NAM","7p0",2020,1.62226220804067 +"109|NAM","7p0",2025,1.62293022756583 +"109|NAM","7p0",2030,1.62318506576471 +"109|NAM","7p0",2035,1.62371186584182 +"109|NAM","7p0",2040,1.62423632314625 +"109|NAM","7p0",2045,1.62458402804162 +"109|NAM","7p0",2050,1.62488681630248 +"109|NAM","7p0",2055,1.62461572598353 +"109|NAM","7p0",2060,1.62421872917848 +"109|NAM","7p0",2065,1.6238982103256 +"109|NAM","7p0",2070,1.6233990998672 +"109|NAM","7p0",2075,1.62333104716033 +"109|NAM","7p0",2080,1.62346723428768 +"109|NAM","7p0",2085,1.62375028932724 +"109|NAM","7p0",2090,1.6240822881475 +"10|FSU","7p0",2020,0.112457479726025 +"10|FSU","7p0",2025,0.126056792960982 +"10|FSU","7p0",2030,0.147129310124674 +"10|FSU","7p0",2035,0.182237805735928 +"10|FSU","7p0",2040,0.209071524187569 +"10|FSU","7p0",2045,0.227299132046101 +"10|FSU","7p0",2050,0.234662364240155 +"10|FSU","7p0",2055,0.236471398609689 +"10|FSU","7p0",2060,0.241620464472381 +"10|FSU","7p0",2065,0.253469166592994 +"10|FSU","7p0",2070,0.267864156104003 +"10|FSU","7p0",2075,0.297577549089618 +"10|FSU","7p0",2080,0.320759867628357 +"10|FSU","7p0",2085,0.349325419095257 +"10|FSU","7p0",2090,0.386082011972642 +"10|SAS","7p0",2020,0.0367672377438594 +"10|SAS","7p0",2025,0.0368365796111055 +"10|SAS","7p0",2030,0.0369360928549386 +"10|SAS","7p0",2035,0.0371224465178331 +"10|SAS","7p0",2040,0.0374047747180576 +"10|SAS","7p0",2045,0.0378293803669602 +"10|SAS","7p0",2050,0.0385039422075343 +"10|SAS","7p0",2055,0.0394924142000316 +"10|SAS","7p0",2060,0.0409551860193689 +"10|SAS","7p0",2065,0.043065251138513 +"10|SAS","7p0",2070,0.0462461817594522 +"10|SAS","7p0",2075,0.051419921555748 +"10|SAS","7p0",2080,0.0581282822508792 +"10|SAS","7p0",2085,0.0668296685741073 +"10|SAS","7p0",2090,0.0791116356616638 +"110|PAS","7p0",2020,0.0777858481446616 +"110|PAS","7p0",2025,0.079560478899473 +"110|PAS","7p0",2030,0.0820347954166109 +"110|PAS","7p0",2035,0.0854985870874764 +"110|PAS","7p0",2040,0.0884483481336499 +"110|PAS","7p0",2045,0.0921079483760585 +"110|PAS","7p0",2050,0.0964013953085619 +"110|PAS","7p0",2055,0.103817555792535 +"110|PAS","7p0",2060,0.114976202790493 +"110|PAS","7p0",2065,0.127760939946253 +"110|PAS","7p0",2070,0.14504694589801 +"110|PAS","7p0",2075,0.162667070186262 +"110|PAS","7p0",2080,0.180859720775924 +"110|PAS","7p0",2085,0.203227092231736 +"110|PAS","7p0",2090,0.231390072254262 +"111|LAM","7p0",2020,0.010984645923044 +"111|LAM","7p0",2025,0.0110758660862776 +"111|LAM","7p0",2030,0.0112879248764101 +"111|LAM","7p0",2035,0.0117852124553382 +"111|LAM","7p0",2040,0.0124143881825692 +"111|LAM","7p0",2045,0.0132188808194253 +"111|LAM","7p0",2050,0.0144120975343663 +"111|LAM","7p0",2055,0.0158024693095791 +"111|LAM","7p0",2060,0.0176664592852071 +"111|LAM","7p0",2065,0.0201075103289253 +"111|LAM","7p0",2070,0.023532620847336 +"111|LAM","7p0",2075,0.0291424345779649 +"111|LAM","7p0",2080,0.0368510880028778 +"111|LAM","7p0",2085,0.0486347935980058 +"111|LAM","7p0",2090,0.0619764387632028 +"113|LAM","7p0",2020,0.0179038537236138 +"113|LAM","7p0",2025,0.0180012322923844 +"113|LAM","7p0",2030,0.0181936165628162 +"113|LAM","7p0",2035,0.0185296176700886 +"113|LAM","7p0",2040,0.0188304569631807 +"113|LAM","7p0",2045,0.0193952655594807 +"113|LAM","7p0",2050,0.0202611560758704 +"113|LAM","7p0",2055,0.0213621718601043 +"113|LAM","7p0",2060,0.0227249796506015 +"113|LAM","7p0",2065,0.0237788074910814 +"113|LAM","7p0",2070,0.0252923247219861 +"113|LAM","7p0",2075,0.0268796280819587 +"113|LAM","7p0",2080,0.0290338158008396 +"113|LAM","7p0",2085,0.0317696897604934 +"113|LAM","7p0",2090,0.0349705952707742 +"114|PAS","7p0",2020,0.018863053020097 +"114|PAS","7p0",2025,0.0224378334606377 +"114|PAS","7p0",2030,0.0267623397528321 +"114|PAS","7p0",2035,0.03415267395481 +"114|PAS","7p0",2040,0.0421930427796566 +"114|PAS","7p0",2045,0.0529558527117344 +"114|PAS","7p0",2050,0.0661635588550381 +"114|PAS","7p0",2055,0.0841487554584983 +"114|PAS","7p0",2060,0.107140147302499 +"114|PAS","7p0",2065,0.138502488481566 +"114|PAS","7p0",2070,0.179248677162953 +"114|PAS","7p0",2075,0.225715391017952 +"114|PAS","7p0",2080,0.285901832132804 +"114|PAS","7p0",2085,0.354383146793055 +"114|PAS","7p0",2090,0.439546765048136 +"115|MEA","7p0",2020,0.12829132930437 +"115|MEA","7p0",2025,0.133778407165827 +"115|MEA","7p0",2030,0.140700388544178 +"115|MEA","7p0",2035,0.165043614641803 +"115|MEA","7p0",2040,0.19648988976577 +"115|MEA","7p0",2045,0.23770997361247 +"115|MEA","7p0",2050,0.301306777959865 +"115|MEA","7p0",2055,0.363319639638913 +"115|MEA","7p0",2060,0.446739035906533 +"115|MEA","7p0",2065,0.526305714358807 +"115|MEA","7p0",2070,0.631812286692778 +"115|MEA","7p0",2075,0.788205015049708 +"115|MEA","7p0",2080,1.01248985548456 +"115|MEA","7p0",2085,1.32016523357743 +"115|MEA","7p0",2090,1.73432631049447 +"115|SAS","7p0",2020,0.0547708406077226 +"115|SAS","7p0",2025,0.0589450376814177 +"115|SAS","7p0",2030,0.0629743781274774 +"115|SAS","7p0",2035,0.072011530649804 +"115|SAS","7p0",2040,0.0847485056355399 +"115|SAS","7p0",2045,0.104244990317922 +"115|SAS","7p0",2050,0.138362606151148 +"115|SAS","7p0",2055,0.189621105454739 +"115|SAS","7p0",2060,0.262730370257245 +"115|SAS","7p0",2065,0.357976594844281 +"115|SAS","7p0",2070,0.485141477581679 +"115|SAS","7p0",2075,0.659048919583939 +"115|SAS","7p0",2080,0.897792515769255 +"115|SAS","7p0",2085,1.21262882065286 +"115|SAS","7p0",2090,1.68503029334188 +"116|LAM","7p0",2020,0.0107570863535817 +"116|LAM","7p0",2025,0.0123369238636448 +"116|LAM","7p0",2030,0.0150887806101147 +"116|LAM","7p0",2035,0.0217929945194926 +"116|LAM","7p0",2040,0.0314898860301829 +"116|LAM","7p0",2045,0.0462250698008731 +"116|LAM","7p0",2050,0.0689928921534712 +"116|LAM","7p0",2055,0.102584188413168 +"116|LAM","7p0",2060,0.150296312839587 +"116|LAM","7p0",2065,0.219003611569803 +"116|LAM","7p0",2070,0.314461516268748 +"116|LAM","7p0",2075,0.450605749671156 +"116|LAM","7p0",2080,0.638598182249808 +"116|LAM","7p0",2085,0.899488842324374 +"116|LAM","7p0",2090,1.25782507288344 +"117|PAS","7p0",2020,0.02346585 +"117|PAS","7p0",2025,0.0362579904751998 +"117|PAS","7p0",2030,0.0465712251356281 +"117|PAS","7p0",2035,0.0605253745801831 +"117|PAS","7p0",2040,0.0789004154498567 +"117|PAS","7p0",2045,0.101586177315224 +"117|PAS","7p0",2050,0.132689349922043 +"117|PAS","7p0",2055,0.174019495173683 +"117|PAS","7p0",2060,0.234182196644303 +"117|PAS","7p0",2065,0.313679294230339 +"117|PAS","7p0",2070,0.414560381189421 +"117|PAS","7p0",2075,0.535662416651046 +"117|PAS","7p0",2080,0.694805324988663 +"117|PAS","7p0",2085,0.891299416152408 +"117|PAS","7p0",2090,1.1780151321837 +"118|CHN","7p0",2020,0 +"118|CHN","7p0",2025,0 +"118|CHN","7p0",2030,0 +"118|CHN","7p0",2035,0 +"118|CHN","7p0",2040,0 +"118|CHN","7p0",2045,0 +"118|CHN","7p0",2050,0 +"118|CHN","7p0",2055,0 +"118|CHN","7p0",2060,0 +"118|CHN","7p0",2065,0 +"118|CHN","7p0",2070,0 +"118|CHN","7p0",2075,0 +"118|CHN","7p0",2080,0.0197189303009914 +"118|CHN","7p0",2085,0.030370924199769 +"118|CHN","7p0",2090,0.0374790991229906 +"119|WEU","7p0",2020,0.106549703876353 +"119|WEU","7p0",2025,0.119226425149589 +"119|WEU","7p0",2030,0.131132566773588 +"119|WEU","7p0",2035,0.152318831101706 +"119|WEU","7p0",2040,0.175569060646875 +"119|WEU","7p0",2045,0.205327257674657 +"119|WEU","7p0",2050,0.244684855947157 +"119|WEU","7p0",2055,0.29903174490408 +"119|WEU","7p0",2060,0.373200771692887 +"119|WEU","7p0",2065,0.47305662564664 +"119|WEU","7p0",2070,0.59795237718242 +"119|WEU","7p0",2075,0.77575554451612 +"119|WEU","7p0",2080,0.999896435392722 +"119|WEU","7p0",2085,1.30745628443265 +"119|WEU","7p0",2090,1.69097788553499 +"11|CHN","7p0",2020,0.334049842346328 +"11|CHN","7p0",2025,0.628827849828849 +"11|CHN","7p0",2030,1.06604186637385 +"11|CHN","7p0",2035,1.73991756281933 +"11|CHN","7p0",2040,2.44292800694964 +"11|CHN","7p0",2045,3.21854442586928 +"11|CHN","7p0",2050,3.95463247860387 +"11|CHN","7p0",2055,4.68055729648695 +"11|CHN","7p0",2060,5.58552774324699 +"11|CHN","7p0",2065,6.38648980091449 +"11|CHN","7p0",2070,7.29895255329314 +"11|CHN","7p0",2075,8.22805641201539 +"11|CHN","7p0",2080,9.2927676383486 +"11|CHN","7p0",2085,10.7457172012601 +"11|CHN","7p0",2090,12.0680747777928 +"11|FSU","7p0",2020,0.06194775574083 +"11|FSU","7p0",2025,0.0631812092026153 +"11|FSU","7p0",2030,0.0659761249150061 +"11|FSU","7p0",2035,0.0716128090533579 +"11|FSU","7p0",2040,0.0756989324152051 +"11|FSU","7p0",2045,0.079344609988963 +"11|FSU","7p0",2050,0.0813894511499148 +"11|FSU","7p0",2055,0.081103352075996 +"11|FSU","7p0",2060,0.0807329412981782 +"11|FSU","7p0",2065,0.0795847705448962 +"11|FSU","7p0",2070,0.0781208242344914 +"11|FSU","7p0",2075,0.0792153258641846 +"11|FSU","7p0",2080,0.0811100673937 +"11|FSU","7p0",2085,0.0832078730153414 +"11|FSU","7p0",2090,0.0843217852516656 +"120|MEA","7p0",2020,5.02702734374886 +"120|MEA","7p0",2025,5.37660454372928 +"120|MEA","7p0",2030,5.69319595980406 +"120|MEA","7p0",2035,6.00042587804269 +"120|MEA","7p0",2040,6.28733528618027 +"120|MEA","7p0",2045,6.60565179816854 +"120|MEA","7p0",2050,6.92623518072643 +"120|MEA","7p0",2055,7.45529321186612 +"120|MEA","7p0",2060,7.88036079440525 +"120|MEA","7p0",2065,8.37049462201372 +"120|MEA","7p0",2070,9.20727219023202 +"120|MEA","7p0",2075,10.000795074259 +"120|MEA","7p0",2080,11.1840757153538 +"120|MEA","7p0",2085,12.6133279806359 +"120|MEA","7p0",2090,14.2026423548345 +"121|AFR","7p0",2020,0.00422434817099042 +"121|AFR","7p0",2025,0.00505201127117869 +"121|AFR","7p0",2030,0.00618412124937341 +"121|AFR","7p0",2035,0.00843430986195597 +"121|AFR","7p0",2040,0.0120881376839443 +"121|AFR","7p0",2045,0.0182225311288768 +"121|AFR","7p0",2050,0.0295001144151353 +"121|AFR","7p0",2055,0.0531609506453447 +"121|AFR","7p0",2060,0.0912669453649335 +"121|AFR","7p0",2065,0.153443097988393 +"121|AFR","7p0",2070,0.260017894781437 +"121|AFR","7p0",2075,0.394857111785011 +"121|AFR","7p0",2080,0.598008465889515 +"121|AFR","7p0",2085,0.923051118721979 +"121|AFR","7p0",2090,1.34502641185643 +"122|LAM","7p0",2020,0.158563077978415 +"122|LAM","7p0",2025,0.168651606397225 +"122|LAM","7p0",2030,0.183028223599204 +"122|LAM","7p0",2035,0.218142790219223 +"122|LAM","7p0",2040,0.253941877814357 +"122|LAM","7p0",2045,0.288536917974256 +"122|LAM","7p0",2050,0.339599322343078 +"122|LAM","7p0",2055,0.406546580303088 +"122|LAM","7p0",2060,0.475259867556852 +"122|LAM","7p0",2065,0.576624062193171 +"122|LAM","7p0",2070,0.69255620816272 +"122|LAM","7p0",2075,0.816577357957623 +"122|LAM","7p0",2080,0.981927820158246 +"122|LAM","7p0",2085,1.16520481201209 +"122|LAM","7p0",2090,1.35350878707909 +"122|NAM","7p0",2020,3.55978528895408 +"122|NAM","7p0",2025,3.82168011221028 +"122|NAM","7p0",2030,4.03457201461554 +"122|NAM","7p0",2035,4.30876944623864 +"122|NAM","7p0",2040,4.56520292659063 +"122|NAM","7p0",2045,4.70357426393747 +"122|NAM","7p0",2050,4.94271817872128 +"122|NAM","7p0",2055,5.14983130089162 +"122|NAM","7p0",2060,5.2438532303621 +"122|NAM","7p0",2065,5.40411852361184 +"122|NAM","7p0",2070,5.57444391156542 +"122|NAM","7p0",2075,5.78288911394556 +"122|NAM","7p0",2080,6.07323484123997 +"122|NAM","7p0",2085,6.4349856672141 +"122|NAM","7p0",2090,6.5858679525161 +"123|CHN","7p0",2020,0.242339153412553 +"123|CHN","7p0",2025,0.483250270432147 +"123|CHN","7p0",2030,0.894784661859789 +"123|CHN","7p0",2035,1.51298389849383 +"123|CHN","7p0",2040,2.21125367680179 +"123|CHN","7p0",2045,3.04099534369157 +"123|CHN","7p0",2050,3.87844478173287 +"123|CHN","7p0",2055,4.51557649019533 +"123|CHN","7p0",2060,5.21005391629191 +"123|CHN","7p0",2065,5.77168836685966 +"123|CHN","7p0",2070,6.39159754284659 +"123|CHN","7p0",2075,6.87712480124242 +"123|CHN","7p0",2080,7.48577812599956 +"123|CHN","7p0",2085,8.33883277777968 +"123|CHN","7p0",2090,8.88874650586474 +"123|FSU","7p0",2020,0.0639523745587218 +"123|FSU","7p0",2025,0.065879998694472 +"123|FSU","7p0",2030,0.0705217520396801 +"123|FSU","7p0",2035,0.0799545933985254 +"123|FSU","7p0",2040,0.0874590050065904 +"123|FSU","7p0",2045,0.0942617598401306 +"123|FSU","7p0",2050,0.0986136174067618 +"123|FSU","7p0",2055,0.0978688634908718 +"123|FSU","7p0",2060,0.0962817133908736 +"123|FSU","7p0",2065,0.0937378902515378 +"123|FSU","7p0",2070,0.0912322905541591 +"123|FSU","7p0",2075,0.0916938951703174 +"123|FSU","7p0",2080,0.0944366713872927 +"123|FSU","7p0",2085,0.0983397574169591 +"123|FSU","7p0",2090,0.099079704388033 +"124|SAS","7p0",2020,0.518969587196116 +"124|SAS","7p0",2025,0.776127264647 +"124|SAS","7p0",2030,1.03883239850157 +"124|SAS","7p0",2035,1.49455172682256 +"124|SAS","7p0",2040,2.06058544049015 +"124|SAS","7p0",2045,2.79831395431397 +"124|SAS","7p0",2050,3.77246653854761 +"124|SAS","7p0",2055,4.99092912315963 +"124|SAS","7p0",2060,6.59044960959809 +"124|SAS","7p0",2065,8.63845680828872 +"124|SAS","7p0",2070,11.3634386660537 +"124|SAS","7p0",2075,14.4504527566661 +"124|SAS","7p0",2080,18.6688240818308 +"124|SAS","7p0",2085,23.7784149140221 +"124|SAS","7p0",2090,29.5056094938963 +"125|LAM","7p0",2020,0.0191360658930006 +"125|LAM","7p0",2025,0.0193981929869119 +"125|LAM","7p0",2030,0.0197808989936089 +"125|LAM","7p0",2035,0.0206425259762677 +"125|LAM","7p0",2040,0.0215492321314909 +"125|LAM","7p0",2045,0.0229828468888046 +"125|LAM","7p0",2050,0.0251964038715269 +"125|LAM","7p0",2055,0.0278929736946557 +"125|LAM","7p0",2060,0.0309638198931082 +"125|LAM","7p0",2065,0.0345955018135663 +"125|LAM","7p0",2070,0.0397844817455171 +"125|LAM","7p0",2075,0.0435841794971368 +"125|LAM","7p0",2080,0.0496530013768958 +"125|LAM","7p0",2085,0.0569445009087633 +"125|LAM","7p0",2090,0.0651448210750494 +"126|NAM","7p0",2020,0.363398475772434 +"126|NAM","7p0",2025,0.372336714379421 +"126|NAM","7p0",2030,0.377881888579622 +"126|NAM","7p0",2035,0.389783806587983 +"126|NAM","7p0",2040,0.395723065400503 +"126|NAM","7p0",2045,0.405342304133556 +"126|NAM","7p0",2050,0.414792716983206 +"126|NAM","7p0",2055,0.421253724969958 +"126|NAM","7p0",2060,0.438551484123046 +"126|NAM","7p0",2065,0.445674172210128 +"126|NAM","7p0",2070,0.462508255716381 +"126|NAM","7p0",2075,0.481634474978973 +"126|NAM","7p0",2080,0.506969864512922 +"126|NAM","7p0",2085,0.540702485274139 +"126|NAM","7p0",2090,0.575747606391809 +"127|FSU","7p0",2020,0.0623264023582618 +"127|FSU","7p0",2025,0.0637247902239973 +"127|FSU","7p0",2030,0.0668409257779846 +"127|FSU","7p0",2035,0.0736561252058698 +"127|FSU","7p0",2040,0.0788512590364239 +"127|FSU","7p0",2045,0.0832742881118552 +"127|FSU","7p0",2050,0.0861300560038991 +"127|FSU","7p0",2055,0.0840582154559453 +"127|FSU","7p0",2060,0.0817134248547784 +"127|FSU","7p0",2065,0.0777356401507655 +"127|FSU","7p0",2070,0.0724383898079084 +"127|FSU","7p0",2075,0.0724092608555842 +"127|FSU","7p0",2080,0.0740079713949925 +"127|FSU","7p0",2085,0.075172567403116 +"127|FSU","7p0",2090,0.0762629123592981 +"127|WEU","7p0",2020,0.00140737083569987 +"127|WEU","7p0",2025,0.00142558853631459 +"127|WEU","7p0",2030,0.00144228521075031 +"127|WEU","7p0",2035,0.00146745037623271 +"127|WEU","7p0",2040,0.00149666694335188 +"127|WEU","7p0",2045,0.0015318013226897 +"127|WEU","7p0",2050,0.00158351242460794 +"127|WEU","7p0",2055,0.0016592285344573 +"127|WEU","7p0",2060,0.0017747603922886 +"127|WEU","7p0",2065,0.0019420898661119 +"127|WEU","7p0",2070,0.00219463160408448 +"127|WEU","7p0",2075,0.00256157348836199 +"127|WEU","7p0",2080,0.00309279764294559 +"127|WEU","7p0",2085,0.00383375659017362 +"127|WEU","7p0",2090,0.00493795253315515 +"128|WEU","7p0",2020,0.0919785259535156 +"128|WEU","7p0",2025,0.0917771347758881 +"128|WEU","7p0",2030,0.0894675497288728 +"128|WEU","7p0",2035,0.0875395377636493 +"128|WEU","7p0",2040,0.0846006188849798 +"128|WEU","7p0",2045,0.0832127690735181 +"128|WEU","7p0",2050,0.0832919509695226 +"128|WEU","7p0",2055,0.0834876133814536 +"128|WEU","7p0",2060,0.0837528194551022 +"128|WEU","7p0",2065,0.0841296096988585 +"128|WEU","7p0",2070,0.0845896541039714 +"128|WEU","7p0",2075,0.0849919674530035 +"128|WEU","7p0",2080,0.0854773398668284 +"128|WEU","7p0",2085,0.0859532109680166 +"128|WEU","7p0",2090,0.0864535307994131 +"129|AFR","7p0",2020,0.000128425476446968 +"129|AFR","7p0",2025,0.000173619302372174 +"129|AFR","7p0",2030,0.000334838842012011 +"129|AFR","7p0",2035,0.000988410812037993 +"129|AFR","7p0",2040,0.0022567535659322 +"129|AFR","7p0",2045,0.00479671920712528 +"129|AFR","7p0",2050,0.00948495021423838 +"129|AFR","7p0",2055,0.0161342159205257 +"129|AFR","7p0",2060,0.0255581234507286 +"129|AFR","7p0",2065,0.0375949533697951 +"129|AFR","7p0",2070,0.0529404939628039 +"129|AFR","7p0",2075,0.0768961537628404 +"129|AFR","7p0",2080,0.110290579276823 +"129|AFR","7p0",2085,0.155564137216177 +"129|AFR","7p0",2090,0.21555979849248 +"12|SAS","7p0",2020,0.124621484087745 +"12|SAS","7p0",2025,0.125493300792386 +"12|SAS","7p0",2030,0.126633152469145 +"12|SAS","7p0",2035,0.128725358682156 +"12|SAS","7p0",2040,0.131285434629108 +"12|SAS","7p0",2045,0.134347648005765 +"12|SAS","7p0",2050,0.137358585691497 +"12|SAS","7p0",2055,0.1410334149346 +"12|SAS","7p0",2060,0.145834883020684 +"12|SAS","7p0",2065,0.151520986053095 +"12|SAS","7p0",2070,0.161171612068016 +"12|SAS","7p0",2075,0.170855183254055 +"12|SAS","7p0",2080,0.184801139235393 +"12|SAS","7p0",2085,0.199694882292002 +"12|SAS","7p0",2090,0.222646796760554 +"130|AFR","7p0",2020,0.00699476180964749 +"130|AFR","7p0",2025,0.00787152866830975 +"130|AFR","7p0",2030,0.00889771955948225 +"130|AFR","7p0",2035,0.0111132501607689 +"130|AFR","7p0",2040,0.0145866428093433 +"130|AFR","7p0",2045,0.0199618346139695 +"130|AFR","7p0",2050,0.0297150493133103 +"130|AFR","7p0",2055,0.0491031411456801 +"130|AFR","7p0",2060,0.0803384118040801 +"130|AFR","7p0",2065,0.124524738521973 +"130|AFR","7p0",2070,0.205153735422409 +"130|AFR","7p0",2075,0.294687930829656 +"130|AFR","7p0",2080,0.395197351749516 +"130|AFR","7p0",2085,0.567954665148944 +"130|AFR","7p0",2090,0.765068602170332 +"131|FSU","7p0",2020,0.0578250421994669 +"131|FSU","7p0",2025,0.0578395742690864 +"131|FSU","7p0",2030,0.0578674159648556 +"131|FSU","7p0",2035,0.0579281893455976 +"131|FSU","7p0",2040,0.0579727940190661 +"131|FSU","7p0",2045,0.0580052959174246 +"131|FSU","7p0",2050,0.0580313954710772 +"131|FSU","7p0",2055,0.0580098136689501 +"131|FSU","7p0",2060,0.0579835712823681 +"131|FSU","7p0",2065,0.057943866981997 +"131|FSU","7p0",2070,0.0578825617048225 +"131|FSU","7p0",2075,0.057876056883698 +"131|FSU","7p0",2080,0.0578834320578225 +"131|FSU","7p0",2085,0.0578899574216537 +"131|FSU","7p0",2090,0.0578955299984405 +"132|FSU","7p0",2020,0.0580863451660042 +"132|FSU","7p0",2025,0.0581864101758523 +"132|FSU","7p0",2030,0.0583938775581628 +"132|FSU","7p0",2035,0.0588405501734685 +"132|FSU","7p0",2040,0.0591770856922209 +"132|FSU","7p0",2045,0.0594436807158132 +"132|FSU","7p0",2050,0.0596300405440752 +"132|FSU","7p0",2055,0.0594771098694659 +"132|FSU","7p0",2060,0.0593038404391819 +"132|FSU","7p0",2065,0.0590587994132688 +"132|FSU","7p0",2070,0.0586926392841799 +"132|FSU","7p0",2075,0.058668879385838 +"132|FSU","7p0",2080,0.0587466273595853 +"132|FSU","7p0",2085,0.058817373762779 +"132|FSU","7p0",2090,0.0588653357084873 +"134|LAM","7p0",2020,0.000487445166576338 +"134|LAM","7p0",2025,0.00051877233659721 +"134|LAM","7p0",2030,0.000593575040193228 +"134|LAM","7p0",2035,0.000781911639570876 +"134|LAM","7p0",2040,0.00104840784515896 +"134|LAM","7p0",2045,0.00145947443446897 +"134|LAM","7p0",2050,0.00206107191893795 +"134|LAM","7p0",2055,0.00287588298562141 +"134|LAM","7p0",2060,0.00404595412754491 +"134|LAM","7p0",2065,0.00603065396205445 +"134|LAM","7p0",2070,0.00882792242968168 +"134|LAM","7p0",2075,0.0209427348366371 +"134|LAM","7p0",2080,0.0340556865365361 +"134|LAM","7p0",2085,0.0485520487265737 +"134|LAM","7p0",2090,0.0691723304530233 +"135|AFR","7p0",2020,0.0594802920757487 +"135|AFR","7p0",2025,0.060328875832185 +"135|AFR","7p0",2030,0.0646554401887715 +"135|AFR","7p0",2035,0.0754511665283089 +"135|AFR","7p0",2040,0.0888850761260992 +"135|AFR","7p0",2045,0.107051573018793 +"135|AFR","7p0",2050,0.128985652434821 +"135|AFR","7p0",2055,0.1574016865095 +"135|AFR","7p0",2060,0.195197677178441 +"135|AFR","7p0",2065,0.243195325172612 +"135|AFR","7p0",2070,0.298680980248164 +"135|AFR","7p0",2075,0.37000605100901 +"135|AFR","7p0",2080,0.446413030249546 +"135|AFR","7p0",2085,0.545875996003349 +"135|AFR","7p0",2090,0.660881173064257 +"136|AFR","7p0",2020,0.0631403768394771 +"136|AFR","7p0",2025,0.0640753019436114 +"136|AFR","7p0",2030,0.0697699915481001 +"136|AFR","7p0",2035,0.0843822293243681 +"136|AFR","7p0",2040,0.103380817521208 +"136|AFR","7p0",2045,0.126350148358312 +"136|AFR","7p0",2050,0.158608640858843 +"136|AFR","7p0",2055,0.193068291029168 +"136|AFR","7p0",2060,0.237910178133035 +"136|AFR","7p0",2065,0.295183338659457 +"136|AFR","7p0",2070,0.362324329548881 +"136|AFR","7p0",2075,0.449894186147084 +"136|AFR","7p0",2080,0.557412532830168 +"136|AFR","7p0",2085,0.700727121158895 +"136|AFR","7p0",2090,0.853525606369136 +"137|LAM","7p0",2020,0.0113553000754119 +"137|LAM","7p0",2025,0.011585099787234 +"137|LAM","7p0",2030,0.0120657977364383 +"137|LAM","7p0",2035,0.0133175214598512 +"137|LAM","7p0",2040,0.0148682726089923 +"137|LAM","7p0",2045,0.0169437859957552 +"137|LAM","7p0",2050,0.0201420167661345 +"137|LAM","7p0",2055,0.0243361108843237 +"137|LAM","7p0",2060,0.0301219125012443 +"137|LAM","7p0",2065,0.0377980345906647 +"137|LAM","7p0",2070,0.0477441777146303 +"137|LAM","7p0",2075,0.0620827313560989 +"137|LAM","7p0",2080,0.0810466968236307 +"137|LAM","7p0",2085,0.10866155664052 +"137|LAM","7p0",2090,0.144748533831008 +"139|LAM","7p0",2020,0.0245946419800302 +"139|LAM","7p0",2025,0.0248123920372172 +"139|LAM","7p0",2030,0.0251853838136006 +"139|LAM","7p0",2035,0.0259568204354119 +"139|LAM","7p0",2040,0.0268367149258694 +"139|LAM","7p0",2045,0.0281424870961518 +"139|LAM","7p0",2050,0.0299296653026499 +"139|LAM","7p0",2055,0.0322622061194254 +"139|LAM","7p0",2060,0.0355970429388982 +"139|LAM","7p0",2065,0.0401824913204092 +"139|LAM","7p0",2070,0.046527112492486 +"139|LAM","7p0",2075,0.0562934891277849 +"139|LAM","7p0",2080,0.0687136247271982 +"139|LAM","7p0",2085,0.0845057441580061 +"139|LAM","7p0",2090,0.105044069219469 +"13|AFR","7p0",2020,0.00020233828734811 +"13|AFR","7p0",2025,0.000204209315020792 +"13|AFR","7p0",2030,0.000217993469205853 +"13|AFR","7p0",2035,0.000250076538581198 +"13|AFR","7p0",2040,0.000281588315657872 +"13|AFR","7p0",2045,0.000414208736162482 +"13|AFR","7p0",2050,0.000534913096854685 +"13|AFR","7p0",2055,0.000767407743129044 +"13|AFR","7p0",2060,0.00154523204155218 +"13|AFR","7p0",2065,0.00213664984438547 +"13|AFR","7p0",2070,0.00306956438319966 +"13|AFR","7p0",2075,0.00438270937305679 +"13|AFR","7p0",2080,0.00571106914372255 +"13|AFR","7p0",2085,0.00681759573114951 +"13|AFR","7p0",2090,0.00954880430906312 +"141|SAS","7p0",2020,0.0028251 +"141|SAS","7p0",2025,0.00517540836321409 +"141|SAS","7p0",2030,0.0090670805896732 +"141|SAS","7p0",2035,0.0171993702250083 +"141|SAS","7p0",2040,0.026689909914749 +"141|SAS","7p0",2045,0.0392780208681025 +"141|SAS","7p0",2050,0.0570797553818721 +"141|SAS","7p0",2055,0.0847318418857898 +"141|SAS","7p0",2060,0.125552935238255 +"141|SAS","7p0",2065,0.174409613826757 +"141|SAS","7p0",2070,0.259143524043903 +"141|SAS","7p0",2075,0.359961006319948 +"141|SAS","7p0",2080,0.488608188512679 +"141|SAS","7p0",2085,0.6882820166906 +"141|SAS","7p0",2090,0.886161986407423 +"142|NAM","7p0",2020,0.979242017852461 +"142|NAM","7p0",2025,1.00917060658158 +"142|NAM","7p0",2030,1.02406125889148 +"142|NAM","7p0",2035,1.05038096098253 +"142|NAM","7p0",2040,1.07350586434638 +"142|NAM","7p0",2045,1.09800325252036 +"142|NAM","7p0",2050,1.11530756330111 +"142|NAM","7p0",2055,1.11733041972182 +"142|NAM","7p0",2060,1.12419529071205 +"142|NAM","7p0",2065,1.13399928479338 +"142|NAM","7p0",2070,1.15525202689773 +"142|NAM","7p0",2075,1.18615701801683 +"142|NAM","7p0",2080,1.23157155124847 +"142|NAM","7p0",2085,1.2788283675068 +"142|NAM","7p0",2090,1.31071070022888 +"143|PAS","7p0",2020,0.0910197672679311 +"143|PAS","7p0",2025,0.0985955720365305 +"143|PAS","7p0",2030,0.10756676436792 +"143|PAS","7p0",2035,0.121842237934239 +"143|PAS","7p0",2040,0.135138517254535 +"143|PAS","7p0",2045,0.152085151382221 +"143|PAS","7p0",2050,0.17266527537264 +"143|PAS","7p0",2055,0.204066291380416 +"143|PAS","7p0",2060,0.247962200780866 +"143|PAS","7p0",2065,0.300104511664625 +"143|PAS","7p0",2070,0.372355473822293 +"143|PAS","7p0",2075,0.453620478958917 +"143|PAS","7p0",2080,0.538258907354639 +"143|PAS","7p0",2085,0.644568915203797 +"143|PAS","7p0",2090,0.789120962835258 +"144|PAS","7p0",2020,0.0859701015572485 +"144|PAS","7p0",2025,0.0913102859240461 +"144|PAS","7p0",2030,0.0975754517946643 +"144|PAS","7p0",2035,0.10787619707611 +"144|PAS","7p0",2040,0.118769270368731 +"144|PAS","7p0",2045,0.132814637294334 +"144|PAS","7p0",2050,0.150210103704759 +"144|PAS","7p0",2055,0.174234697073112 +"144|PAS","7p0",2060,0.207547020805241 +"144|PAS","7p0",2065,0.252829187956376 +"144|PAS","7p0",2070,0.31232971966625 +"144|PAS","7p0",2075,0.383098889388834 +"144|PAS","7p0",2080,0.474666874396366 +"144|PAS","7p0",2085,0.564755873333006 +"144|PAS","7p0",2090,0.675893975681671 +"145|WEU","7p0",2020,0.000238397178490678 +"145|WEU","7p0",2025,0.000249687612834273 +"145|WEU","7p0",2030,0.000264500922005486 +"145|WEU","7p0",2035,0.000291321401612928 +"145|WEU","7p0",2040,0.000327131683598205 +"145|WEU","7p0",2045,0.00037407988181696 +"145|WEU","7p0",2050,0.000438297050691086 +"145|WEU","7p0",2055,0.000522633085225481 +"145|WEU","7p0",2060,0.000656648838131646 +"145|WEU","7p0",2065,0.000857479872252532 +"145|WEU","7p0",2070,0.00115294823742289 +"145|WEU","7p0",2075,0.00158969385705732 +"145|WEU","7p0",2080,0.00221312120235689 +"145|WEU","7p0",2085,0.00301893059755319 +"145|WEU","7p0",2090,0.00429283626741587 +"146|FSU","7p0",2020,0.0918254119976614 +"146|FSU","7p0",2025,0.101302658782343 +"146|FSU","7p0",2030,0.117819979390364 +"146|FSU","7p0",2035,0.147219008764893 +"146|FSU","7p0",2040,0.173997024625704 +"146|FSU","7p0",2045,0.191007836872298 +"146|FSU","7p0",2050,0.1987100695694 +"146|FSU","7p0",2055,0.191313760707069 +"146|FSU","7p0",2060,0.183182970851918 +"146|FSU","7p0",2065,0.180633958488329 +"146|FSU","7p0",2070,0.183366832703009 +"146|FSU","7p0",2075,0.189837683004638 +"146|FSU","7p0",2080,0.202806792062967 +"146|FSU","7p0",2085,0.221708005632413 +"146|FSU","7p0",2090,0.245684630260471 +"148|CHN","7p0",2020,1.12040032158681 +"148|CHN","7p0",2025,1.86795210689229 +"148|CHN","7p0",2030,2.84980442117967 +"148|CHN","7p0",2035,4.50509863645983 +"148|CHN","7p0",2040,6.2086422145407 +"148|CHN","7p0",2045,8.21706070825371 +"148|CHN","7p0",2050,10.3469834916995 +"148|CHN","7p0",2055,12.1428254362379 +"148|CHN","7p0",2060,13.9667454147927 +"148|CHN","7p0",2065,15.7647502246801 +"148|CHN","7p0",2070,17.4781689250106 +"148|CHN","7p0",2075,20.2342440528828 +"148|CHN","7p0",2080,23.3237175990121 +"148|CHN","7p0",2085,26.5874460020873 +"148|CHN","7p0",2090,30.688358205428 +"148|FSU","7p0",2020,0.0595746123357163 +"148|FSU","7p0",2025,0.0609926185406009 +"148|FSU","7p0",2030,0.0640658063533931 +"148|FSU","7p0",2035,0.069085520923518 +"148|FSU","7p0",2040,0.073892772938036 +"148|FSU","7p0",2045,0.0783962821305928 +"148|FSU","7p0",2050,0.0807460610459072 +"148|FSU","7p0",2055,0.0786273739115189 +"148|FSU","7p0",2060,0.0764014451675629 +"148|FSU","7p0",2065,0.0734133490144797 +"148|FSU","7p0",2070,0.0701817084274788 +"148|FSU","7p0",2075,0.0701629023503987 +"148|FSU","7p0",2080,0.0711868698675872 +"148|FSU","7p0",2085,0.0726417460278865 +"148|FSU","7p0",2090,0.0746317837460437 +"148|SAS","7p0",2020,0.0371881504831643 +"148|SAS","7p0",2025,0.0373364822861758 +"148|SAS","7p0",2030,0.0375331730707695 +"148|SAS","7p0",2035,0.0379697328494851 +"148|SAS","7p0",2040,0.0386072433862457 +"148|SAS","7p0",2045,0.0395940644733399 +"148|SAS","7p0",2050,0.0411003130061229 +"148|SAS","7p0",2055,0.0427744273384904 +"148|SAS","7p0",2060,0.0449151815129163 +"148|SAS","7p0",2065,0.0479944636298394 +"148|SAS","7p0",2070,0.0519281924339738 +"148|SAS","7p0",2075,0.05926614548677 +"148|SAS","7p0",2080,0.0695074506591157 +"148|SAS","7p0",2085,0.082580018623163 +"148|SAS","7p0",2090,0.100114705814024 +"149|PAO","7p0",2020,0.69380779414294 +"149|PAO","7p0",2025,0.695795090027465 +"149|PAO","7p0",2030,0.697671190287332 +"149|PAO","7p0",2035,0.699995874689158 +"149|PAO","7p0",2040,0.70313968166864 +"149|PAO","7p0",2045,0.705102279652007 +"149|PAO","7p0",2050,0.708175737348095 +"149|PAO","7p0",2055,0.712306372007002 +"149|PAO","7p0",2060,0.714446027696163 +"149|PAO","7p0",2065,0.719354485018394 +"149|PAO","7p0",2070,0.725112254828961 +"149|PAO","7p0",2075,0.730662623161718 +"149|PAO","7p0",2080,0.739772621563848 +"149|PAO","7p0",2085,0.749377376918247 +"149|PAO","7p0",2090,0.757724732303698 +"14|MEA","7p0",2020,3.17092474072563 +"14|MEA","7p0",2025,3.32354651515329 +"14|MEA","7p0",2030,3.5044445902734 +"14|MEA","7p0",2035,3.63304729864846 +"14|MEA","7p0",2040,3.76281838088824 +"14|MEA","7p0",2045,3.88166175134548 +"14|MEA","7p0",2050,4.07788180443013 +"14|MEA","7p0",2055,4.32300778167358 +"14|MEA","7p0",2060,4.44214156484315 +"14|MEA","7p0",2065,4.51232493753033 +"14|MEA","7p0",2070,4.6739174699742 +"14|MEA","7p0",2075,4.83678866758176 +"14|MEA","7p0",2080,5.27744125454972 +"14|MEA","7p0",2085,5.96554347730609 +"14|MEA","7p0",2090,6.76548588503848 +"150|WEU","7p0",2020,0.109800376966448 +"150|WEU","7p0",2025,0.123110561285263 +"150|WEU","7p0",2030,0.135532240096975 +"150|WEU","7p0",2035,0.157771664196935 +"150|WEU","7p0",2040,0.182769936163457 +"150|WEU","7p0",2045,0.215811039111849 +"150|WEU","7p0",2050,0.256479068936635 +"150|WEU","7p0",2055,0.31584129657643 +"150|WEU","7p0",2060,0.393264372134645 +"150|WEU","7p0",2065,0.501708865759752 +"150|WEU","7p0",2070,0.638999791663829 +"150|WEU","7p0",2075,0.833814152054882 +"150|WEU","7p0",2080,1.08444168434785 +"150|WEU","7p0",2085,1.40930890890089 +"150|WEU","7p0",2090,1.83804272654731 +"151|MEA","7p0",2020,0.310961530829189 +"151|MEA","7p0",2025,0.325778225639879 +"151|MEA","7p0",2030,0.356939943985329 +"151|MEA","7p0",2035,0.392893864115896 +"151|MEA","7p0",2040,0.430436328075421 +"151|MEA","7p0",2045,0.485975062978417 +"151|MEA","7p0",2050,0.536332235753711 +"151|MEA","7p0",2055,0.595579113092085 +"151|MEA","7p0",2060,0.649446012400191 +"151|MEA","7p0",2065,0.703536018295043 +"151|MEA","7p0",2070,0.796807193111747 +"151|MEA","7p0",2075,0.919612326676362 +"151|MEA","7p0",2080,1.10926834378624 +"151|MEA","7p0",2085,1.41412660005027 +"151|MEA","7p0",2090,1.79904126320958 +"151|WEU","7p0",2020,0.108483326516266 +"151|WEU","7p0",2025,0.118185512026941 +"151|WEU","7p0",2030,0.131295679782156 +"151|WEU","7p0",2035,0.150874716658967 +"151|WEU","7p0",2040,0.169788321256205 +"151|WEU","7p0",2045,0.19271939207677 +"151|WEU","7p0",2050,0.216246745455927 +"151|WEU","7p0",2055,0.243180220987442 +"151|WEU","7p0",2060,0.267949858554495 +"151|WEU","7p0",2065,0.299776566257744 +"151|WEU","7p0",2070,0.336605064720186 +"151|WEU","7p0",2075,0.370678126670787 +"151|WEU","7p0",2080,0.418766064814069 +"151|WEU","7p0",2085,0.469643497067008 +"151|WEU","7p0",2090,0.51855593440047 +"152|LAM","7p0",2020,0.0173239851219405 +"152|LAM","7p0",2025,0.0173447831949536 +"152|LAM","7p0",2030,0.0173794339532114 +"152|LAM","7p0",2035,0.0174369620897576 +"152|LAM","7p0",2040,0.017502677978236 +"152|LAM","7p0",2045,0.0175875265323246 +"152|LAM","7p0",2050,0.0176987966876136 +"152|LAM","7p0",2055,0.0178300147167275 +"152|LAM","7p0",2060,0.0179803428006377 +"152|LAM","7p0",2065,0.0181587258865798 +"152|LAM","7p0",2070,0.0184012969159586 +"152|LAM","7p0",2075,0.0186416685378467 +"152|LAM","7p0",2080,0.0189787221643604 +"152|LAM","7p0",2085,0.0193148440018376 +"152|LAM","7p0",2090,0.0197219079568224 +"153|NAM","7p0",2020,2.73520124323569 +"153|NAM","7p0",2025,2.84870088951328 +"153|NAM","7p0",2030,2.92249891634579 +"153|NAM","7p0",2035,3.0420918329994 +"153|NAM","7p0",2040,3.14723331729485 +"153|NAM","7p0",2045,3.22324278916102 +"153|NAM","7p0",2050,3.27610100285077 +"153|NAM","7p0",2055,3.2989441087652 +"153|NAM","7p0",2060,3.34892820923413 +"153|NAM","7p0",2065,3.40159169402037 +"153|NAM","7p0",2070,3.49928595597643 +"153|NAM","7p0",2075,3.60664684277353 +"153|NAM","7p0",2080,3.70210074181464 +"153|NAM","7p0",2085,3.8402739447395 +"153|NAM","7p0",2090,3.94699338063218 +"154|FSU","7p0",2020,0.0920331789720148 +"154|FSU","7p0",2025,0.102372294199434 +"154|FSU","7p0",2030,0.119716279310634 +"154|FSU","7p0",2035,0.157278144205424 +"154|FSU","7p0",2040,0.185932534919976 +"154|FSU","7p0",2045,0.204648807758832 +"154|FSU","7p0",2050,0.217437118779105 +"154|FSU","7p0",2055,0.211661285696528 +"154|FSU","7p0",2060,0.211480375800303 +"154|FSU","7p0",2065,0.219404303280491 +"154|FSU","7p0",2070,0.225504509425855 +"154|FSU","7p0",2075,0.237875659728763 +"154|FSU","7p0",2080,0.25687610227555 +"154|FSU","7p0",2085,0.276668533379607 +"154|FSU","7p0",2090,0.295206756772437 +"155|LAM","7p0",2020,0.0193133561051524 +"155|LAM","7p0",2025,0.0197728763792411 +"155|LAM","7p0",2030,0.0204904621097194 +"155|LAM","7p0",2035,0.0219229904035638 +"155|LAM","7p0",2040,0.0235473425310643 +"155|LAM","7p0",2045,0.0257380486801053 +"155|LAM","7p0",2050,0.0287452637225047 +"155|LAM","7p0",2055,0.0327353484601889 +"155|LAM","7p0",2060,0.0375275251673665 +"155|LAM","7p0",2065,0.0435169552146117 +"155|LAM","7p0",2070,0.0519543637215235 +"155|LAM","7p0",2075,0.05938109307469 +"155|LAM","7p0",2080,0.0694479824133757 +"155|LAM","7p0",2085,0.0807526034623012 +"155|LAM","7p0",2090,0.0947899658945552 +"156|RCPA","7p0",2020,0.0133237731286374 +"156|RCPA","7p0",2025,0.0173876942584541 +"156|RCPA","7p0",2030,0.0216974612815554 +"156|RCPA","7p0",2035,0.0282496652562701 +"156|RCPA","7p0",2040,0.0352331818481641 +"156|RCPA","7p0",2045,0.0444430324432906 +"156|RCPA","7p0",2050,0.0567029306635838 +"156|RCPA","7p0",2055,0.0728726693354607 +"156|RCPA","7p0",2060,0.0927969427366259 +"156|RCPA","7p0",2065,0.120648075626629 +"156|RCPA","7p0",2070,0.150585424463408 +"156|RCPA","7p0",2075,0.184264296844512 +"156|RCPA","7p0",2080,0.225958818748924 +"156|RCPA","7p0",2085,0.27113315378218 +"156|RCPA","7p0",2090,0.337050025869414 +"157|FSU","7p0",2020,0.0803215301639617 +"157|FSU","7p0",2025,0.087286211631236 +"157|FSU","7p0",2030,0.10035535092217 +"157|FSU","7p0",2035,0.131003788629496 +"157|FSU","7p0",2040,0.151566578808852 +"157|FSU","7p0",2045,0.168795799553004 +"157|FSU","7p0",2050,0.183187305617101 +"157|FSU","7p0",2055,0.179918754694554 +"157|FSU","7p0",2060,0.180638493963961 +"157|FSU","7p0",2065,0.180947507315085 +"157|FSU","7p0",2070,0.17461943858963 +"157|FSU","7p0",2075,0.182240478713783 +"157|FSU","7p0",2080,0.197133735898917 +"157|FSU","7p0",2085,0.20607720331215 +"157|FSU","7p0",2090,0.215310514011864 +"158|AFR","7p0",2020,0.0329480951007865 +"158|AFR","7p0",2025,0.0340689597789305 +"158|AFR","7p0",2030,0.0369009425776825 +"158|AFR","7p0",2035,0.0441981949205085 +"158|AFR","7p0",2040,0.0532085724445166 +"158|AFR","7p0",2045,0.068944235003276 +"158|AFR","7p0",2050,0.0950384838609529 +"158|AFR","7p0",2055,0.150595793278215 +"158|AFR","7p0",2060,0.240211402227549 +"158|AFR","7p0",2065,0.36530051925177 +"158|AFR","7p0",2070,0.551878864901589 +"158|AFR","7p0",2075,0.810373437403883 +"158|AFR","7p0",2080,1.15747906817931 +"158|AFR","7p0",2085,1.71898384465849 +"158|AFR","7p0",2090,2.38024485034338 +"159|CHN","7p0",2020,0.517290863913048 +"159|CHN","7p0",2025,0.903440987841371 +"159|CHN","7p0",2030,1.39892014494739 +"159|CHN","7p0",2035,2.19851752456837 +"159|CHN","7p0",2040,3.06465548606045 +"159|CHN","7p0",2045,4.08451240843301 +"159|CHN","7p0",2050,5.17838061851884 +"159|CHN","7p0",2055,6.39616960464089 +"159|CHN","7p0",2060,7.77974797150547 +"159|CHN","7p0",2065,9.20704604598661 +"159|CHN","7p0",2070,10.9512803494552 +"159|CHN","7p0",2075,12.8854597633543 +"159|CHN","7p0",2080,14.733265537008 +"159|CHN","7p0",2085,16.9659340580189 +"159|CHN","7p0",2090,19.3241192932388 +"15|SAS","7p0",2020,0.0667601796527165 +"15|SAS","7p0",2025,0.0741100010449973 +"15|SAS","7p0",2030,0.0835194150361556 +"15|SAS","7p0",2035,0.0989485945334138 +"15|SAS","7p0",2040,0.121278142377442 +"15|SAS","7p0",2045,0.152030130825509 +"15|SAS","7p0",2050,0.206829535592512 +"15|SAS","7p0",2055,0.287129748719121 +"15|SAS","7p0",2060,0.397782429135548 +"15|SAS","7p0",2065,0.543507631811748 +"15|SAS","7p0",2070,0.755985237317971 +"15|SAS","7p0",2075,1.00994579284883 +"15|SAS","7p0",2080,1.37440844971992 +"15|SAS","7p0",2085,1.82588019464395 +"15|SAS","7p0",2090,2.51553761902209 +"160|FSU","7p0",2020,0.0604904413356021 +"160|FSU","7p0",2025,0.0612705776621886 +"160|FSU","7p0",2030,0.0629111978214685 +"160|FSU","7p0",2035,0.0664428761218184 +"160|FSU","7p0",2040,0.0690925146449047 +"160|FSU","7p0",2045,0.0712066237250224 +"160|FSU","7p0",2050,0.0727272474909887 +"160|FSU","7p0",2055,0.0722475807426635 +"160|FSU","7p0",2060,0.0718794089408438 +"160|FSU","7p0",2065,0.0714700451007488 +"160|FSU","7p0",2070,0.0705004584214873 +"160|FSU","7p0",2075,0.0712528544249619 +"160|FSU","7p0",2080,0.0724239238035253 +"160|FSU","7p0",2085,0.0733930687602729 +"160|FSU","7p0",2090,0.0743074348599688 +"160|RCPA","7p0",2020,0.0581583114930355 +"160|RCPA","7p0",2025,0.0583035706967752 +"160|RCPA","7p0",2030,0.0586309442123138 +"160|RCPA","7p0",2035,0.0593388076630425 +"160|RCPA","7p0",2040,0.0599477994347069 +"160|RCPA","7p0",2045,0.0604862883216133 +"160|RCPA","7p0",2050,0.0609446435174953 +"160|RCPA","7p0",2055,0.060782730436662 +"160|RCPA","7p0",2060,0.0605657314976241 +"160|RCPA","7p0",2065,0.0602184890042249 +"160|RCPA","7p0",2070,0.0596185453508911 +"160|RCPA","7p0",2075,0.0595641282996413 +"160|RCPA","7p0",2080,0.0596866027910144 +"160|RCPA","7p0",2085,0.0598135619353722 +"160|RCPA","7p0",2090,0.0598989810416688 +"161|AFR","7p0",2020,0.000121576021976397 +"161|AFR","7p0",2025,0.000137281954323692 +"161|AFR","7p0",2030,0.000179114966934587 +"161|AFR","7p0",2035,0.000279410512632738 +"161|AFR","7p0",2040,0.000437292766137462 +"161|AFR","7p0",2045,0.00073277298743383 +"161|AFR","7p0",2050,0.00126308957322486 +"161|AFR","7p0",2055,0.00221900406697446 +"161|AFR","7p0",2060,0.0039513698598175 +"161|AFR","7p0",2065,0.00729968641344286 +"161|AFR","7p0",2070,0.0134806769768382 +"161|AFR","7p0",2075,0.0243062891118184 +"161|AFR","7p0",2080,0.0428652199775066 +"161|AFR","7p0",2085,0.0700384206036858 +"161|AFR","7p0",2090,0.0995089570134266 +"162|CHN","7p0",2020,2.10601408236296 +"162|CHN","7p0",2025,3.37177042769016 +"162|CHN","7p0",2030,4.82921160740403 +"162|CHN","7p0",2035,7.33394579751912 +"162|CHN","7p0",2040,9.9991328313615 +"162|CHN","7p0",2045,12.8286618675896 +"162|CHN","7p0",2050,16.3025400557257 +"162|CHN","7p0",2055,19.6778677467225 +"162|CHN","7p0",2060,23.9337128914997 +"162|CHN","7p0",2065,28.7751686723699 +"162|CHN","7p0",2070,33.4225072423229 +"162|CHN","7p0",2075,38.9163007423601 +"162|CHN","7p0",2080,44.6231962860388 +"162|CHN","7p0",2085,50.9663006608521 +"162|CHN","7p0",2090,57.6694935109815 +"16|FSU","7p0",2020,0.0577936181234935 +"16|FSU","7p0",2025,0.0577970891183277 +"16|FSU","7p0",2030,0.0578043468967206 +"16|FSU","7p0",2035,0.0578205212810831 +"16|FSU","7p0",2040,0.0578323752843483 +"16|FSU","7p0",2045,0.0578417258011827 +"16|FSU","7p0",2050,0.0578489432099883 +"16|FSU","7p0",2055,0.0578444800373769 +"16|FSU","7p0",2060,0.0578381040564372 +"16|FSU","7p0",2065,0.0578286508873823 +"16|FSU","7p0",2070,0.0578154716794346 +"16|FSU","7p0",2075,0.0578139215257577 +"16|FSU","7p0",2080,0.0578156102854411 +"16|FSU","7p0",2085,0.0578173070766691 +"16|FSU","7p0",2090,0.0578191996742611 +"17|NAM","7p0",2020,0.111555427155656 +"17|NAM","7p0",2025,0.111692388045644 +"17|NAM","7p0",2030,0.111795205516188 +"17|NAM","7p0",2035,0.111992232454381 +"17|NAM","7p0",2040,0.112213390186306 +"17|NAM","7p0",2045,0.112463714650168 +"17|NAM","7p0",2050,0.112744637609515 +"17|NAM","7p0",2055,0.112910636840773 +"17|NAM","7p0",2060,0.113128511921843 +"17|NAM","7p0",2065,0.113415213723179 +"17|NAM","7p0",2070,0.113813099091093 +"17|NAM","7p0",2075,0.114579072091115 +"17|NAM","7p0",2080,0.115655515009582 +"17|NAM","7p0",2085,0.117024730530678 +"17|NAM","7p0",2090,0.118830508806492 +"18|PAO","7p0",2020,0.758563593577398 +"18|PAO","7p0",2025,0.769666631887237 +"18|PAO","7p0",2030,0.783803349516308 +"18|PAO","7p0",2035,0.801942420040991 +"18|PAO","7p0",2040,0.81468101328112 +"18|PAO","7p0",2045,0.841024704071821 +"18|PAO","7p0",2050,0.857924410830034 +"18|PAO","7p0",2055,0.886678580225459 +"18|PAO","7p0",2060,0.920805060149317 +"18|PAO","7p0",2065,0.96085033327742 +"18|PAO","7p0",2070,1.00344538003271 +"18|PAO","7p0",2075,1.06299626270036 +"18|PAO","7p0",2080,1.12170446014247 +"18|PAO","7p0",2085,1.19228963970866 +"18|PAO","7p0",2090,1.24994469081578 +"19|PAO","7p0",2020,0.688140251917134 +"19|PAO","7p0",2025,0.688971150937231 +"19|PAO","7p0",2030,0.690108708704814 +"19|PAO","7p0",2035,0.691996799760243 +"19|PAO","7p0",2040,0.6930280141425 +"19|PAO","7p0",2045,0.694666102162168 +"19|PAO","7p0",2050,0.696461011930773 +"19|PAO","7p0",2055,0.699059713519309 +"19|PAO","7p0",2060,0.701652148176614 +"19|PAO","7p0",2065,0.70536395727487 +"19|PAO","7p0",2070,0.709146811587786 +"19|PAO","7p0",2075,0.712709788990345 +"19|PAO","7p0",2080,0.716254369915973 +"19|PAO","7p0",2085,0.720752715248152 +"19|PAO","7p0",2090,0.725238147930037 +"1|AFR","7p0",2020,0.00587883274013346 +"1|AFR","7p0",2025,0.00611069304848469 +"1|AFR","7p0",2030,0.00648608069174534 +"1|AFR","7p0",2035,0.00724261164057464 +"1|AFR","7p0",2040,0.00828163323796381 +"1|AFR","7p0",2045,0.0101239316443453 +"1|AFR","7p0",2050,0.0128930729810429 +"1|AFR","7p0",2055,0.0186659478340948 +"1|AFR","7p0",2060,0.0275757198414488 +"1|AFR","7p0",2065,0.0407484605813445 +"1|AFR","7p0",2070,0.0650575712901085 +"1|AFR","7p0",2075,0.0983763887084827 +"1|AFR","7p0",2080,0.151414975253025 +"1|AFR","7p0",2085,0.235966672355775 +"1|AFR","7p0",2090,0.327019918383365 +"20|PAO","7p0",2020,0.685793221514779 +"20|PAO","7p0",2025,0.68617390833341 +"20|PAO","7p0",2030,0.686797782028423 +"20|PAO","7p0",2035,0.687593324674818 +"20|PAO","7p0",2040,0.688145273039852 +"20|PAO","7p0",2045,0.689013062683312 +"20|PAO","7p0",2050,0.690191179617631 +"20|PAO","7p0",2055,0.691714550019679 +"20|PAO","7p0",2060,0.693218798609394 +"20|PAO","7p0",2065,0.694902855892008 +"20|PAO","7p0",2070,0.695347732621924 +"20|PAO","7p0",2075,0.697212306863789 +"20|PAO","7p0",2080,0.699613038835652 +"20|PAO","7p0",2085,0.703308211549064 +"20|PAO","7p0",2090,0.70589796217561 +"21|PAO","7p0",2020,0.700970097460145 +"21|PAO","7p0",2025,0.704565345536068 +"21|PAO","7p0",2030,0.709673397707206 +"21|PAO","7p0",2035,0.715218858080079 +"21|PAO","7p0",2040,0.720491022648447 +"21|PAO","7p0",2045,0.725312721422499 +"21|PAO","7p0",2050,0.732541866137876 +"21|PAO","7p0",2055,0.741502186047706 +"21|PAO","7p0",2060,0.750933470895141 +"21|PAO","7p0",2065,0.761218364842107 +"21|PAO","7p0",2070,0.771353322423572 +"21|PAO","7p0",2075,0.783763864274011 +"21|PAO","7p0",2080,0.800703967906647 +"21|PAO","7p0",2085,0.816149150684403 +"21|PAO","7p0",2090,0.841982645579374 +"22|PAO","7p0",2020,0.690186369180104 +"22|PAO","7p0",2025,0.691882548721895 +"22|PAO","7p0",2030,0.694221210996727 +"22|PAO","7p0",2035,0.697015807400027 +"22|PAO","7p0",2040,0.700796544637632 +"22|PAO","7p0",2045,0.704232792811039 +"22|PAO","7p0",2050,0.707618820193316 +"22|PAO","7p0",2055,0.711077945669529 +"22|PAO","7p0",2060,0.713302160044107 +"22|PAO","7p0",2065,0.716259496447857 +"22|PAO","7p0",2070,0.723636492998719 +"22|PAO","7p0",2075,0.730919369405282 +"22|PAO","7p0",2080,0.742164002523212 +"22|PAO","7p0",2085,0.753546573133974 +"22|PAO","7p0",2090,0.76429214653209 +"23|FSU","7p0",2020,0.0593337666253726 +"23|FSU","7p0",2025,0.0598515095517839 +"23|FSU","7p0",2030,0.0608822773585355 +"23|FSU","7p0",2035,0.0632411221443771 +"23|FSU","7p0",2040,0.0650146545110599 +"23|FSU","7p0",2045,0.0665293608872286 +"23|FSU","7p0",2050,0.0675152466754759 +"23|FSU","7p0",2055,0.0666770258587195 +"23|FSU","7p0",2060,0.0658484812770171 +"23|FSU","7p0",2065,0.064464731113517 +"23|FSU","7p0",2070,0.062621099046026 +"23|FSU","7p0",2075,0.0624719887222771 +"23|FSU","7p0",2080,0.0629521108496095 +"23|FSU","7p0",2085,0.0632431903475846 +"23|FSU","7p0",2090,0.0635414606018044 +"24|SAS","7p0",2020,0.0543980655418622 +"24|SAS","7p0",2025,0.0565744019116884 +"24|SAS","7p0",2030,0.058984685584912 +"24|SAS","7p0",2035,0.0636360772505087 +"24|SAS","7p0",2040,0.0694131889144712 +"24|SAS","7p0",2045,0.0774826722121614 +"24|SAS","7p0",2050,0.0864081042031003 +"24|SAS","7p0",2055,0.100272453070884 +"24|SAS","7p0",2060,0.120001810389708 +"24|SAS","7p0",2065,0.148510039614805 +"24|SAS","7p0",2070,0.188933489895702 +"24|SAS","7p0",2075,0.239834998557961 +"24|SAS","7p0",2080,0.303338197010908 +"24|SAS","7p0",2085,0.374489484579787 +"24|SAS","7p0",2090,0.463771194678104 +"25|FSU","7p0",2020,0.0528531947687088 +"25|FSU","7p0",2025,0.059551722343809 +"25|FSU","7p0",2030,0.0718504317992208 +"25|FSU","7p0",2035,0.10006090236232 +"25|FSU","7p0",2040,0.122868494864557 +"25|FSU","7p0",2045,0.144468448204997 +"25|FSU","7p0",2050,0.168101499062837 +"25|FSU","7p0",2055,0.181325118085601 +"25|FSU","7p0",2060,0.207649951734876 +"25|FSU","7p0",2065,0.238875078519029 +"25|FSU","7p0",2070,0.274986993194932 +"25|FSU","7p0",2075,0.342302275239501 +"25|FSU","7p0",2080,0.424909585038689 +"25|FSU","7p0",2085,0.534045038634846 +"25|FSU","7p0",2090,0.648112053120491 +"26|WEU","7p0",2020,0.113117951573719 +"26|WEU","7p0",2025,0.124368352511772 +"26|WEU","7p0",2030,0.139037405710509 +"26|WEU","7p0",2035,0.159890181702473 +"26|WEU","7p0",2040,0.180301223610812 +"26|WEU","7p0",2045,0.204156146236314 +"26|WEU","7p0",2050,0.227003888358027 +"26|WEU","7p0",2055,0.254758926777937 +"26|WEU","7p0",2060,0.28151542218587 +"26|WEU","7p0",2065,0.315779439259094 +"26|WEU","7p0",2070,0.3531786342961 +"26|WEU","7p0",2075,0.392978024878807 +"26|WEU","7p0",2080,0.446211345533009 +"26|WEU","7p0",2085,0.508170786528012 +"26|WEU","7p0",2090,0.562925485152033 +"27|LAM","7p0",2020,0.191718412541578 +"27|LAM","7p0",2025,0.207155238337161 +"27|LAM","7p0",2030,0.233672643563081 +"27|LAM","7p0",2035,0.289193181773217 +"27|LAM","7p0",2040,0.341267581239191 +"27|LAM","7p0",2045,0.40002881944989 +"27|LAM","7p0",2050,0.483519309935432 +"27|LAM","7p0",2055,0.589841499140705 +"27|LAM","7p0",2060,0.711310416242796 +"27|LAM","7p0",2065,0.859482459158517 +"27|LAM","7p0",2070,1.02679249203107 +"27|LAM","7p0",2075,1.24642523217504 +"27|LAM","7p0",2080,1.49599842633756 +"27|LAM","7p0",2085,1.79994320763065 +"27|LAM","7p0",2090,2.14576027920475 +"27|NAM","7p0",2020,4.86786003761463 +"27|NAM","7p0",2025,5.32953285759884 +"27|NAM","7p0",2030,5.7082967831487 +"27|NAM","7p0",2035,6.25435361735102 +"27|NAM","7p0",2040,6.81583745322733 +"27|NAM","7p0",2045,7.128876982331 +"27|NAM","7p0",2050,7.42258789920498 +"27|NAM","7p0",2055,7.73170651003107 +"27|NAM","7p0",2060,8.02031236723331 +"27|NAM","7p0",2065,8.42505284432336 +"27|NAM","7p0",2070,8.91325859207529 +"27|NAM","7p0",2075,9.21431869138057 +"27|NAM","7p0",2080,9.66217342291099 +"27|NAM","7p0",2085,10.0608741864857 +"27|NAM","7p0",2090,10.3957064504879 +"28|LAM","7p0",2020,0.00125556779411765 +"28|LAM","7p0",2025,0.00245537738059507 +"28|LAM","7p0",2030,0.00369458377752795 +"28|LAM","7p0",2035,0.00561836940196543 +"28|LAM","7p0",2040,0.00789807189201444 +"28|LAM","7p0",2045,0.0118703481302384 +"28|LAM","7p0",2050,0.0182358953284978 +"28|LAM","7p0",2055,0.0268984476939072 +"28|LAM","7p0",2060,0.039746370614627 +"28|LAM","7p0",2065,0.0570325342363266 +"28|LAM","7p0",2070,0.0828842978045586 +"28|LAM","7p0",2075,0.125465105025276 +"28|LAM","7p0",2080,0.181269360178146 +"28|LAM","7p0",2085,0.258350177934603 +"28|LAM","7p0",2090,0.350171132420635 +"29|LAM","7p0",2020,0.00758330821204704 +"29|LAM","7p0",2025,0.00889224006078925 +"29|LAM","7p0",2030,0.0100669462552919 +"29|LAM","7p0",2035,0.0124258113516972 +"29|LAM","7p0",2040,0.0151893784122296 +"29|LAM","7p0",2045,0.0193437045182888 +"29|LAM","7p0",2050,0.0255854592628272 +"29|LAM","7p0",2055,0.0332451978268787 +"29|LAM","7p0",2060,0.040667337536451 +"29|LAM","7p0",2065,0.0534790000179478 +"29|LAM","7p0",2070,0.0667925112572167 +"29|LAM","7p0",2075,0.0893837400366955 +"29|LAM","7p0",2080,0.119440124144725 +"29|LAM","7p0",2085,0.148781387222361 +"29|LAM","7p0",2090,0.18782870444629 +"30|FSU","7p0",2020,0.10019291894985 +"30|FSU","7p0",2025,0.112793320371682 +"30|FSU","7p0",2030,0.136440501863281 +"30|FSU","7p0",2035,0.171402955170138 +"30|FSU","7p0",2040,0.204000899318113 +"30|FSU","7p0",2045,0.236145761872865 +"30|FSU","7p0",2050,0.247572216560027 +"30|FSU","7p0",2055,0.251788912875694 +"30|FSU","7p0",2060,0.256608818869273 +"30|FSU","7p0",2065,0.259119459767089 +"30|FSU","7p0",2070,0.271770956210324 +"30|FSU","7p0",2075,0.292604942153969 +"30|FSU","7p0",2080,0.324692785428016 +"30|FSU","7p0",2085,0.369606059792424 +"30|FSU","7p0",2090,0.422419625196921 +"30|MEA","7p0",2020,0.180626413547295 +"30|MEA","7p0",2025,0.190600166777887 +"30|MEA","7p0",2030,0.214037947958524 +"30|MEA","7p0",2035,0.257901828387039 +"30|MEA","7p0",2040,0.319570679753288 +"30|MEA","7p0",2045,0.3923749039367 +"30|MEA","7p0",2050,0.473253251140424 +"30|MEA","7p0",2055,0.575090801055536 +"30|MEA","7p0",2060,0.698175531214269 +"30|MEA","7p0",2065,0.853316230332407 +"30|MEA","7p0",2070,1.06730545552426 +"30|MEA","7p0",2075,1.34645965368039 +"30|MEA","7p0",2080,1.68107093177691 +"30|MEA","7p0",2085,2.13952086318622 +"30|MEA","7p0",2090,2.72841104515832 +"31|FSU","7p0",2020,0.0736999151137129 +"31|FSU","7p0",2025,0.0844244375245657 +"31|FSU","7p0",2030,0.102292089547884 +"31|FSU","7p0",2035,0.143771683192389 +"31|FSU","7p0",2040,0.17469855351772 +"31|FSU","7p0",2045,0.19696149088602 +"31|FSU","7p0",2050,0.215217105874508 +"31|FSU","7p0",2055,0.219922883763506 +"31|FSU","7p0",2060,0.231402024046406 +"31|FSU","7p0",2065,0.249835235494507 +"31|FSU","7p0",2070,0.268990669427566 +"31|FSU","7p0",2075,0.295227865034571 +"31|FSU","7p0",2080,0.329044491032998 +"31|FSU","7p0",2085,0.361148611983846 +"31|FSU","7p0",2090,0.384154811610763 +"31|MEA","7p0",2020,0.153731075366543 +"31|MEA","7p0",2025,0.160695279450667 +"31|MEA","7p0",2030,0.181066185142932 +"31|MEA","7p0",2035,0.215719889842042 +"31|MEA","7p0",2040,0.264417635765198 +"31|MEA","7p0",2045,0.328369533481093 +"31|MEA","7p0",2050,0.393709232861004 +"31|MEA","7p0",2055,0.476732705799372 +"31|MEA","7p0",2060,0.576907790821457 +"31|MEA","7p0",2065,0.698587005060057 +"31|MEA","7p0",2070,0.899686282846483 +"31|MEA","7p0",2075,1.13206078841562 +"31|MEA","7p0",2080,1.42490099460842 +"31|MEA","7p0",2085,1.81582096782521 +"31|MEA","7p0",2090,2.30783922190731 +"31|WEU","7p0",2020,0.124740941038581 +"31|WEU","7p0",2025,0.138645823747585 +"31|WEU","7p0",2030,0.15649425640605 +"31|WEU","7p0",2035,0.18338542443008 +"31|WEU","7p0",2040,0.206629724113813 +"31|WEU","7p0",2045,0.23334139216613 +"31|WEU","7p0",2050,0.262786948266324 +"31|WEU","7p0",2055,0.294167383047042 +"31|WEU","7p0",2060,0.328907919359673 +"31|WEU","7p0",2065,0.36800549812985 +"31|WEU","7p0",2070,0.414664540040634 +"31|WEU","7p0",2075,0.462816781608564 +"31|WEU","7p0",2080,0.523164614416783 +"31|WEU","7p0",2085,0.59599206743695 +"31|WEU","7p0",2090,0.665158568043882 +"32|LAM","7p0",2020,0.0958953211363733 +"32|LAM","7p0",2025,0.0994531945730305 +"32|LAM","7p0",2030,0.104765433891383 +"32|LAM","7p0",2035,0.11714775240689 +"32|LAM","7p0",2040,0.131309317521167 +"32|LAM","7p0",2045,0.14738624008309 +"32|LAM","7p0",2050,0.168773471090381 +"32|LAM","7p0",2055,0.19862135204532 +"32|LAM","7p0",2060,0.227622542569042 +"32|LAM","7p0",2065,0.267937830367585 +"32|LAM","7p0",2070,0.31795811489558 +"32|LAM","7p0",2075,0.384281107531587 +"32|LAM","7p0",2080,0.477909759094847 +"32|LAM","7p0",2085,0.578643590121776 +"32|LAM","7p0",2090,0.689862793742624 +"33|LAM","7p0",2020,0.133612507971118 +"33|LAM","7p0",2025,0.140003186340221 +"33|LAM","7p0",2030,0.150495961659684 +"33|LAM","7p0",2035,0.174021475550411 +"33|LAM","7p0",2040,0.198286244283033 +"33|LAM","7p0",2045,0.226385852189759 +"33|LAM","7p0",2050,0.264051846683487 +"33|LAM","7p0",2055,0.313780968640947 +"33|LAM","7p0",2060,0.365913674681962 +"33|LAM","7p0",2065,0.437968417554884 +"33|LAM","7p0",2070,0.52796871988022 +"33|LAM","7p0",2075,0.641087516252983 +"33|LAM","7p0",2080,0.780865408422928 +"33|LAM","7p0",2085,0.934515990255845 +"33|LAM","7p0",2090,1.10388384742096 +"33|NAM","7p0",2020,6.31387050326581 +"33|NAM","7p0",2025,6.96470998811467 +"33|NAM","7p0",2030,7.55675436047726 +"33|NAM","7p0",2035,8.28105476862641 +"33|NAM","7p0",2040,8.76574071387243 +"33|NAM","7p0",2045,9.15232930798904 +"33|NAM","7p0",2050,9.68062794254345 +"33|NAM","7p0",2055,10.3489630520593 +"33|NAM","7p0",2060,10.6283308235843 +"33|NAM","7p0",2065,11.2981444575407 +"33|NAM","7p0",2070,11.6075221288001 +"33|NAM","7p0",2075,12.2242513309099 +"33|NAM","7p0",2080,12.9131349033191 +"33|NAM","7p0",2085,13.6314829933511 +"33|NAM","7p0",2090,14.4727743901223 +"34|MEA","7p0",2020,0.144492367177246 +"34|MEA","7p0",2025,0.150695146101044 +"34|MEA","7p0",2030,0.164110194158053 +"34|MEA","7p0",2035,0.192928072099917 +"34|MEA","7p0",2040,0.233723210402438 +"34|MEA","7p0",2045,0.283174975043336 +"34|MEA","7p0",2050,0.345387920236517 +"34|MEA","7p0",2055,0.420057836063001 +"34|MEA","7p0",2060,0.507873132350185 +"34|MEA","7p0",2065,0.613648538480218 +"34|MEA","7p0",2070,0.757029342592495 +"34|MEA","7p0",2075,0.936203838548667 +"34|MEA","7p0",2080,1.17841804245142 +"34|MEA","7p0",2085,1.50850434064611 +"34|MEA","7p0",2090,1.9404672499308 +"35|CHN","7p0",2020,1.78077216046252 +"35|CHN","7p0",2025,2.85233541246099 +"35|CHN","7p0",2030,4.18186739445532 +"35|CHN","7p0",2035,6.39395879783345 +"35|CHN","7p0",2040,8.77480507832931 +"35|CHN","7p0",2045,11.5584339707921 +"35|CHN","7p0",2050,14.4746854405805 +"35|CHN","7p0",2055,17.6325526841371 +"35|CHN","7p0",2060,21.4499832111574 +"35|CHN","7p0",2065,25.3416997821896 +"35|CHN","7p0",2070,30.3784270178438 +"35|CHN","7p0",2075,35.6477812934578 +"35|CHN","7p0",2080,40.8747543884726 +"35|CHN","7p0",2085,47.3015848941329 +"35|CHN","7p0",2090,54.1860116643572 +"36|NAM","7p0",2020,2.57300596417689 +"36|NAM","7p0",2025,2.70232858353236 +"36|NAM","7p0",2030,2.81132603930659 +"36|NAM","7p0",2035,2.96379406878018 +"36|NAM","7p0",2040,3.09065409620613 +"36|NAM","7p0",2045,3.22881155444166 +"36|NAM","7p0",2050,3.3346092752583 +"36|NAM","7p0",2055,3.43127437788771 +"36|NAM","7p0",2060,3.56129053147447 +"36|NAM","7p0",2065,3.66820030579846 +"36|NAM","7p0",2070,3.826945420369 +"36|NAM","7p0",2075,3.92406513858149 +"36|NAM","7p0",2080,4.0621044332153 +"36|NAM","7p0",2085,4.19978218093779 +"36|NAM","7p0",2090,4.32623363133156 +"37|LAM","7p0",2020,0.00219463079472335 +"37|LAM","7p0",2025,0.00234451790223321 +"37|LAM","7p0",2030,0.0025894458317602 +"37|LAM","7p0",2035,0.00309282879173313 +"37|LAM","7p0",2040,0.00379361841987881 +"37|LAM","7p0",2045,0.0048217482976128 +"37|LAM","7p0",2050,0.00630228892023621 +"37|LAM","7p0",2055,0.00849431035641128 +"37|LAM","7p0",2060,0.0114628839187059 +"37|LAM","7p0",2065,0.015537714496786 +"37|LAM","7p0",2070,0.0217884368718699 +"37|LAM","7p0",2075,0.0309028281959998 +"37|LAM","7p0",2080,0.0444945643213874 +"37|LAM","7p0",2085,0.0628704881822149 +"37|LAM","7p0",2090,0.0875379855035827 +"38|AFR","7p0",2020,5.69330073801738e-05 +"38|AFR","7p0",2025,7.81869547297246e-05 +"38|AFR","7p0",2030,0.000128075565758171 +"38|AFR","7p0",2035,0.000244195781409209 +"38|AFR","7p0",2040,0.000431714392791216 +"38|AFR","7p0",2045,0.00074509963943246 +"38|AFR","7p0",2050,0.00135556689026043 +"38|AFR","7p0",2055,0.00259314931586365 +"38|AFR","7p0",2060,0.00486225742947438 +"38|AFR","7p0",2065,0.0095137911510512 +"38|AFR","7p0",2070,0.0175068348626976 +"38|AFR","7p0",2075,0.0310991375921398 +"38|AFR","7p0",2080,0.0531116767841953 +"38|AFR","7p0",2085,0.084445233347044 +"38|AFR","7p0",2090,0.125062813828378 +"39|EEU","7p0",2020,0.000263816096786059 +"39|EEU","7p0",2025,0.000552474313465196 +"39|EEU","7p0",2030,0.000998197936995446 +"39|EEU","7p0",2035,0.00183756659024871 +"39|EEU","7p0",2040,0.00289531836547257 +"39|EEU","7p0",2045,0.00425701907571207 +"39|EEU","7p0",2050,0.00598130727094273 +"39|EEU","7p0",2055,0.00712632265170255 +"39|EEU","7p0",2060,0.0080847212240945 +"39|EEU","7p0",2065,0.00873909968004982 +"39|EEU","7p0",2070,0.00835313220641063 +"39|EEU","7p0",2075,0.0109937505819739 +"39|EEU","7p0",2080,0.0154049735351944 +"39|EEU","7p0",2085,0.0217797878360616 +"39|EEU","7p0",2090,0.0296407341388077 +"39|FSU","7p0",2020,0.00496822689571456 +"39|FSU","7p0",2025,0.00561027392371846 +"39|FSU","7p0",2030,0.00675971634376638 +"39|FSU","7p0",2035,0.00965940644921248 +"39|FSU","7p0",2040,0.0134418343767379 +"39|FSU","7p0",2045,0.0190118691378594 +"39|FSU","7p0",2050,0.026462443005068 +"39|FSU","7p0",2055,0.0344097566012622 +"39|FSU","7p0",2060,0.0453628838493398 +"39|FSU","7p0",2065,0.0582864381771739 +"39|FSU","7p0",2070,0.0742380107436341 +"39|FSU","7p0",2075,0.103981418266249 +"39|FSU","7p0",2080,0.142367262552373 +"39|FSU","7p0",2085,0.192825042050109 +"39|FSU","7p0",2090,0.251689346534752 +"39|WEU","7p0",2020,0.0166771783054075 +"39|WEU","7p0",2025,0.0184338510600381 +"39|WEU","7p0",2030,0.0196567942019225 +"39|WEU","7p0",2035,0.0219824432623796 +"39|WEU","7p0",2040,0.0249797420173501 +"39|WEU","7p0",2045,0.0289010254541543 +"39|WEU","7p0",2050,0.0340069390791072 +"39|WEU","7p0",2055,0.0390913057296265 +"39|WEU","7p0",2060,0.0467481886469857 +"39|WEU","7p0",2065,0.0565499578317601 +"39|WEU","7p0",2070,0.067658656168658 +"39|WEU","7p0",2075,0.0872079995597218 +"39|WEU","7p0",2080,0.112877540430839 +"39|WEU","7p0",2085,0.14474546190396 +"39|WEU","7p0",2090,0.185918421202241 +"3|MEA","7p0",2020,0.568309320349596 +"3|MEA","7p0",2025,0.639126236713779 +"3|MEA","7p0",2030,0.715535631523513 +"3|MEA","7p0",2035,0.853869526675523 +"3|MEA","7p0",2040,1.01111636032585 +"3|MEA","7p0",2045,1.20816333904911 +"3|MEA","7p0",2050,1.44120402614422 +"3|MEA","7p0",2055,1.75714524640133 +"3|MEA","7p0",2060,2.16512653256798 +"3|MEA","7p0",2065,2.73088407135096 +"3|MEA","7p0",2070,3.43614384091768 +"3|MEA","7p0",2075,4.31626065401257 +"3|MEA","7p0",2080,5.42621115390763 +"3|MEA","7p0",2085,6.78541092897769 +"3|MEA","7p0",2090,8.50867784209079 +"40|MEA","7p0",2020,3.03275358954709 +"40|MEA","7p0",2025,3.22832851644391 +"40|MEA","7p0",2030,3.51589597391376 +"40|MEA","7p0",2035,3.78843042074562 +"40|MEA","7p0",2040,3.92692284503647 +"40|MEA","7p0",2045,4.11273261507008 +"40|MEA","7p0",2050,4.23165196984864 +"40|MEA","7p0",2055,4.49968584264448 +"40|MEA","7p0",2060,4.74508138603472 +"40|MEA","7p0",2065,5.1249265303617 +"40|MEA","7p0",2070,5.71768501726738 +"40|MEA","7p0",2075,6.3281482385687 +"40|MEA","7p0",2080,7.21807148205753 +"40|MEA","7p0",2085,8.25643866973181 +"40|MEA","7p0",2090,9.40711772455441 +"41|WEU","7p0",2020,0.0211403242082596 +"41|WEU","7p0",2025,0.0245991072438415 +"41|WEU","7p0",2030,0.0271320005195873 +"41|WEU","7p0",2035,0.0316148992250169 +"41|WEU","7p0",2040,0.0371157165911365 +"41|WEU","7p0",2045,0.0436798082572037 +"41|WEU","7p0",2050,0.052835471908632 +"41|WEU","7p0",2055,0.0605792082391057 +"41|WEU","7p0",2060,0.0724812221059344 +"41|WEU","7p0",2065,0.087408337582347 +"41|WEU","7p0",2070,0.104317946179305 +"41|WEU","7p0",2075,0.132179622020106 +"41|WEU","7p0",2080,0.171095326952311 +"41|WEU","7p0",2085,0.214716659413344 +"41|WEU","7p0",2090,0.273384946417078 +"42|FSU","7p0",2020,0.0269369576868714 +"42|FSU","7p0",2025,0.0298903648608786 +"42|FSU","7p0",2030,0.0350412839241017 +"42|FSU","7p0",2035,0.0476603474870443 +"42|FSU","7p0",2040,0.0580485709640966 +"42|FSU","7p0",2045,0.069656052306609 +"42|FSU","7p0",2050,0.0810704524201798 +"42|FSU","7p0",2055,0.0851254851452831 +"42|FSU","7p0",2060,0.0920672564385434 +"42|FSU","7p0",2065,0.0959882348659675 +"42|FSU","7p0",2070,0.0999011688669254 +"42|FSU","7p0",2075,0.120479084381051 +"42|FSU","7p0",2080,0.149301733783549 +"42|FSU","7p0",2085,0.183653704999142 +"42|FSU","7p0",2090,0.220119048740792 +"43|FSU","7p0",2020,0.00498269715981773 +"43|FSU","7p0",2025,0.00567377356526281 +"43|FSU","7p0",2030,0.00689040894560505 +"43|FSU","7p0",2035,0.0101646585114763 +"43|FSU","7p0",2040,0.0146961845741043 +"43|FSU","7p0",2045,0.0219102247588014 +"43|FSU","7p0",2050,0.0316979882602103 +"43|FSU","7p0",2055,0.039970576710486 +"43|FSU","7p0",2060,0.0500206673239628 +"43|FSU","7p0",2065,0.058311435406178 +"43|FSU","7p0",2070,0.0670002374038212 +"43|FSU","7p0",2075,0.0944406054396023 +"43|FSU","7p0",2080,0.130710211981429 +"43|FSU","7p0",2085,0.179915783554218 +"43|FSU","7p0",2090,0.234592511975394 +"44|FSU","7p0",2020,0.0799324692835826 +"44|FSU","7p0",2025,0.0891468278172585 +"44|FSU","7p0",2030,0.104762242548459 +"44|FSU","7p0",2035,0.142458656964893 +"44|FSU","7p0",2040,0.168914868012153 +"44|FSU","7p0",2045,0.190939422668752 +"44|FSU","7p0",2050,0.21078771593702 +"44|FSU","7p0",2055,0.210645903833078 +"44|FSU","7p0",2060,0.217180836220262 +"44|FSU","7p0",2065,0.222936237024359 +"44|FSU","7p0",2070,0.225395360050541 +"44|FSU","7p0",2075,0.246409403656795 +"44|FSU","7p0",2080,0.274993390534351 +"44|FSU","7p0",2085,0.303472471943234 +"44|FSU","7p0",2090,0.32425118611684 +"45|WEU","7p0",2020,1.4225694937682 +"45|WEU","7p0",2025,1.52883388760096 +"45|WEU","7p0",2030,1.59290287063112 +"45|WEU","7p0",2035,1.68038815981493 +"45|WEU","7p0",2040,1.73394900268313 +"45|WEU","7p0",2045,1.80211257976036 +"45|WEU","7p0",2050,1.86707357251382 +"45|WEU","7p0",2055,1.96903197293266 +"45|WEU","7p0",2060,2.12484791331499 +"45|WEU","7p0",2065,2.33269799747254 +"45|WEU","7p0",2070,2.61378783397703 +"45|WEU","7p0",2075,3.00123888620256 +"45|WEU","7p0",2080,3.3708198199779 +"45|WEU","7p0",2085,3.88356175772716 +"45|WEU","7p0",2090,4.37890583855729 +"46|LAM","7p0",2020,0.0223840075942231 +"46|LAM","7p0",2025,0.0230975918030641 +"46|LAM","7p0",2030,0.0247567262245908 +"46|LAM","7p0",2035,0.02775557816365 +"46|LAM","7p0",2040,0.0309480955489398 +"46|LAM","7p0",2045,0.0361429216993634 +"46|LAM","7p0",2050,0.043149109899218 +"46|LAM","7p0",2055,0.0517209063115772 +"46|LAM","7p0",2060,0.0636022140484731 +"46|LAM","7p0",2065,0.0753704182510952 +"46|LAM","7p0",2070,0.0891885442449782 +"46|LAM","7p0",2075,0.105601280580769 +"46|LAM","7p0",2080,0.126981194748414 +"46|LAM","7p0",2085,0.151734616621387 +"46|LAM","7p0",2090,0.18376901837908 +"47|WEU","7p0",2020,1.29019167232257 +"47|WEU","7p0",2025,1.40538313082465 +"47|WEU","7p0",2030,1.47092807871924 +"47|WEU","7p0",2035,1.56331684821558 +"47|WEU","7p0",2040,1.61894402854376 +"47|WEU","7p0",2045,1.69292476615412 +"47|WEU","7p0",2050,1.76404312470983 +"47|WEU","7p0",2055,1.87794173264752 +"47|WEU","7p0",2060,2.04094541466536 +"47|WEU","7p0",2065,2.2502500257638 +"47|WEU","7p0",2070,2.52434339917977 +"47|WEU","7p0",2075,2.8896507458966 +"47|WEU","7p0",2080,3.23978161286086 +"47|WEU","7p0",2085,3.70709655696578 +"47|WEU","7p0",2090,4.21305289354963 +"48|WEU","7p0",2020,0.0719101070285133 +"48|WEU","7p0",2025,0.0782734186233036 +"48|WEU","7p0",2030,0.0819153017849602 +"48|WEU","7p0",2035,0.0902612972140211 +"48|WEU","7p0",2040,0.0993365567215862 +"48|WEU","7p0",2045,0.109941867003855 +"48|WEU","7p0",2050,0.123329449097675 +"48|WEU","7p0",2055,0.134881099972702 +"48|WEU","7p0",2060,0.154066324534333 +"48|WEU","7p0",2065,0.176156211929749 +"48|WEU","7p0",2070,0.201683397400349 +"48|WEU","7p0",2075,0.242954622040332 +"48|WEU","7p0",2080,0.295994407598401 +"48|WEU","7p0",2085,0.354409796234338 +"48|WEU","7p0",2090,0.429178778824604 +"49|WEU","7p0",2020,0.109924419674352 +"49|WEU","7p0",2025,0.115161989451339 +"49|WEU","7p0",2030,0.117880328609239 +"49|WEU","7p0",2035,0.124966375664822 +"49|WEU","7p0",2040,0.131368312516864 +"49|WEU","7p0",2045,0.137983673944397 +"49|WEU","7p0",2050,0.144970869855056 +"49|WEU","7p0",2055,0.152039902017824 +"49|WEU","7p0",2060,0.16239241083783 +"49|WEU","7p0",2065,0.17531131128887 +"49|WEU","7p0",2070,0.192233518958461 +"49|WEU","7p0",2075,0.211068959022702 +"49|WEU","7p0",2080,0.236929604252214 +"49|WEU","7p0",2085,0.262505194756327 +"49|WEU","7p0",2090,0.290612456123849 +"4|MEA","7p0",2020,0.112147458160782 +"4|MEA","7p0",2025,0.119284839405542 +"4|MEA","7p0",2030,0.137615762244329 +"4|MEA","7p0",2035,0.181152984737925 +"4|MEA","7p0",2040,0.243185639212703 +"4|MEA","7p0",2045,0.344425433662503 +"4|MEA","7p0",2050,0.463852211800649 +"4|MEA","7p0",2055,0.636847424365109 +"4|MEA","7p0",2060,0.848301371283654 +"4|MEA","7p0",2065,1.11384166665013 +"4|MEA","7p0",2070,1.52587394571762 +"4|MEA","7p0",2075,2.08787349090553 +"4|MEA","7p0",2080,2.83977686765062 +"4|MEA","7p0",2085,3.80647820722032 +"4|MEA","7p0",2090,4.93884899202347 +"4|WEU","7p0",2020,1.73413834114386 +"4|WEU","7p0",2025,1.94603863454535 +"4|WEU","7p0",2030,2.13155116942873 +"4|WEU","7p0",2035,2.31837535297471 +"4|WEU","7p0",2040,2.45020130985783 +"4|WEU","7p0",2045,2.64644659933312 +"4|WEU","7p0",2050,2.72325579056145 +"4|WEU","7p0",2055,3.02571048124984 +"4|WEU","7p0",2060,3.39994575299722 +"4|WEU","7p0",2065,3.79412047879884 +"4|WEU","7p0",2070,4.47620993371052 +"4|WEU","7p0",2075,5.17853514826808 +"4|WEU","7p0",2080,5.81910191685624 +"4|WEU","7p0",2085,6.63159824195005 +"4|WEU","7p0",2090,7.73708699224075 +"50|MEA","7p0",2020,0.125268539237754 +"50|MEA","7p0",2025,0.130226030232199 +"50|MEA","7p0",2030,0.138156817658597 +"50|MEA","7p0",2035,0.16064712539715 +"50|MEA","7p0",2040,0.191483240304319 +"50|MEA","7p0",2045,0.228248562275833 +"50|MEA","7p0",2050,0.282527438862806 +"50|MEA","7p0",2055,0.345020764371835 +"50|MEA","7p0",2060,0.414616677593272 +"50|MEA","7p0",2065,0.500440393571082 +"50|MEA","7p0",2070,0.608751653560656 +"50|MEA","7p0",2075,0.753171490911532 +"50|MEA","7p0",2080,0.95220374622337 +"50|MEA","7p0",2085,1.22287751990569 +"50|MEA","7p0",2090,1.58544247960515 +"50|SAS","7p0",2020,0.0549106369537663 +"50|SAS","7p0",2025,0.0587405753659065 +"50|SAS","7p0",2030,0.0625084908873949 +"50|SAS","7p0",2035,0.0716300169765599 +"50|SAS","7p0",2040,0.0836975037815558 +"50|SAS","7p0",2045,0.10237703468777 +"50|SAS","7p0",2050,0.134176215840997 +"50|SAS","7p0",2055,0.183220355688925 +"50|SAS","7p0",2060,0.255822312268733 +"50|SAS","7p0",2065,0.349482597985463 +"50|SAS","7p0",2070,0.481515551576165 +"50|SAS","7p0",2075,0.662790727145271 +"50|SAS","7p0",2080,0.894616059968521 +"50|SAS","7p0",2085,1.24387630928607 +"50|SAS","7p0",2090,1.73260431102216 +"51|FSU","7p0",2020,0.0746488464884602 +"51|FSU","7p0",2025,0.0794536117976585 +"51|FSU","7p0",2030,0.0887337557811293 +"51|FSU","7p0",2035,0.109243724848956 +"51|FSU","7p0",2040,0.124427087745082 +"51|FSU","7p0",2045,0.136665519880408 +"51|FSU","7p0",2050,0.145405623896746 +"51|FSU","7p0",2055,0.144565288505593 +"51|FSU","7p0",2060,0.144491517799326 +"51|FSU","7p0",2065,0.142508914354527 +"51|FSU","7p0",2070,0.137957838484122 +"51|FSU","7p0",2075,0.143930989583215 +"51|FSU","7p0",2080,0.1530040895535 +"51|FSU","7p0",2085,0.158741265500277 +"51|FSU","7p0",2090,0.165940088908003 +"51|WEU","7p0",2020,0.000500100302829146 +"51|WEU","7p0",2025,0.000504652600175231 +"51|WEU","7p0",2030,0.000510023594464587 +"51|WEU","7p0",2035,0.000520299897748037 +"51|WEU","7p0",2040,0.000534885997624234 +"51|WEU","7p0",2045,0.000555481015071759 +"51|WEU","7p0",2050,0.000583647156000697 +"51|WEU","7p0",2055,0.000622290690890989 +"51|WEU","7p0",2060,0.000673521579635402 +"51|WEU","7p0",2065,0.000750093080006713 +"51|WEU","7p0",2070,0.000858743900715483 +"51|WEU","7p0",2075,0.00103373412475711 +"51|WEU","7p0",2080,0.00131402445150295 +"51|WEU","7p0",2085,0.00166336893866833 +"51|WEU","7p0",2090,0.00221005291294571 +"52|NAM","7p0",2020,0.465428038511642 +"52|NAM","7p0",2025,0.467107586681561 +"52|NAM","7p0",2030,0.468820326708544 +"52|NAM","7p0",2035,0.471180472209845 +"52|NAM","7p0",2040,0.472841624150281 +"52|NAM","7p0",2045,0.475522479193249 +"52|NAM","7p0",2050,0.477187915792609 +"52|NAM","7p0",2055,0.478324578744789 +"52|NAM","7p0",2060,0.480300941142662 +"52|NAM","7p0",2065,0.481738340495095 +"52|NAM","7p0",2070,0.483917134604494 +"52|NAM","7p0",2075,0.482051573956631 +"52|NAM","7p0",2080,0.485412500403545 +"52|NAM","7p0",2085,0.488995709265887 +"52|NAM","7p0",2090,0.49265727638757 +"53|CHN","7p0",2020,0 +"53|CHN","7p0",2025,0 +"53|CHN","7p0",2030,0 +"53|CHN","7p0",2035,0 +"53|CHN","7p0",2040,0 +"53|CHN","7p0",2045,0.00521753122539164 +"53|CHN","7p0",2050,0.0462579463535085 +"53|CHN","7p0",2055,0.0757575390199121 +"53|CHN","7p0",2060,0.115906170327452 +"53|CHN","7p0",2065,0.152976339160197 +"53|CHN","7p0",2070,0.189123951078768 +"53|CHN","7p0",2075,0.231844420433603 +"53|CHN","7p0",2080,0.286100351656562 +"53|CHN","7p0",2085,0.330515803086383 +"53|CHN","7p0",2090,0.384325190207513 +"53|SAS","7p0",2020,0.306236370632862 +"53|SAS","7p0",2025,0.436040536817172 +"53|SAS","7p0",2030,0.5700434865516 +"53|SAS","7p0",2035,0.803916364225496 +"53|SAS","7p0",2040,1.08767346663372 +"53|SAS","7p0",2045,1.46437964420853 +"53|SAS","7p0",2050,1.94607797843082 +"53|SAS","7p0",2055,2.56914128040657 +"53|SAS","7p0",2060,3.45474015275653 +"53|SAS","7p0",2065,4.48123821590069 +"53|SAS","7p0",2070,5.87498127095647 +"53|SAS","7p0",2075,7.48130138428862 +"53|SAS","7p0",2080,9.54060119339855 +"53|SAS","7p0",2085,12.2770747106688 +"53|SAS","7p0",2090,15.3496782875665 +"54|CHN","7p0",2020,1.24974385853273 +"54|CHN","7p0",2025,2.03778452449343 +"54|CHN","7p0",2030,3.04100117645757 +"54|CHN","7p0",2035,4.71346207974964 +"54|CHN","7p0",2040,6.45682664933293 +"54|CHN","7p0",2045,8.42859747639568 +"54|CHN","7p0",2050,10.6150302538952 +"54|CHN","7p0",2055,12.4339815526312 +"54|CHN","7p0",2060,14.4703081523057 +"54|CHN","7p0",2065,16.5719526181687 +"54|CHN","7p0",2070,18.6848834291823 +"54|CHN","7p0",2075,21.6652877637572 +"54|CHN","7p0",2080,24.959699520326 +"54|CHN","7p0",2085,28.3548764003506 +"54|CHN","7p0",2090,32.2202878752793 +"54|FSU","7p0",2020,0.074893065512751 +"54|FSU","7p0",2025,0.0795209151159297 +"54|FSU","7p0",2030,0.0888787696379346 +"54|FSU","7p0",2035,0.110130849176436 +"54|FSU","7p0",2040,0.127429893881879 +"54|FSU","7p0",2045,0.142369744402141 +"54|FSU","7p0",2050,0.155319728981615 +"54|FSU","7p0",2055,0.162225822960553 +"54|FSU","7p0",2060,0.169083670447589 +"54|FSU","7p0",2065,0.181849478551644 +"54|FSU","7p0",2070,0.196903468818659 +"54|FSU","7p0",2075,0.218613991935903 +"54|FSU","7p0",2080,0.236047343508404 +"54|FSU","7p0",2085,0.244568006176139 +"54|FSU","7p0",2090,0.248207527182352 +"55|NAM","7p0",2020,3.77450854399706 +"55|NAM","7p0",2025,4.06814911784786 +"55|NAM","7p0",2030,4.29998291666461 +"55|NAM","7p0",2035,4.63014734780394 +"55|NAM","7p0",2040,5.01438238566165 +"55|NAM","7p0",2045,5.22985890937021 +"55|NAM","7p0",2050,5.41902687545907 +"55|NAM","7p0",2055,5.64756539749638 +"55|NAM","7p0",2060,5.83079187887666 +"55|NAM","7p0",2065,6.10877361583435 +"55|NAM","7p0",2070,6.48549328017099 +"55|NAM","7p0",2075,6.70198860766797 +"55|NAM","7p0",2080,6.94440978740038 +"55|NAM","7p0",2085,7.17654307761889 +"55|NAM","7p0",2090,7.31773076181905 +"56|NAM","7p0",2020,4.02700181990485 +"56|NAM","7p0",2025,4.34236552646016 +"56|NAM","7p0",2030,4.5621380265754 +"56|NAM","7p0",2035,4.90311759048739 +"56|NAM","7p0",2040,5.19545050123018 +"56|NAM","7p0",2045,5.36460440058677 +"56|NAM","7p0",2050,5.59637852006866 +"56|NAM","7p0",2055,5.86194882045479 +"56|NAM","7p0",2060,6.06360424203716 +"56|NAM","7p0",2065,6.30300333571964 +"56|NAM","7p0",2070,6.548282293565 +"56|NAM","7p0",2075,6.82228052093167 +"56|NAM","7p0",2080,7.1367896502711 +"56|NAM","7p0",2085,7.68352552520896 +"56|NAM","7p0",2090,8.09472523706147 +"57|AFR","7p0",2020,0.0015948285342423 +"57|AFR","7p0",2025,0.00172968668342145 +"57|AFR","7p0",2030,0.00234250246510946 +"57|AFR","7p0",2035,0.00379603429600773 +"57|AFR","7p0",2040,0.00632397741233099 +"57|AFR","7p0",2045,0.0112979287907775 +"57|AFR","7p0",2050,0.0201490243320435 +"57|AFR","7p0",2055,0.0414176786310292 +"57|AFR","7p0",2060,0.0809394531302428 +"57|AFR","7p0",2065,0.151391389559807 +"57|AFR","7p0",2070,0.279416167365716 +"57|AFR","7p0",2075,0.49256465186311 +"57|AFR","7p0",2080,0.841606643743724 +"57|AFR","7p0",2085,1.39909220842597 +"57|AFR","7p0",2090,2.25423857667117 +"58|NAM","7p0",2020,2.94839504189904 +"58|NAM","7p0",2025,3.07781862714988 +"58|NAM","7p0",2030,3.15686837772887 +"58|NAM","7p0",2035,3.31998271844963 +"58|NAM","7p0",2040,3.48132081455483 +"58|NAM","7p0",2045,3.56549387067685 +"58|NAM","7p0",2050,3.64781768839221 +"58|NAM","7p0",2055,3.69619987286156 +"58|NAM","7p0",2060,3.73270206852927 +"58|NAM","7p0",2065,3.8272016727791 +"58|NAM","7p0",2070,4.00978144769466 +"58|NAM","7p0",2075,4.2129431996085 +"58|NAM","7p0",2080,4.37968932158531 +"58|NAM","7p0",2085,4.62877648930016 +"58|NAM","7p0",2090,4.77581205932895 +"59|PAS","7p0",2020,0.0393710697291899 +"59|PAS","7p0",2025,0.0471539874957968 +"59|PAS","7p0",2030,0.0578624255712021 +"59|PAS","7p0",2035,0.0754261040264438 +"59|PAS","7p0",2040,0.0956723624323419 +"59|PAS","7p0",2045,0.120485156647322 +"59|PAS","7p0",2050,0.148126513115576 +"59|PAS","7p0",2055,0.186522224951219 +"59|PAS","7p0",2060,0.231973058952791 +"59|PAS","7p0",2065,0.290554193386528 +"59|PAS","7p0",2070,0.365777365275805 +"59|PAS","7p0",2075,0.446928819345562 +"59|PAS","7p0",2080,0.533326959871369 +"59|PAS","7p0",2085,0.636142897625632 +"59|PAS","7p0",2090,0.758172534362781 +"59|RCPA","7p0",2020,0.0359525156666296 +"59|RCPA","7p0",2025,0.0529153540315809 +"59|RCPA","7p0",2030,0.0690152462753609 +"59|RCPA","7p0",2035,0.0959609805091942 +"59|RCPA","7p0",2040,0.122865616868484 +"59|RCPA","7p0",2045,0.158753841565885 +"59|RCPA","7p0",2050,0.204603808019226 +"59|RCPA","7p0",2055,0.260370479470303 +"59|RCPA","7p0",2060,0.338356409964519 +"59|RCPA","7p0",2065,0.453521176727343 +"59|RCPA","7p0",2070,0.577769638858437 +"59|RCPA","7p0",2075,0.735495834511103 +"59|RCPA","7p0",2080,0.909353633092615 +"59|RCPA","7p0",2085,1.08195438573231 +"59|RCPA","7p0",2090,1.32943096152256 +"5|AFR","7p0",2020,0.00120442004141422 +"5|AFR","7p0",2025,0.00265193628949565 +"5|AFR","7p0",2030,0.00495681337523501 +"5|AFR","7p0",2035,0.0105156574759201 +"5|AFR","7p0",2040,0.021508279601006 +"5|AFR","7p0",2045,0.0389809397623181 +"5|AFR","7p0",2050,0.0701268130213037 +"5|AFR","7p0",2055,0.129638692990257 +"5|AFR","7p0",2060,0.232623489709132 +"5|AFR","7p0",2065,0.399245591246754 +"5|AFR","7p0",2070,0.659325354177081 +"5|AFR","7p0",2075,0.993473548194522 +"5|AFR","7p0",2080,1.29255605816601 +"5|AFR","7p0",2085,1.85514605195144 +"5|AFR","7p0",2090,2.54946759253771 +"5|MEA","7p0",2020,0.145381445223126 +"5|MEA","7p0",2025,0.205124981215205 +"5|MEA","7p0",2030,0.286861509831929 +"5|MEA","7p0",2035,0.453219562374898 +"5|MEA","7p0",2040,0.630690698620491 +"5|MEA","7p0",2045,0.855676328965976 +"5|MEA","7p0",2050,1.14144919082389 +"5|MEA","7p0",2055,1.48500196298063 +"5|MEA","7p0",2060,1.92512144309862 +"5|MEA","7p0",2065,2.47442839525484 +"5|MEA","7p0",2070,3.20207957410353 +"5|MEA","7p0",2075,4.06427599150669 +"5|MEA","7p0",2080,5.11757137373731 +"5|MEA","7p0",2085,6.3785318143881 +"5|MEA","7p0",2090,7.89701992820211 +"60|CHN","7p0",2020,0.676002388319727 +"60|CHN","7p0",2025,1.08623544685392 +"60|CHN","7p0",2030,1.68997810497114 +"60|CHN","7p0",2035,2.62914500345633 +"60|CHN","7p0",2040,3.63609707494066 +"60|CHN","7p0",2045,4.86893370840421 +"60|CHN","7p0",2050,6.11161918692283 +"60|CHN","7p0",2055,7.57048267880688 +"60|CHN","7p0",2060,9.23815449201345 +"60|CHN","7p0",2065,10.6540564141283 +"60|CHN","7p0",2070,12.0712913475102 +"60|CHN","7p0",2075,13.4224833843152 +"60|CHN","7p0",2080,14.8279943639415 +"60|CHN","7p0",2085,17.2827195141833 +"60|CHN","7p0",2090,19.8569853606631 +"61|CHN","7p0",2020,0.535352656812263 +"61|CHN","7p0",2025,0.909838510692483 +"61|CHN","7p0",2030,1.40266383839022 +"61|CHN","7p0",2035,2.22197675627593 +"61|CHN","7p0",2040,3.04929856080924 +"61|CHN","7p0",2045,4.14015757999986 +"61|CHN","7p0",2050,5.2072531472989 +"61|CHN","7p0",2055,6.31669400417818 +"61|CHN","7p0",2060,7.83345027750946 +"61|CHN","7p0",2065,9.28356636778471 +"61|CHN","7p0",2070,10.6142768202144 +"61|CHN","7p0",2075,12.2440725277339 +"61|CHN","7p0",2080,13.8186219216888 +"61|CHN","7p0",2085,15.4932984559379 +"61|CHN","7p0",2090,17.7440964429614 +"61|RCPA","7p0",2020,0.0160825385639592 +"61|RCPA","7p0",2025,0.0213442721557301 +"61|RCPA","7p0",2030,0.0273517987369316 +"61|RCPA","7p0",2035,0.036768705657738 +"61|RCPA","7p0",2040,0.0460981365772916 +"61|RCPA","7p0",2045,0.0612391279619978 +"61|RCPA","7p0",2050,0.0790569434811801 +"61|RCPA","7p0",2055,0.104216375805411 +"61|RCPA","7p0",2060,0.137850695494632 +"61|RCPA","7p0",2065,0.180803869471593 +"61|RCPA","7p0",2070,0.228626473118468 +"61|RCPA","7p0",2075,0.282699180994133 +"61|RCPA","7p0",2080,0.344467129165189 +"61|RCPA","7p0",2085,0.407040853441541 +"61|RCPA","7p0",2090,0.502151080087295 +"62|CHN","7p0",2020,0.965154826241596 +"62|CHN","7p0",2025,1.62547969966534 +"62|CHN","7p0",2030,2.45164652332621 +"62|CHN","7p0",2035,3.79371433737476 +"62|CHN","7p0",2040,5.23609714627892 +"62|CHN","7p0",2045,6.65633779116343 +"62|CHN","7p0",2050,8.66388828190641 +"62|CHN","7p0",2055,10.2904193735833 +"62|CHN","7p0",2060,12.3112444690133 +"62|CHN","7p0",2065,14.6668728116064 +"62|CHN","7p0",2070,16.7444000951151 +"62|CHN","7p0",2075,19.4753553823022 +"62|CHN","7p0",2080,21.9359951742515 +"62|CHN","7p0",2085,24.7731343797892 +"62|CHN","7p0",2090,27.5450722497556 +"63|NAM","7p0",2020,0.0573816064880916 +"63|NAM","7p0",2025,0.0573899714423417 +"63|NAM","7p0",2030,0.0573981570745953 +"63|NAM","7p0",2035,0.0574116795725588 +"63|NAM","7p0",2040,0.0574290017299624 +"63|NAM","7p0",2045,0.0574511785319611 +"63|NAM","7p0",2050,0.0574811885003666 +"63|NAM","7p0",2055,0.0575024333741428 +"63|NAM","7p0",2060,0.0575278878571689 +"63|NAM","7p0",2065,0.057560304791704 +"63|NAM","7p0",2070,0.0575915100501722 +"63|NAM","7p0",2075,0.0576618711900352 +"63|NAM","7p0",2080,0.0577679430191759 +"63|NAM","7p0",2085,0.0578960705814324 +"63|NAM","7p0",2090,0.0580796232076825 +"65|SAS","7p0",2020,0.366989559558185 +"65|SAS","7p0",2025,0.525705297534255 +"65|SAS","7p0",2030,0.686668613844098 +"65|SAS","7p0",2035,0.966060622429227 +"65|SAS","7p0",2040,1.30352216281884 +"65|SAS","7p0",2045,1.73956501198511 +"65|SAS","7p0",2050,2.37452630444261 +"65|SAS","7p0",2055,3.18320393160928 +"65|SAS","7p0",2060,4.22968376453537 +"65|SAS","7p0",2065,5.47437941375246 +"65|SAS","7p0",2070,7.07183300839795 +"65|SAS","7p0",2075,8.99338978408481 +"65|SAS","7p0",2080,11.4535733202739 +"65|SAS","7p0",2085,14.7611207488474 +"65|SAS","7p0",2090,18.6512989168827 +"66|SAS","7p0",2020,0.288868737656208 +"66|SAS","7p0",2025,0.401067243068582 +"66|SAS","7p0",2030,0.527007570781395 +"66|SAS","7p0",2035,0.737932412998721 +"66|SAS","7p0",2040,0.986634831898666 +"66|SAS","7p0",2045,1.32834659871089 +"66|SAS","7p0",2050,1.80402492581158 +"66|SAS","7p0",2055,2.35242100196142 +"66|SAS","7p0",2060,3.14089430032411 +"66|SAS","7p0",2065,3.99807738177819 +"66|SAS","7p0",2070,5.15771389699758 +"66|SAS","7p0",2075,6.53178380521718 +"66|SAS","7p0",2080,8.29671371666787 +"66|SAS","7p0",2085,10.7423808137738 +"66|SAS","7p0",2090,13.5224642311601 +"67|CHN","7p0",2020,0 +"67|CHN","7p0",2025,0 +"67|CHN","7p0",2030,0.083146663465575 +"67|CHN","7p0",2035,0.25292706901484 +"67|CHN","7p0",2040,0.439983868481743 +"67|CHN","7p0",2045,0.656878279292182 +"67|CHN","7p0",2050,0.873752069604911 +"67|CHN","7p0",2055,1.00779314748358 +"67|CHN","7p0",2060,1.13141193538295 +"67|CHN","7p0",2065,1.22348769961794 +"67|CHN","7p0",2070,1.29588401763477 +"67|CHN","7p0",2075,1.47791368067568 +"67|CHN","7p0",2080,1.64623929911656 +"67|CHN","7p0",2085,1.74836012820466 +"67|CHN","7p0",2090,1.86236365507425 +"67|SAS","7p0",2020,0.102379148456279 +"67|SAS","7p0",2025,0.122398753311053 +"67|SAS","7p0",2030,0.142454548594776 +"67|SAS","7p0",2035,0.17975422468248 +"67|SAS","7p0",2040,0.230006387382995 +"67|SAS","7p0",2045,0.297529994133572 +"67|SAS","7p0",2050,0.392028501887707 +"67|SAS","7p0",2055,0.519249685575877 +"67|SAS","7p0",2060,0.680253926064004 +"67|SAS","7p0",2065,0.896522455669972 +"67|SAS","7p0",2070,1.19035587666465 +"67|SAS","7p0",2075,1.57607111612576 +"67|SAS","7p0",2080,2.09545144805113 +"67|SAS","7p0",2085,2.75717894620232 +"67|SAS","7p0",2090,3.54343306755815 +"68|WEU","7p0",2020,0.0161777522398462 +"68|WEU","7p0",2025,0.0166750998031253 +"68|WEU","7p0",2030,0.0169889273299016 +"68|WEU","7p0",2035,0.0176390672708869 +"68|WEU","7p0",2040,0.0182600248768824 +"68|WEU","7p0",2045,0.0189827076917654 +"68|WEU","7p0",2050,0.0198211264912815 +"68|WEU","7p0",2055,0.0206267058690813 +"68|WEU","7p0",2060,0.0217447135610444 +"68|WEU","7p0",2065,0.0233890584801986 +"68|WEU","7p0",2070,0.0253282455416877 +"68|WEU","7p0",2075,0.0276684610652519 +"68|WEU","7p0",2080,0.0311215463691062 +"68|WEU","7p0",2085,0.0349063089024289 +"68|WEU","7p0",2090,0.0398270480969767 +"69|PAS","7p0",2020,0.0747141667140417 +"69|PAS","7p0",2025,0.0750090230806069 +"69|PAS","7p0",2030,0.0754385988863847 +"69|PAS","7p0",2035,0.0761259974782559 +"69|PAS","7p0",2040,0.0769102034891852 +"69|PAS","7p0",2045,0.0778419902914787 +"69|PAS","7p0",2050,0.0788715245015107 +"69|PAS","7p0",2055,0.0805586239291348 +"69|PAS","7p0",2060,0.0828698624760078 +"69|PAS","7p0",2065,0.0859196593387483 +"69|PAS","7p0",2070,0.0897964999406785 +"69|PAS","7p0",2075,0.094285048241733 +"69|PAS","7p0",2080,0.0994722260342302 +"69|PAS","7p0",2085,0.105797366582665 +"69|PAS","7p0",2090,0.11364967799833 +"6|AFR","7p0",2020,0.000284540817011304 +"6|AFR","7p0",2025,0.000300784599518209 +"6|AFR","7p0",2030,0.00036685649196932 +"6|AFR","7p0",2035,0.000571390818042163 +"6|AFR","7p0",2040,0.000883250751662285 +"6|AFR","7p0",2045,0.00170997402309913 +"6|AFR","7p0",2050,0.00304815487854264 +"6|AFR","7p0",2055,0.0048547378666405 +"6|AFR","7p0",2060,0.00951922749279444 +"6|AFR","7p0",2065,0.0145079530801408 +"6|AFR","7p0",2070,0.0199614961544428 +"6|AFR","7p0",2075,0.0293744498884521 +"6|AFR","7p0",2080,0.0412206149886416 +"6|AFR","7p0",2085,0.057603669691023 +"6|AFR","7p0",2090,0.085681080652148 +"70|CHN","7p0",2020,0 +"70|CHN","7p0",2025,0 +"70|CHN","7p0",2030,0 +"70|CHN","7p0",2035,0 +"70|CHN","7p0",2040,0.0322258642755122 +"70|CHN","7p0",2045,0.094160187137634 +"70|CHN","7p0",2050,0.155707870050112 +"70|CHN","7p0",2055,0.217470965526648 +"70|CHN","7p0",2060,0.278707689781565 +"70|CHN","7p0",2065,0.350327757077793 +"70|CHN","7p0",2070,0.41682929569467 +"70|CHN","7p0",2075,0.484350867176514 +"70|CHN","7p0",2080,0.574752811584952 +"70|CHN","7p0",2085,0.641029148810485 +"70|CHN","7p0",2090,0.743466776081594 +"70|PAS","7p0",2020,0.0202141279771139 +"70|PAS","7p0",2025,0.0212125831877139 +"70|PAS","7p0",2030,0.022600563319955 +"70|PAS","7p0",2035,0.0250217361842587 +"70|PAS","7p0",2040,0.0277871990388385 +"70|PAS","7p0",2045,0.0311115491808239 +"70|PAS","7p0",2050,0.0346149498632664 +"70|PAS","7p0",2055,0.0392475713480589 +"70|PAS","7p0",2060,0.0447933741319057 +"70|PAS","7p0",2065,0.0521350805812512 +"70|PAS","7p0",2070,0.0613937120263917 +"70|PAS","7p0",2075,0.0714671712914093 +"70|PAS","7p0",2080,0.0804438177468418 +"70|PAS","7p0",2085,0.0937475207876481 +"70|PAS","7p0",2090,0.109132664988788 +"70|SAS","7p0",2020,0.155807563357859 +"70|SAS","7p0",2025,0.176271350199671 +"70|SAS","7p0",2030,0.196718154309875 +"70|SAS","7p0",2035,0.237514467953751 +"70|SAS","7p0",2040,0.286446457254338 +"70|SAS","7p0",2045,0.354191367991423 +"70|SAS","7p0",2050,0.435113975703869 +"70|SAS","7p0",2055,0.548733957310337 +"70|SAS","7p0",2060,0.68238909829922 +"70|SAS","7p0",2065,0.867595446508966 +"70|SAS","7p0",2070,1.10692414103803 +"70|SAS","7p0",2075,1.36618908730444 +"70|SAS","7p0",2080,1.70718578509316 +"70|SAS","7p0",2085,2.06135722073607 +"70|SAS","7p0",2090,2.48393432351045 +"71|FSU","7p0",2020,0.0579458262410138 +"71|FSU","7p0",2025,0.0579846637988869 +"71|FSU","7p0",2030,0.0580526005185738 +"71|FSU","7p0",2035,0.0582045964756143 +"71|FSU","7p0",2040,0.0583024733040208 +"71|FSU","7p0",2045,0.0583808020204346 +"71|FSU","7p0",2050,0.0584334007850289 +"71|FSU","7p0",2055,0.0585618661998441 +"71|FSU","7p0",2060,0.0587544411154504 +"71|FSU","7p0",2065,0.0589746185327326 +"71|FSU","7p0",2070,0.0592613661928826 +"71|FSU","7p0",2075,0.0594913056880201 +"71|FSU","7p0",2080,0.0597159835939953 +"71|FSU","7p0",2085,0.0599997256546587 +"71|FSU","7p0",2090,0.0602126676243887 +"71|PAO","7p0",2020,0.17806525 +"71|PAO","7p0",2025,0.186767641078545 +"71|PAO","7p0",2030,0.191017853280027 +"71|PAO","7p0",2035,0.201925292048529 +"71|PAO","7p0",2040,0.211866650760367 +"71|PAO","7p0",2045,0.22493753418341 +"71|PAO","7p0",2050,0.241643996180187 +"71|PAO","7p0",2055,0.254584474905565 +"71|PAO","7p0",2060,0.269809523269525 +"71|PAO","7p0",2065,0.286171662515654 +"71|PAO","7p0",2070,0.307812883288226 +"71|PAO","7p0",2075,0.335577442863917 +"71|PAO","7p0",2080,0.373655937939662 +"71|PAO","7p0",2085,0.419897202536606 +"71|PAO","7p0",2090,0.463965080980969 +"72|PAS","7p0",2020,0.2112217371631 +"72|PAS","7p0",2025,0.273151763783985 +"72|PAS","7p0",2030,0.340338278820589 +"72|PAS","7p0",2035,0.450869616021286 +"72|PAS","7p0",2040,0.56784031732671 +"72|PAS","7p0",2045,0.720188615017025 +"72|PAS","7p0",2050,0.947524513877413 +"72|PAS","7p0",2055,1.22419265207359 +"72|PAS","7p0",2060,1.58897473891399 +"72|PAS","7p0",2065,2.04285047355844 +"72|PAS","7p0",2070,2.62388210245616 +"72|PAS","7p0",2075,3.28446700858689 +"72|PAS","7p0",2080,4.14813833082926 +"72|PAS","7p0",2085,5.2015102824591 +"72|PAS","7p0",2090,6.31633041353467 +"73|PAS","7p0",2020,0.0571404155809709 +"73|PAS","7p0",2025,0.057816529430556 +"73|PAS","7p0",2030,0.0586353018814382 +"73|PAS","7p0",2035,0.0599198445709984 +"73|PAS","7p0",2040,0.0613812280877799 +"73|PAS","7p0",2045,0.0632022448536321 +"73|PAS","7p0",2050,0.0653848317213462 +"73|PAS","7p0",2055,0.0690040152934064 +"73|PAS","7p0",2060,0.0737183555013039 +"73|PAS","7p0",2065,0.0798290100173186 +"73|PAS","7p0",2070,0.0886665868439795 +"73|PAS","7p0",2075,0.0993387757755593 +"73|PAS","7p0",2080,0.111609710344347 +"73|PAS","7p0",2085,0.125700719807458 +"73|PAS","7p0",2090,0.14382484476042 +"74|FSU","7p0",2020,0.0580767880493127 +"74|FSU","7p0",2025,0.0581634265286704 +"74|FSU","7p0",2030,0.0583447155062902 +"74|FSU","7p0",2035,0.0587448234099771 +"74|FSU","7p0",2040,0.0590438522667636 +"74|FSU","7p0",2045,0.0592956534113923 +"74|FSU","7p0",2050,0.0594556623593472 +"74|FSU","7p0",2055,0.05941939415169 +"74|FSU","7p0",2060,0.0593907917966255 +"74|FSU","7p0",2065,0.0593248750724025 +"74|FSU","7p0",2070,0.0592308790297149 +"74|FSU","7p0",2075,0.0593535348273987 +"74|FSU","7p0",2080,0.0595494055079 +"74|FSU","7p0",2085,0.0597146516067762 +"74|FSU","7p0",2090,0.059814878845409 +"75|LAM","7p0",2020,0.0138350317779591 +"75|LAM","7p0",2025,0.0139932640164312 +"75|LAM","7p0",2030,0.0142505306450442 +"75|LAM","7p0",2035,0.0147642303353953 +"75|LAM","7p0",2040,0.0153595690866788 +"75|LAM","7p0",2045,0.0161546506317664 +"75|LAM","7p0",2050,0.017273735383806 +"75|LAM","7p0",2055,0.0187653187355698 +"75|LAM","7p0",2060,0.0209497044382475 +"75|LAM","7p0",2065,0.0237902497349983 +"75|LAM","7p0",2070,0.0276283908325373 +"75|LAM","7p0",2075,0.0334303528452889 +"75|LAM","7p0",2080,0.0409460511905903 +"75|LAM","7p0",2085,0.0518398550678725 +"75|LAM","7p0",2090,0.065543343698119 +"76|LAM","7p0",2020,0.016241515033149 +"76|LAM","7p0",2025,0.0190122387146964 +"76|LAM","7p0",2030,0.0239217552750691 +"76|LAM","7p0",2035,0.0347051785880519 +"76|LAM","7p0",2040,0.0478724436905567 +"76|LAM","7p0",2045,0.0669123310844145 +"76|LAM","7p0",2050,0.0925374966227919 +"76|LAM","7p0",2055,0.126922476755639 +"76|LAM","7p0",2060,0.172739432374162 +"76|LAM","7p0",2065,0.23813964539499 +"76|LAM","7p0",2070,0.323847090083374 +"76|LAM","7p0",2075,0.443007378362162 +"76|LAM","7p0",2080,0.60586732503175 +"76|LAM","7p0",2085,0.822850038439625 +"76|LAM","7p0",2090,1.10113351586528 +"77|CHN","7p0",2020,1.32740770537781 +"77|CHN","7p0",2025,2.10056999898396 +"77|CHN","7p0",2030,3.0933015614129 +"77|CHN","7p0",2035,4.71256459100987 +"77|CHN","7p0",2040,6.37491275028771 +"77|CHN","7p0",2045,8.31545952404915 +"77|CHN","7p0",2050,10.347184366772 +"77|CHN","7p0",2055,12.4531598546141 +"77|CHN","7p0",2060,14.6922887850138 +"77|CHN","7p0",2065,17.2599305661333 +"77|CHN","7p0",2070,20.2003468410308 +"77|CHN","7p0",2075,23.7000796437761 +"77|CHN","7p0",2080,27.2989262535477 +"77|CHN","7p0",2085,31.2096192928507 +"77|CHN","7p0",2090,36.4918587773812 +"77|FSU","7p0",2020,0.11253966131433 +"77|FSU","7p0",2025,0.126188262409846 +"77|FSU","7p0",2030,0.149453603966729 +"77|FSU","7p0",2035,0.192063897234015 +"77|FSU","7p0",2040,0.226487516324531 +"77|FSU","7p0",2045,0.252098848568509 +"77|FSU","7p0",2050,0.261402470937259 +"77|FSU","7p0",2055,0.253322180086568 +"77|FSU","7p0",2060,0.247846969554172 +"77|FSU","7p0",2065,0.250127128725083 +"77|FSU","7p0",2070,0.259838539669087 +"77|FSU","7p0",2075,0.273568615722547 +"77|FSU","7p0",2080,0.292852725482611 +"77|FSU","7p0",2085,0.317752663204314 +"77|FSU","7p0",2090,0.348395979036476 +"78|AFR","7p0",2020,0.00531674668954976 +"78|AFR","7p0",2025,0.00539488457965792 +"78|AFR","7p0",2030,0.00711603085929706 +"78|AFR","7p0",2035,0.0106842218771291 +"78|AFR","7p0",2040,0.0164263579476835 +"78|AFR","7p0",2045,0.0277168733942462 +"78|AFR","7p0",2050,0.0481036767787338 +"78|AFR","7p0",2055,0.0900646238713095 +"78|AFR","7p0",2060,0.164857333938625 +"78|AFR","7p0",2065,0.287535188751395 +"78|AFR","7p0",2070,0.463691922302705 +"78|AFR","7p0",2075,0.755253486567825 +"78|AFR","7p0",2080,1.16422709113674 +"78|AFR","7p0",2085,1.85160084361637 +"78|AFR","7p0",2090,2.85085369535878 +"78|MEA","7p0",2020,0.450358447527383 +"78|MEA","7p0",2025,0.486072895648019 +"78|MEA","7p0",2030,0.527244162645972 +"78|MEA","7p0",2035,0.598286094960019 +"78|MEA","7p0",2040,0.678632877763188 +"78|MEA","7p0",2045,0.765417277926944 +"78|MEA","7p0",2050,0.875728104880197 +"78|MEA","7p0",2055,1.03464848658816 +"78|MEA","7p0",2060,1.26074981839597 +"78|MEA","7p0",2065,1.58002002076627 +"78|MEA","7p0",2070,1.97356495107324 +"78|MEA","7p0",2075,2.49026338814696 +"78|MEA","7p0",2080,3.15792521210655 +"78|MEA","7p0",2085,4.00139971634684 +"78|MEA","7p0",2090,5.23007848160691 +"79|FSU","7p0",2020,0.0583575171506303 +"79|FSU","7p0",2025,0.0585431304687383 +"79|FSU","7p0",2030,0.0589244520322733 +"79|FSU","7p0",2035,0.0597471808250337 +"79|FSU","7p0",2040,0.0603414283793901 +"79|FSU","7p0",2045,0.0608109681095084 +"79|FSU","7p0",2050,0.0611510898962562 +"79|FSU","7p0",2055,0.0609084030086408 +"79|FSU","7p0",2060,0.0606380720872433 +"79|FSU","7p0",2065,0.0602222913073555 +"79|FSU","7p0",2070,0.0596181336091519 +"79|FSU","7p0",2075,0.0596347399039585 +"79|FSU","7p0",2080,0.059792491901077 +"79|FSU","7p0",2085,0.0599324736734982 +"79|FSU","7p0",2090,0.0600228472459363 +"7|AFR","7p0",2020,0.0113295364381306 +"7|AFR","7p0",2025,0.0135920798017873 +"7|AFR","7p0",2030,0.019512554824643 +"7|AFR","7p0",2035,0.0346141220461214 +"7|AFR","7p0",2040,0.0541687355949232 +"7|AFR","7p0",2045,0.0873470955144764 +"7|AFR","7p0",2050,0.139108345362656 +"7|AFR","7p0",2055,0.23443462086956 +"7|AFR","7p0",2060,0.375777048715244 +"7|AFR","7p0",2065,0.574599948325861 +"7|AFR","7p0",2070,0.860884549824872 +"7|AFR","7p0",2075,1.22337330393375 +"7|AFR","7p0",2080,1.68420755012974 +"7|AFR","7p0",2085,2.30382654088048 +"7|AFR","7p0",2090,3.10862814865625 +"80|AFR","7p0",2020,0.0648894095998866 +"80|AFR","7p0",2025,0.0661890593846625 +"80|AFR","7p0",2030,0.0735841958917925 +"80|AFR","7p0",2035,0.0906975075998528 +"80|AFR","7p0",2040,0.113938196088532 +"80|AFR","7p0",2045,0.143474713905897 +"80|AFR","7p0",2050,0.180888317712468 +"80|AFR","7p0",2055,0.227898683074887 +"80|AFR","7p0",2060,0.282861288767781 +"80|AFR","7p0",2065,0.363926418890066 +"80|AFR","7p0",2070,0.442359449474572 +"80|AFR","7p0",2075,0.542469858104127 +"80|AFR","7p0",2080,0.66753952598262 +"80|AFR","7p0",2085,0.806783263562026 +"80|AFR","7p0",2090,0.972045300527235 +"81|NAM","7p0",2020,0.0575243794620037 +"81|NAM","7p0",2025,0.0575595209049069 +"81|NAM","7p0",2030,0.0575860625881588 +"81|NAM","7p0",2035,0.0576366293617381 +"81|NAM","7p0",2040,0.0577002342802398 +"81|NAM","7p0",2045,0.0578190166078198 +"81|NAM","7p0",2050,0.0579514213809261 +"81|NAM","7p0",2055,0.0580315430313184 +"81|NAM","7p0",2060,0.0581175730254958 +"81|NAM","7p0",2065,0.0581763771270883 +"81|NAM","7p0",2070,0.0582070514883282 +"81|NAM","7p0",2075,0.0584255139181554 +"81|NAM","7p0",2080,0.0588182885506646 +"81|NAM","7p0",2085,0.0593335702553164 +"81|NAM","7p0",2090,0.0599698442728564 +"82|AFR","7p0",2020,5.84e-06 +"82|AFR","7p0",2025,7.29759336735892e-06 +"82|AFR","7p0",2030,9.79737161020387e-06 +"82|AFR","7p0",2035,1.52102284480631e-05 +"82|AFR","7p0",2040,2.62007059753913e-05 +"82|AFR","7p0",2045,4.62513345456447e-05 +"82|AFR","7p0",2050,9.00945816218192e-05 +"82|AFR","7p0",2055,0.000186278842349495 +"82|AFR","7p0",2060,0.000378784371384618 +"82|AFR","7p0",2065,0.000725072185977265 +"82|AFR","7p0",2070,0.00145382245221397 +"82|AFR","7p0",2075,0.00289474726623757 +"82|AFR","7p0",2080,0.00558864910203437 +"82|AFR","7p0",2085,0.0104273311287504 +"82|AFR","7p0",2090,0.0191748225238428 +"83|LAM","7p0",2020,0.00602730120871597 +"83|LAM","7p0",2025,0.0068339338332323 +"83|LAM","7p0",2030,0.00778756629903559 +"83|LAM","7p0",2035,0.00967294279696517 +"83|LAM","7p0",2040,0.011817338597163 +"83|LAM","7p0",2045,0.0148928861735863 +"83|LAM","7p0",2050,0.0184788688482127 +"83|LAM","7p0",2055,0.0228355965067025 +"83|LAM","7p0",2060,0.0275808070290526 +"83|LAM","7p0",2065,0.0342325572064927 +"83|LAM","7p0",2070,0.0424101774461642 +"83|LAM","7p0",2075,0.0535387304940024 +"83|LAM","7p0",2080,0.0700198491756125 +"83|LAM","7p0",2085,0.0854444188072391 +"83|LAM","7p0",2090,0.105689703383708 +"84|LAM","7p0",2020,0.0115610659860458 +"84|LAM","7p0",2025,0.0118572807129154 +"84|LAM","7p0",2030,0.0124906688652842 +"84|LAM","7p0",2035,0.0140774798800481 +"84|LAM","7p0",2040,0.0160867396502448 +"84|LAM","7p0",2045,0.0189248448744004 +"84|LAM","7p0",2050,0.0225290166391389 +"84|LAM","7p0",2055,0.0271966052763494 +"84|LAM","7p0",2060,0.0337016085740932 +"84|LAM","7p0",2065,0.0424337035333429 +"84|LAM","7p0",2070,0.0552446643131295 +"84|LAM","7p0",2075,0.0760418012884017 +"84|LAM","7p0",2080,0.101772219672887 +"84|LAM","7p0",2085,0.140230890137207 +"84|LAM","7p0",2090,0.186246243417106 +"85|MEA","7p0",2020,0.363409365279235 +"85|MEA","7p0",2025,0.477335569350204 +"85|MEA","7p0",2030,0.638536163081491 +"85|MEA","7p0",2035,0.939262102885334 +"85|MEA","7p0",2040,1.2840723335396 +"85|MEA","7p0",2045,1.72321465299668 +"85|MEA","7p0",2050,2.24119589645604 +"85|MEA","7p0",2055,2.96325529803951 +"85|MEA","7p0",2060,3.77679190574706 +"85|MEA","7p0",2065,4.84355061539461 +"85|MEA","7p0",2070,6.19778811734144 +"85|MEA","7p0",2075,7.73101427959169 +"85|MEA","7p0",2080,9.66614188557054 +"85|MEA","7p0",2085,11.667663551473 +"85|MEA","7p0",2090,14.1706386170205 +"85|WEU","7p0",2020,0.104583383783085 +"85|WEU","7p0",2025,0.113256607317693 +"85|WEU","7p0",2030,0.126014997460495 +"85|WEU","7p0",2035,0.142937157736972 +"85|WEU","7p0",2040,0.159914974210644 +"85|WEU","7p0",2045,0.182238918841609 +"85|WEU","7p0",2050,0.201995989958461 +"85|WEU","7p0",2055,0.230232749656508 +"85|WEU","7p0",2060,0.254732020541563 +"85|WEU","7p0",2065,0.289758982550762 +"85|WEU","7p0",2070,0.323762775317533 +"85|WEU","7p0",2075,0.357999980377928 +"85|WEU","7p0",2080,0.409087274951198 +"85|WEU","7p0",2085,0.46093097160721 +"85|WEU","7p0",2090,0.510747305969561 +"86|WEU","7p0",2020,0.25634787138112 +"86|WEU","7p0",2025,0.290218957613212 +"86|WEU","7p0",2030,0.316255679399096 +"86|WEU","7p0",2035,0.36438024064247 +"86|WEU","7p0",2040,0.413168125780681 +"86|WEU","7p0",2045,0.481696965390335 +"86|WEU","7p0",2050,0.567371114660208 +"86|WEU","7p0",2055,0.691608981578849 +"86|WEU","7p0",2060,0.849684298122532 +"86|WEU","7p0",2065,1.06836940002512 +"86|WEU","7p0",2070,1.3502062872979 +"86|WEU","7p0",2075,1.72049068932144 +"86|WEU","7p0",2080,2.20778409785233 +"86|WEU","7p0",2085,2.8450848871083 +"86|WEU","7p0",2090,3.69793209368011 +"87|MEA","7p0",2020,0.36978078702699 +"87|MEA","7p0",2025,0.399952883717405 +"87|MEA","7p0",2030,0.43643517504848 +"87|MEA","7p0",2035,0.506005308681553 +"87|MEA","7p0",2040,0.585063106700006 +"87|MEA","7p0",2045,0.693883236572613 +"87|MEA","7p0",2050,0.830691423665588 +"87|MEA","7p0",2055,1.00927756178756 +"87|MEA","7p0",2060,1.24193741630278 +"87|MEA","7p0",2065,1.55212101762272 +"87|MEA","7p0",2070,1.92220922300991 +"87|MEA","7p0",2075,2.45521949953325 +"87|MEA","7p0",2080,3.14056921870456 +"87|MEA","7p0",2085,3.974903031502 +"87|MEA","7p0",2090,5.08371785801529 +"88|CHN","7p0",2020,0 +"88|CHN","7p0",2025,0.0737783270517774 +"88|CHN","7p0",2030,0.170265018073709 +"88|CHN","7p0",2035,0.34119810758056 +"88|CHN","7p0",2040,0.520389466627552 +"88|CHN","7p0",2045,0.749431988409128 +"88|CHN","7p0",2050,0.98302046725576 +"88|CHN","7p0",2055,1.22574584621343 +"88|CHN","7p0",2060,1.47686142435397 +"88|CHN","7p0",2065,1.79864733484321 +"88|CHN","7p0",2070,2.0541162979957 +"88|CHN","7p0",2075,2.32244845707578 +"88|CHN","7p0",2080,2.6622966811316 +"88|CHN","7p0",2085,2.88094423091391 +"88|CHN","7p0",2090,3.34974868916093 +"88|PAS","7p0",2020,0.0341579483954577 +"88|PAS","7p0",2025,0.0401337397838656 +"88|PAS","7p0",2030,0.0490780546692822 +"88|PAS","7p0",2035,0.0625670224906554 +"88|PAS","7p0",2040,0.0783846223320088 +"88|PAS","7p0",2045,0.0980886746683313 +"88|PAS","7p0",2050,0.122387941095119 +"88|PAS","7p0",2055,0.153716978184824 +"88|PAS","7p0",2060,0.192627141211601 +"88|PAS","7p0",2065,0.240852069104176 +"88|PAS","7p0",2070,0.302622036208547 +"88|PAS","7p0",2075,0.369638402382691 +"88|PAS","7p0",2080,0.438719142589031 +"88|PAS","7p0",2085,0.52335171953884 +"88|PAS","7p0",2090,0.6248573645088 +"88|RCPA","7p0",2020,0.0106254048161672 +"88|RCPA","7p0",2025,0.0132222931320513 +"88|RCPA","7p0",2030,0.015809074223989 +"88|RCPA","7p0",2035,0.0200601880788189 +"88|RCPA","7p0",2040,0.024500488976522 +"88|RCPA","7p0",2045,0.030297021092392 +"88|RCPA","7p0",2050,0.0380788722225105 +"88|RCPA","7p0",2055,0.0468169725427441 +"88|RCPA","7p0",2060,0.0586668521505814 +"88|RCPA","7p0",2065,0.0752559460557699 +"88|RCPA","7p0",2070,0.0925116461229384 +"88|RCPA","7p0",2075,0.114084265411005 +"88|RCPA","7p0",2080,0.139135657781399 +"88|RCPA","7p0",2085,0.164964057181476 +"88|RCPA","7p0",2090,0.202185358265192 +"8|AFR","7p0",2020,0.00213241094104509 +"8|AFR","7p0",2025,0.00233255312061524 +"8|AFR","7p0",2030,0.00325580560146357 +"8|AFR","7p0",2035,0.00540858487866946 +"8|AFR","7p0",2040,0.00921837609550078 +"8|AFR","7p0",2045,0.0166001008482638 +"8|AFR","7p0",2050,0.0299034356554054 +"8|AFR","7p0",2055,0.0614082716765451 +"8|AFR","7p0",2060,0.120052877303002 +"8|AFR","7p0",2065,0.224012421144855 +"8|AFR","7p0",2070,0.408349120300356 +"8|AFR","7p0",2075,0.705623629124954 +"8|AFR","7p0",2080,1.16587977420415 +"8|AFR","7p0",2085,1.8831831037916 +"8|AFR","7p0",2090,2.93036193552575 +"90|NAM","7p0",2020,3.07463384296512 +"90|NAM","7p0",2025,3.24406546461039 +"90|NAM","7p0",2030,3.35927798352592 +"90|NAM","7p0",2035,3.54193956940728 +"90|NAM","7p0",2040,3.67477717890573 +"90|NAM","7p0",2045,3.78501295617777 +"90|NAM","7p0",2050,3.93303266174648 +"90|NAM","7p0",2055,4.03952076048893 +"90|NAM","7p0",2060,4.18486966617116 +"90|NAM","7p0",2065,4.29377391199724 +"90|NAM","7p0",2070,4.42725686856553 +"90|NAM","7p0",2075,4.60265647404468 +"90|NAM","7p0",2080,4.75543214801306 +"90|NAM","7p0",2085,5.02493422898521 +"90|NAM","7p0",2090,5.19737238755828 +"91|PAO","7p0",2020,0.76122287074116 +"91|PAO","7p0",2025,0.773355971778559 +"91|PAO","7p0",2030,0.785458811861597 +"91|PAO","7p0",2035,0.803518982272506 +"91|PAO","7p0",2040,0.814751416211092 +"91|PAO","7p0",2045,0.833620907535962 +"91|PAO","7p0",2050,0.851404474225932 +"91|PAO","7p0",2055,0.878306717213025 +"91|PAO","7p0",2060,0.914393099299742 +"91|PAO","7p0",2065,0.949272495909644 +"91|PAO","7p0",2070,0.992756295749017 +"91|PAO","7p0",2075,1.04142564263396 +"91|PAO","7p0",2080,1.08419691711578 +"91|PAO","7p0",2085,1.12837276518535 +"91|PAO","7p0",2090,1.18437473627743 +"92|AFR","7p0",2020,0.000680112487024662 +"92|AFR","7p0",2025,0.000754127739184359 +"92|AFR","7p0",2030,0.00104634491387427 +"92|AFR","7p0",2035,0.0018005959860976 +"92|AFR","7p0",2040,0.0029262840986135 +"92|AFR","7p0",2045,0.00485437826973312 +"92|AFR","7p0",2050,0.00788927184720292 +"92|AFR","7p0",2055,0.0124213009263094 +"92|AFR","7p0",2060,0.02054522853844 +"92|AFR","7p0",2065,0.0318737222525421 +"92|AFR","7p0",2070,0.0470345655642499 +"92|AFR","7p0",2075,0.0690818675760846 +"92|AFR","7p0",2080,0.101373597191799 +"92|AFR","7p0",2085,0.144339773150266 +"92|AFR","7p0",2090,0.207577461092243 +"93|LAM","7p0",2020,0.011342301365729 +"93|LAM","7p0",2025,0.0114384307873941 +"93|LAM","7p0",2030,0.0116604338389053 +"93|LAM","7p0",2035,0.0122132507967152 +"93|LAM","7p0",2040,0.0129193310138305 +"93|LAM","7p0",2045,0.0138863678047035 +"93|LAM","7p0",2050,0.0152865819279473 +"93|LAM","7p0",2055,0.0170448077371587 +"93|LAM","7p0",2060,0.0191318125939319 +"93|LAM","7p0",2065,0.0221694786180228 +"93|LAM","7p0",2070,0.0260584528251921 +"93|LAM","7p0",2075,0.0318102841909319 +"93|LAM","7p0",2080,0.040511357750234 +"93|LAM","7p0",2085,0.0526302504435054 +"93|LAM","7p0",2090,0.0686038136445965 +"95|AFR","7p0",2020,0.0025849810587909 +"95|AFR","7p0",2025,0.0026569763971697 +"95|AFR","7p0",2030,0.00348975828848432 +"95|AFR","7p0",2035,0.00529154426558209 +"95|AFR","7p0",2040,0.00824263518539207 +"95|AFR","7p0",2045,0.0138711721385392 +"95|AFR","7p0",2050,0.023474381584869 +"95|AFR","7p0",2055,0.0427101770148746 +"95|AFR","7p0",2060,0.0763302508568289 +"95|AFR","7p0",2065,0.130120334929497 +"95|AFR","7p0",2070,0.212549957252687 +"95|AFR","7p0",2075,0.345721496357766 +"95|AFR","7p0",2080,0.542169931969413 +"95|AFR","7p0",2085,0.861795438564185 +"95|AFR","7p0",2090,1.32027595432904 +"95|MEA","7p0",2020,0.810565605270717 +"95|MEA","7p0",2025,0.805314390722966 +"95|MEA","7p0",2030,0.829784678643669 +"95|MEA","7p0",2035,0.863008327240359 +"95|MEA","7p0",2040,0.892843274946252 +"95|MEA","7p0",2045,0.939927390190134 +"95|MEA","7p0",2050,0.995186355419039 +"95|MEA","7p0",2055,1.07563834234319 +"95|MEA","7p0",2060,1.19954999536191 +"95|MEA","7p0",2065,1.38353608521124 +"95|MEA","7p0",2070,1.61055039374022 +"95|MEA","7p0",2075,2.02330304718418 +"95|MEA","7p0",2080,2.53014479063751 +"95|MEA","7p0",2085,3.17181320446841 +"95|MEA","7p0",2090,4.07956704726135 +"96|AFR","7p0",2020,0.00145775542988856 +"96|AFR","7p0",2025,0.00197943548229322 +"96|AFR","7p0",2030,0.0027150413505722 +"96|AFR","7p0",2035,0.00430505916493085 +"96|AFR","7p0",2040,0.00702936122309036 +"96|AFR","7p0",2045,0.0118439038827998 +"96|AFR","7p0",2050,0.0204190649106811 +"96|AFR","7p0",2055,0.0365619674340624 +"96|AFR","7p0",2060,0.0621045419101145 +"96|AFR","7p0",2065,0.105538961811222 +"96|AFR","7p0",2070,0.174421380459995 +"96|AFR","7p0",2075,0.266146166667258 +"96|AFR","7p0",2080,0.408060797784259 +"96|AFR","7p0",2085,0.606656646827895 +"96|AFR","7p0",2090,0.886556177383102 +"96|MEA","7p0",2020,0.0479788600478204 +"96|MEA","7p0",2025,0.0668858774355414 +"96|MEA","7p0",2030,0.0941466769239361 +"96|MEA","7p0",2035,0.147715704653955 +"96|MEA","7p0",2040,0.209624529414591 +"96|MEA","7p0",2045,0.291484975014976 +"96|MEA","7p0",2050,0.397347512087985 +"96|MEA","7p0",2055,0.541843094012688 +"96|MEA","7p0",2060,0.736847995410274 +"96|MEA","7p0",2065,0.999755246084738 +"96|MEA","7p0",2070,1.35089411631749 +"96|MEA","7p0",2075,1.81058796861417 +"96|MEA","7p0",2080,2.41215016487279 +"96|MEA","7p0",2085,3.20750000328223 +"96|MEA","7p0",2090,4.2925657373229 +"97|LAM","7p0",2020,0.150322835837072 +"97|LAM","7p0",2025,0.160718078451277 +"97|LAM","7p0",2030,0.178540938631742 +"97|LAM","7p0",2035,0.21047844082216 +"97|LAM","7p0",2040,0.247653529032093 +"97|LAM","7p0",2045,0.280984105236389 +"97|LAM","7p0",2050,0.327963026293237 +"97|LAM","7p0",2055,0.401138124838732 +"97|LAM","7p0",2060,0.463420461186781 +"97|LAM","7p0",2065,0.554447338852365 +"97|LAM","7p0",2070,0.652357000907949 +"97|LAM","7p0",2075,0.790918423887289 +"97|LAM","7p0",2080,0.936082891303256 +"97|LAM","7p0",2085,1.11805527933632 +"97|LAM","7p0",2090,1.33432273398079 +"97|NAM","7p0",2020,3.50333812068375 +"97|NAM","7p0",2025,3.74149900849625 +"97|NAM","7p0",2030,3.93568047742499 +"97|NAM","7p0",2035,4.17906879791066 +"97|NAM","7p0",2040,4.42046007158404 +"97|NAM","7p0",2045,4.5579797686785 +"97|NAM","7p0",2050,4.75799506740969 +"97|NAM","7p0",2055,5.0289880309769 +"97|NAM","7p0",2060,5.12953805497389 +"97|NAM","7p0",2065,5.38139178644307 +"97|NAM","7p0",2070,5.59713449613456 +"97|NAM","7p0",2075,5.8014731375409 +"97|NAM","7p0",2080,6.0036944598269 +"97|NAM","7p0",2085,6.23847987659499 +"97|NAM","7p0",2090,6.40487195633889 +"98|CHN","7p0",2020,1.34599447285924 +"98|CHN","7p0",2025,2.21238387854172 +"98|CHN","7p0",2030,3.31316115860957 +"98|CHN","7p0",2035,5.1588108845329 +"98|CHN","7p0",2040,7.17589196500107 +"98|CHN","7p0",2045,9.35116532359177 +"98|CHN","7p0",2050,11.7300573705908 +"98|CHN","7p0",2055,14.1311639131678 +"98|CHN","7p0",2060,17.1318997979069 +"98|CHN","7p0",2065,20.0774435467721 +"98|CHN","7p0",2070,23.3399554943367 +"98|CHN","7p0",2075,26.6727013504532 +"98|CHN","7p0",2080,30.4401638278652 +"98|CHN","7p0",2085,34.2019404079785 +"98|CHN","7p0",2090,38.2201539662811 +"98|PAS","7p0",2020,0.11205865 +"98|PAS","7p0",2025,0.147418507606424 +"98|PAS","7p0",2030,0.196886295503398 +"98|PAS","7p0",2035,0.289043686263821 +"98|PAS","7p0",2040,0.3975489684464 +"98|PAS","7p0",2045,0.527453971488281 +"98|PAS","7p0",2050,0.707665931435374 +"98|PAS","7p0",2055,0.89367489144259 +"98|PAS","7p0",2060,1.14705091706354 +"98|PAS","7p0",2065,1.42063846091604 +"98|PAS","7p0",2070,1.91142545889013 +"98|PAS","7p0",2075,2.5854887204987 +"98|PAS","7p0",2080,3.42991455350124 +"98|PAS","7p0",2085,4.67569894803522 +"98|PAS","7p0",2090,5.94565021450498 +"99|LAM","7p0",2020,0.0173717196543993 +"99|LAM","7p0",2025,0.0174022311416746 +"99|LAM","7p0",2030,0.0174628986890104 +"99|LAM","7p0",2035,0.017562763062062 +"99|LAM","7p0",2040,0.0176920968697957 +"99|LAM","7p0",2045,0.0178396091348976 +"99|LAM","7p0",2050,0.0180405993383877 +"99|LAM","7p0",2055,0.0183056769937995 +"99|LAM","7p0",2060,0.0185790791488204 +"99|LAM","7p0",2065,0.0189658061413693 +"99|LAM","7p0",2070,0.0194242441652661 +"99|LAM","7p0",2075,0.020025259407985 +"99|LAM","7p0",2080,0.020743120814743 +"99|LAM","7p0",2085,0.0215047608211372 +"99|LAM","7p0",2090,0.0223590835984915 +"9|LAM","7p0",2020,0.0124680760733801 +"9|LAM","7p0",2025,0.0124803382161854 +"9|LAM","7p0",2030,0.0125022702492213 +"9|LAM","7p0",2035,0.0125551028474557 +"9|LAM","7p0",2040,0.012628987895278 +"9|LAM","7p0",2045,0.0127460480012055 +"9|LAM","7p0",2050,0.0129329479007046 +"9|LAM","7p0",2055,0.0132137751873667 +"9|LAM","7p0",2060,0.0136240456558893 +"9|LAM","7p0",2065,0.0142431108903038 +"9|LAM","7p0",2070,0.0151569252855209 +"9|LAM","7p0",2075,0.0165241772724223 +"9|LAM","7p0",2080,0.0185160321073307 +"9|LAM","7p0",2085,0.0213654160626754 +"9|LAM","7p0",2090,0.0251713524666107 "0|EEU","no_climate",2020,0.000770369787974928 "0|EEU","no_climate",2025,0.00166487731773914 "0|EEU","no_climate",2030,0.00294688468440548 From 8bed21c2312e46f2107db7126e249770c1d53c44 Mon Sep 17 00:00:00 2001 From: Vignesh Raghunathan Date: Wed, 27 Aug 2025 11:23:45 +0200 Subject: [PATCH 17/43] Ruff changes --- .../model/water/data/infrastructure.py | 59 ++++++++----------- 1 file changed, 25 insertions(+), 34 deletions(-) diff --git a/message_ix_models/model/water/data/infrastructure.py b/message_ix_models/model/water/data/infrastructure.py index 2834546ba5..03b73f8b78 100644 --- a/message_ix_models/model/water/data/infrastructure.py +++ b/message_ix_models/model/water/data/infrastructure.py @@ -80,7 +80,7 @@ def start_creating_input_dataframe( get_vintage_and_active_years( scenario_info, rows["technical_lifetime_mid"], - same_year_only=use_same_year + same_year_only=use_same_year, ), time=sub_time, ) @@ -112,7 +112,7 @@ def start_creating_input_dataframe( get_vintage_and_active_years( scenario_info, rows["technical_lifetime_mid"], - same_year_only=use_same_year + same_year_only=use_same_year, ), node_loc=df_node["node"], time=sub_time, @@ -146,7 +146,7 @@ def start_creating_input_dataframe( get_vintage_and_active_years( scenario_info, rows["technical_lifetime_mid"], - same_year_only=use_same_year + same_year_only=use_same_year, ), node_loc=df_node["node"], time=sub_time, @@ -175,7 +175,7 @@ def start_creating_input_dataframe( get_vintage_and_active_years( scenario_info, rows["technical_lifetime_mid"], - same_year_only=use_same_year + same_year_only=use_same_year, ), node_loc=df_node["node"], time=sub_time, @@ -299,7 +299,7 @@ def add_infrastructure_techs(context: "Context") -> dict[str, pd.DataFrame]: get_vintage_and_active_years( scenario_info, rows["technical_lifetime_mid"], - same_year_only=use_same_year + same_year_only=use_same_year, ), node_loc=df_node["node"], time=sub_time, @@ -332,7 +332,7 @@ def add_infrastructure_techs(context: "Context") -> dict[str, pd.DataFrame]: get_vintage_and_active_years( scenario_info, dist_rows["technical_lifetime_mid"], - same_year_only=use_same_year_dist + same_year_only=use_same_year_dist, ), node_loc=df_node["node"], time=sub_time, @@ -364,7 +364,7 @@ def add_infrastructure_techs(context: "Context") -> dict[str, pd.DataFrame]: get_vintage_and_active_years( scenario_info, dist_rows["technical_lifetime_mid"], - same_year_only=use_same_year_dist + same_year_only=use_same_year_dist, ), node_loc=df_node["node"], time=sub_time, @@ -391,7 +391,7 @@ def add_infrastructure_techs(context: "Context") -> dict[str, pd.DataFrame]: get_vintage_and_active_years( scenario_info, dist_rows["technical_lifetime_mid"], - same_year_only=use_same_year_dist + same_year_only=use_same_year_dist, ), node_loc=df_node["node"], time=sub_time, @@ -425,7 +425,7 @@ def add_infrastructure_techs(context: "Context") -> dict[str, pd.DataFrame]: get_vintage_and_active_years( scenario_info, rows["technical_lifetime_mid"], - same_year_only=use_same_year + same_year_only=use_same_year, ), node_loc=df_node["node"], time=sub_time, @@ -492,7 +492,7 @@ def add_infrastructure_techs(context: "Context") -> dict[str, pd.DataFrame]: get_vintage_and_active_years( scenario_info, rows["technical_lifetime_mid"], - same_year_only=use_same_year + same_year_only=use_same_year, ), node_loc=df_node["node"], ), @@ -529,7 +529,7 @@ def add_infrastructure_techs(context: "Context") -> dict[str, pd.DataFrame]: get_vintage_and_active_years( scenario_info, rows["technical_lifetime_mid"], - same_year_only=use_same_year + same_year_only=use_same_year, ), node_loc=df_node["node"], time=sub_time, @@ -556,7 +556,7 @@ def add_infrastructure_techs(context: "Context") -> dict[str, pd.DataFrame]: get_vintage_and_active_years( scenario_info, rows["technical_lifetime_mid"], - same_year_only=use_same_year + same_year_only=use_same_year, ), node_loc=df_node["node"], time=sub_time, @@ -584,7 +584,7 @@ def add_infrastructure_techs(context: "Context") -> dict[str, pd.DataFrame]: get_vintage_and_active_years( scenario_info, rows["technical_lifetime_mid"], - same_year_only=use_same_year + same_year_only=use_same_year, ), node_loc=df_node["node"], time=sub_time, @@ -610,7 +610,7 @@ def add_infrastructure_techs(context: "Context") -> dict[str, pd.DataFrame]: get_vintage_and_active_years( scenario_info, rows["technical_lifetime_mid"], - same_year_only=use_same_year + same_year_only=use_same_year, ), node_loc=df_node["node"], time=sub_time, @@ -632,7 +632,7 @@ def add_infrastructure_techs(context: "Context") -> dict[str, pd.DataFrame]: get_vintage_and_active_years( scenario_info, rows["technical_lifetime_mid"], - same_year_only=use_same_year + same_year_only=use_same_year, ), node_loc=df_node["node"], time=sub_time, @@ -685,7 +685,7 @@ def prepare_input_dataframe( scenario_info, # 1 because elec commodities don't have technical lifetime 1, - same_year_only=use_same_year + same_year_only=use_same_year, ), time=sub_time, ) @@ -709,7 +709,7 @@ def prepare_input_dataframe( scenario_info, # 1 because elec commodities don't have technical lifetime 1, - same_year_only=use_same_year + same_year_only=use_same_year, ), time=sub_time, ) @@ -732,9 +732,7 @@ def prepare_input_dataframe( broadcast, # 1 because elec commodities don't have technical lifetime get_vintage_and_active_years( - scenario_info, - 1, - same_year_only=use_same_year + scenario_info, 1, same_year_only=use_same_year ), time=sub_time, ), @@ -760,9 +758,7 @@ def prepare_input_dataframe( ).pipe( broadcast, get_vintage_and_active_years( - scenario_info, - 1, - same_year_only=use_same_year + scenario_info, 1, same_year_only=use_same_year ), time=sub_time, ) @@ -927,7 +923,7 @@ def add_desalination(context: "Context") -> dict[str, pd.DataFrame]: get_vintage_and_active_years( scenario_info, rows["lifetime_mid"], - same_year_only=use_same_year + same_year_only=use_same_year, ), node_loc=df_node["node"], ), @@ -949,7 +945,7 @@ def add_desalination(context: "Context") -> dict[str, pd.DataFrame]: get_vintage_and_active_years( scenario_info, rows["lifetime_mid"], - same_year_only=use_same_year + same_year_only=use_same_year, ), node_loc=df_node["node"], time=pd.Series(sub_time), @@ -1015,9 +1011,7 @@ def add_desalination(context: "Context") -> dict[str, pd.DataFrame]: ).pipe( broadcast, get_vintage_and_active_years( - scenario_info, - rows["lifetime_mid"], - same_year_only=use_same_year + scenario_info, rows["lifetime_mid"], same_year_only=use_same_year ), time=pd.Series(sub_time), ) @@ -1051,9 +1045,7 @@ def add_desalination(context: "Context") -> dict[str, pd.DataFrame]: ).pipe( broadcast, get_vintage_and_active_years( - scenario_info, - rows["lifetime_mid"], - same_year_only=use_same_year + scenario_info, rows["lifetime_mid"], same_year_only=use_same_year ), time=pd.Series(sub_time), ) @@ -1087,7 +1079,7 @@ def add_desalination(context: "Context") -> dict[str, pd.DataFrame]: get_vintage_and_active_years( scenario_info, rows["lifetime_mid"], - same_year_only=use_same_year + same_year_only=use_same_year, ), node_loc=df_node["node"], time=pd.Series(sub_time), @@ -1098,7 +1090,6 @@ def add_desalination(context: "Context") -> dict[str, pd.DataFrame]: ] ) - inp_df.dropna(inplace=True) results["input"] = inp_df @@ -1121,7 +1112,7 @@ def add_desalination(context: "Context") -> dict[str, pd.DataFrame]: get_vintage_and_active_years( scenario_info, rows["lifetime_mid"], - same_year_only=use_same_year + same_year_only=use_same_year, ), node_loc=df_node["node"], time=pd.Series(sub_time), From ec945d0b1953ea0bb19b35117c42d864a0e45703 Mon Sep 17 00:00:00 2001 From: Vignesh Raghunathan Date: Wed, 27 Aug 2025 15:47:09 +0200 Subject: [PATCH 18/43] Set hist to 2025 Unreasonable expectation for first model year here. --- message_ix_models/model/water/data/infrastructure.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/message_ix_models/model/water/data/infrastructure.py b/message_ix_models/model/water/data/infrastructure.py index 03b73f8b78..a66728f7f6 100644 --- a/message_ix_models/model/water/data/infrastructure.py +++ b/message_ix_models/model/water/data/infrastructure.py @@ -1126,7 +1126,7 @@ def add_desalination(context: "Context") -> dict[str, pd.DataFrame]: results["output"] = out_df # putting a lower bound on desalination tecs based on hist capacities - df_bound = df_hist[df_hist["year"] == firstyear] + df_bound = df_hist[df_hist["year"] == 2025] # firstyear dataabsent bound_lo = make_df( "bound_activity_lo", node_loc="B" + df_bound["BCU_name"], From b0151078f22578003ff21c8da193ff62c22badee Mon Sep 17 00:00:00 2001 From: Vignesh Raghunathan Date: Thu, 28 Aug 2025 14:10:58 +0200 Subject: [PATCH 19/43] Add soft constraint relaxation - desal act bound lo causes infeasibilties. --- .../model/water/data/infrastructure.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/message_ix_models/model/water/data/infrastructure.py b/message_ix_models/model/water/data/infrastructure.py index a66728f7f6..ba7db31668 100644 --- a/message_ix_models/model/water/data/infrastructure.py +++ b/message_ix_models/model/water/data/infrastructure.py @@ -1146,6 +1146,23 @@ def add_desalination(context: "Context") -> dict[str, pd.DataFrame]: bound_lo["value"] = bound_lo["value"] / 5 results["bound_activity_lo"] = bound_lo + + # Add soft constraints for desalination bound_activity_lo + # Parameters for soft constraints + relaxation_factor = 0.5 # Allow 50% relaxation of the original bounds + penalty_multiplier = 1.0 # 100% of levelized cost as penalty for violations + + # Create soft_activity_lo parameter using the same bound_lo data + soft_lo = bound_lo.copy() + soft_lo["value"] = relaxation_factor + soft_lo["unit"] = "-" + results["soft_activity_lo"] = soft_lo + + # Create penalty cost parameter + penalty_lo = bound_lo.copy() + penalty_lo["value"] = penalty_multiplier + penalty_lo["unit"] = "-" + results["level_cost_activity_soft_lo"] = penalty_lo # Remove duplicates from all DataFrames in results for key, df in results.items(): From 1449fff4e66d404aaa9fa858c4138fbeec67bd62 Mon Sep 17 00:00:00 2001 From: Vignesh Raghunathan Date: Thu, 28 Aug 2025 14:11:27 +0200 Subject: [PATCH 20/43] Lower fossil_gw elec inp cost --- message_ix_models/model/water/data/water_supply.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/message_ix_models/model/water/data/water_supply.py b/message_ix_models/model/water/data/water_supply.py index 974cbbf770..5ee6a2364a 100644 --- a/message_ix_models/model/water/data/water_supply.py +++ b/message_ix_models/model/water/data/water_supply.py @@ -454,8 +454,8 @@ def add_water_supply(context: "Context") -> dict[str, pd.DataFrame]: make_df( "input", technology="extract_gw_fossil", - value=((df_gwt["GW_per_km3_per_year"] + 0.043464579) * 50) - * GWa_KM3_TO_GWa_MCM, # twice as much normal gw + value=((df_gwt["GW_per_km3_per_year"] + 0.043464579) * 5) + * GWa_KM3_TO_GWa_MCM, # reduced from 50 to 5 unit="GWa/MCM", level="final", commodity="electr", From 6b09a04214f67898ea837b06910fc84a7feb8045 Mon Sep 17 00:00:00 2001 From: Vignesh Raghunathan Date: Thu, 28 Aug 2025 14:50:22 +0200 Subject: [PATCH 21/43] Make TL filtering more efficient Harcoded heuristic for kinkyear. --- message_ix_models/model/water/utils.py | 38 +++++++++++++++++++++----- 1 file changed, 31 insertions(+), 7 deletions(-) diff --git a/message_ix_models/model/water/utils.py b/message_ix_models/model/water/utils.py index 5c3a0b477f..a33c18ce73 100644 --- a/message_ix_models/model/water/utils.py +++ b/message_ix_models/model/water/utils.py @@ -179,20 +179,44 @@ def get_vintage_and_active_years( same_year_mask = yv_ya["year_vtg"] == yv_ya["year_act"] return yv_ya[same_year_mask].reset_index(drop=True) - # If no technical lifetime specified or is nan, return all combinations + # If no technical lifetime specified or is nan, default to same year if technical_lifetime is None or pd.isna(technical_lifetime): warn( - """no technical_lifetime provided, - using all year vintage year active combinations""", + "no technical_lifetime provided, defaulting to same year", UserWarning, ) - return yv_ya - # Apply simple lifetime logic: year_act - year_vtg <= technical_lifetime + same_year_mask = yv_ya["year_vtg"] == yv_ya["year_act"] + return yv_ya[same_year_mask].reset_index(drop=True) + # Memory optimization: use same-year logic for short-lived technologies + # to reduce unused equations. Time steps are 5-year intervals pre-2060, + # 10-year intervals post-2060. Short lifetimes don't benefit from advance construction. + kink_year = 2060 + + if (technical_lifetime <= 5) or (technical_lifetime <= 10 and (yv_ya["year_act"] >= kink_year).any()): + # Pre-2060: use same-year if lifetime <= 5 + # Post-2060: use same-year if lifetime <= 10 + if technical_lifetime <= 5: + # Same-year for entire horizon + same_year_mask = yv_ya["year_vtg"] == yv_ya["year_act"] + return yv_ya[same_year_mask].reset_index(drop=True) + else: + # Same-year only for post-2060, normal logic for pre-2060 + pre_kink = yv_ya[yv_ya["year_act"] < kink_year] + post_kink = yv_ya[yv_ya["year_act"] >= kink_year] + + # Pre-2060: normal lifetime filtering + pre_kink_filtered = pre_kink[(pre_kink["year_act"] - pre_kink["year_vtg"]) <= technical_lifetime] + + # Post-2060: same-year only + post_kink_same_year = post_kink[post_kink["year_vtg"] == post_kink["year_act"]] + + result = pd.concat([pre_kink_filtered, post_kink_same_year], ignore_index=True) + return result.reset_index(drop=True) + + # Apply simple lifetime logic: year_act - year_vtg <= technical_lifetime condition_values = yv_ya["year_act"] - yv_ya["year_vtg"] - valid_mask = condition_values <= technical_lifetime - result = yv_ya[valid_mask].reset_index(drop=True) return result From d78c3fb3ac5537f69d17df82eaa6f304fbbc1583 Mon Sep 17 00:00:00 2001 From: Vignesh Raghunathan Date: Fri, 29 Aug 2025 14:51:02 +0200 Subject: [PATCH 22/43] Increase bound_act_lo relaxation --- message_ix_models/model/water/data/infrastructure.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/message_ix_models/model/water/data/infrastructure.py b/message_ix_models/model/water/data/infrastructure.py index ba7db31668..378d78d3e0 100644 --- a/message_ix_models/model/water/data/infrastructure.py +++ b/message_ix_models/model/water/data/infrastructure.py @@ -1146,18 +1146,18 @@ def add_desalination(context: "Context") -> dict[str, pd.DataFrame]: bound_lo["value"] = bound_lo["value"] / 5 results["bound_activity_lo"] = bound_lo - + # Add soft constraints for desalination bound_activity_lo # Parameters for soft constraints - relaxation_factor = 0.5 # Allow 50% relaxation of the original bounds + relaxation_factor = 10 # Effectively allow complete relaxation at penalty penalty_multiplier = 1.0 # 100% of levelized cost as penalty for violations - + # Create soft_activity_lo parameter using the same bound_lo data soft_lo = bound_lo.copy() soft_lo["value"] = relaxation_factor soft_lo["unit"] = "-" results["soft_activity_lo"] = soft_lo - + # Create penalty cost parameter penalty_lo = bound_lo.copy() penalty_lo["value"] = penalty_multiplier From ac28914071db52b4229aec14249305c05f2bfe95 Mon Sep 17 00:00:00 2001 From: Vignesh Raghunathan Date: Fri, 29 Aug 2025 15:29:05 +0200 Subject: [PATCH 23/43] Clip act bound to cap limit --- .../model/water/data/infrastructure.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/message_ix_models/model/water/data/infrastructure.py b/message_ix_models/model/water/data/infrastructure.py index 378d78d3e0..a8a1a1e456 100644 --- a/message_ix_models/model/water/data/infrastructure.py +++ b/message_ix_models/model/water/data/infrastructure.py @@ -4,6 +4,7 @@ from collections import defaultdict from typing import Any +import numpy as np import pandas as pd from message_ix import make_df @@ -1145,6 +1146,18 @@ def add_desalination(context: "Context") -> dict[str, pd.DataFrame]: # 5 years and model needs per year bound_lo["value"] = bound_lo["value"] / 5 + # Clip activity bounds to not exceed capacity bounds + bound_lo = bound_lo.merge( + bound_up[["node_loc", "year_act", "value"]], + on=["node_loc", "year_act"], + how="left", + suffixes=("", "_cap"), + ) + bound_lo["value"] = np.minimum( + bound_lo["value"], bound_lo["value_cap"].fillna(np.inf) + ) + bound_lo = bound_lo.drop("value_cap", axis=1) + results["bound_activity_lo"] = bound_lo # Add soft constraints for desalination bound_activity_lo From 3b4235f4647e536a383ad1d6b1f43292eb3c9c14 Mon Sep 17 00:00:00 2001 From: Vignesh Raghunathan Date: Mon, 1 Sep 2025 13:06:06 +0200 Subject: [PATCH 24/43] Comment out soft constraints --- .../model/water/data/infrastructure.py | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/message_ix_models/model/water/data/infrastructure.py b/message_ix_models/model/water/data/infrastructure.py index a8a1a1e456..9724be6d1e 100644 --- a/message_ix_models/model/water/data/infrastructure.py +++ b/message_ix_models/model/water/data/infrastructure.py @@ -1160,23 +1160,23 @@ def add_desalination(context: "Context") -> dict[str, pd.DataFrame]: results["bound_activity_lo"] = bound_lo - # Add soft constraints for desalination bound_activity_lo - # Parameters for soft constraints - relaxation_factor = 10 # Effectively allow complete relaxation at penalty - penalty_multiplier = 1.0 # 100% of levelized cost as penalty for violations - - # Create soft_activity_lo parameter using the same bound_lo data - soft_lo = bound_lo.copy() - soft_lo["value"] = relaxation_factor - soft_lo["unit"] = "-" - results["soft_activity_lo"] = soft_lo - - # Create penalty cost parameter - penalty_lo = bound_lo.copy() - penalty_lo["value"] = penalty_multiplier - penalty_lo["unit"] = "-" - results["level_cost_activity_soft_lo"] = penalty_lo - + # # Add soft constraints for desalination bound_activity_lo + # # Parameters for soft constraints + # relaxation_factor = 10 # Effectively allow complete relaxation at penalty + # penalty_multiplier = 1.0 # 100% of levelized cost as penalty for violations + # + # # Create soft_activity_lo parameter using the same bound_lo data + # soft_lo = bound_lo.copy() + # soft_lo["value"] = relaxation_factor + # soft_lo["unit"] = "-" + # results["soft_activity_lo"] = soft_lo + # + # # Create penalty cost parameter + # penalty_lo = bound_lo.copy() + # penalty_lo["value"] = penalty_multiplier + # penalty_lo["unit"] = "-" + # results["level_cost_activity_soft_lo"] = penalty_lo + # # Remove duplicates from all DataFrames in results for key, df in results.items(): results[key] = df.dropna().drop_duplicates().reset_index(drop=True) From 934304009b3691efcb345904ac417cc737b27f60 Mon Sep 17 00:00:00 2001 From: Vignesh Raghunathan Date: Thu, 4 Sep 2025 10:26:41 +0200 Subject: [PATCH 25/43] Set ot_saline growht new cap growth rate 0 --- message_ix_models/model/water/data/water_for_ppl.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/message_ix_models/model/water/data/water_for_ppl.py b/message_ix_models/model/water/data/water_for_ppl.py index 39aff398b6..27ce07641d 100644 --- a/message_ix_models/model/water/data/water_for_ppl.py +++ b/message_ix_models/model/water/data/water_for_ppl.py @@ -965,6 +965,12 @@ def cool_tech( else df_param ) + # Set growth_new_capacity_up to 0 for __ot_saline technologies + if param_name == "growth_new_capacity_up": + df_param_share.loc[ + df_param_share["technology"].str.endswith("__ot_saline"), "value" + ] = 0 + print(f"setting growth up new cap 0 for {df_param_share['technology']}") results[param_name] = pd.concat( [results.get(param_name, pd.DataFrame()), df_param_share], ignore_index=True ) From bebf89780249d126db1908684c74e0d2f3cda7a1 Mon Sep 17 00:00:00 2001 From: Vignesh Raghunathan Date: Mon, 8 Sep 2025 11:37:17 +0200 Subject: [PATCH 26/43] Swap basin to reg inputs - Input level at water_avail_basin - Input commodity surfacewater_basin - output level water_supply - output commodity freshwater --- message_ix_models/model/water/data/water_supply.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/message_ix_models/model/water/data/water_supply.py b/message_ix_models/model/water/data/water_supply.py index 5ee6a2364a..fdd819ca86 100644 --- a/message_ix_models/model/water/data/water_supply.py +++ b/message_ix_models/model/water/data/water_supply.py @@ -1,10 +1,10 @@ """Prepare data for water use for cooling & energy technologies.""" +from typing import Tuple import numpy as np -import pandas as pd from message_ix import make_df -from message_ix_models import Context, ScenarioInfo + from message_ix_models.model.water.data.demands import read_water_availability from message_ix_models.model.water.utils import ( ANNUAL_CAPACITY_FACTOR, @@ -316,8 +316,8 @@ def add_water_supply(context: "Context") -> dict[str, pd.DataFrame]: technology="basin_to_reg", value=1, unit="-", - level="water_supply_basin", - commodity="freshwater_basin", + level="water_avail_basin", + commodity="surfacewater_basin", mode=df_node["mode"], node_origin=df_node["node"], node_loc=df_node["region"], @@ -612,7 +612,7 @@ def add_water_supply(context: "Context") -> dict[str, pd.DataFrame]: value=1, unit="-", level="water_supply", - commodity="freshwater", + commodity="surfacewater", time_dest="year", node_loc=df_node["region"], node_dest=df_node["region"], From 46cf122dd9a1f944977ba4aedd799724b43ee005 Mon Sep 17 00:00:00 2001 From: Vignesh Raghunathan Date: Thu, 4 Sep 2025 10:26:41 +0200 Subject: [PATCH 27/43] Set ot_saline growht new cap growth rate 0 From f27309b3e984387fecaab899b88ef45aa186f019 Mon Sep 17 00:00:00 2001 From: Vignesh Raghunathan Date: Mon, 8 Sep 2025 11:37:17 +0200 Subject: [PATCH 28/43] Swap basin to reg inputs - Input level at water_avail_basin - Input commodity surfacewater_basin - output level water_supply - output commodity freshwater From 14fff78aa36a043f42db904fb55f04fac759a11d Mon Sep 17 00:00:00 2001 From: Vignesh Raghunathan Date: Mon, 8 Sep 2025 11:43:02 +0200 Subject: [PATCH 29/43] Add reg_to_basin return tech consolidate return logic --- message_ix_models/data/water/set.yaml | 1 + message_ix_models/data/water/technology.yaml | 7 ++ .../model/water/data/water_for_ppl.py | 85 +++++++++++++++++-- 3 files changed, 86 insertions(+), 7 deletions(-) diff --git a/message_ix_models/data/water/set.yaml b/message_ix_models/data/water/set.yaml index 40cda77f24..eacd61ad91 100644 --- a/message_ix_models/data/water/set.yaml +++ b/message_ix_models/data/water/set.yaml @@ -85,6 +85,7 @@ cooling: - cl_fresh - air - ot_saline + - water_return level: require: diff --git a/message_ix_models/data/water/technology.yaml b/message_ix_models/data/water/technology.yaml index 005f2c629d..13764bccb0 100644 --- a/message_ix_models/data/water/technology.yaml +++ b/message_ix_models/data/water/technology.yaml @@ -1101,6 +1101,13 @@ nexus: input: { commodity: freshwater_supply } + reg_to_basin: + description: >- + technology for distributing water return flows from fresh cooling technologies + back to surface water basins based on basin availability shares + + input: { commodity: water_return } + ueff1: description: >- low urban efficiency diff --git a/message_ix_models/model/water/data/water_for_ppl.py b/message_ix_models/model/water/data/water_for_ppl.py index 27ce07641d..7a09ba9549 100644 --- a/message_ix_models/model/water/data/water_for_ppl.py +++ b/message_ix_models/model/water/data/water_for_ppl.py @@ -643,11 +643,82 @@ def cool_tech( out_t.drop(columns={"share"}, inplace=True) out = pd.concat([out, out_t]) - out = out.dropna(subset=["value"]) - out.reset_index(drop=True, inplace=True) + # Add water return flows output from fresh cooling technologies to reg_to_basin + # Fresh cooling technologies output their return flows to reg_to_basin technology + out_return = make_df( + "output", + node_loc=icmse_df["node_loc"], + technology=icmse_df["technology_name"], + year_vtg=icmse_df["year_vtg"], + year_act=icmse_df["year_act"], + mode=icmse_df["mode"], + node_dest=icmse_df["node_origin"], + commodity="water_return", + level="water_supply", + time="year", + time_dest="year", + value=icmse_df["value_return"], + unit="MCM/GWa", + ) + + # Combine all outputs (share constraints + return flows) + out = pd.concat([out, out_return]) + # in any case save out into results results["output"] = out + # Create reg_to_basin technology for distributing return flows to basins + if context.nexus_set == "nexus": + # Get basin-region mapping + df_sw = map_basin_region_wat(context) + df_sw.drop(columns={"mode", "date", "MSGREG"}, inplace=True) + df_sw.rename( + columns={"region": "node_dest", "time": "time_dest", "year": "year_act"}, + inplace=True, + ) + df_sw["time_dest"] = df_sw["time_dest"].astype(str) + + # reg_to_basin technology inputs (receives return flows) + reg_to_basin_input = make_df( + "input", + technology="reg_to_basin", + node_loc=node_region, + commodity="water_return", + level="water_supply", + time="year", + time_origin="year", + value=1, + unit="MCM/GWa", + mode="M1", + ).pipe(broadcast, year_vtg=year_wat, year_act=year_wat) + + # reg_to_basin technology outputs (distributes to basins) + reg_to_basin_output = ( + make_df( + "output", + technology="reg_to_basin", + node_loc=node_region, + commodity="surfacewater_basin", + level="water_avail_basin", + time="year", + time_dest="year", + value=1, + unit="MCM/GWa", + mode="M1", + ) + .pipe(broadcast, year_vtg=year_wat, year_act=year_wat) + .pipe(broadcast, node_dest=df_sw["node_dest"].unique()) + .merge(df_sw.drop_duplicates(["node_dest"]), on="node_dest", how="left") + ) + + # Apply basin availability shares to reg_to_basin outputs + reg_to_basin_output["value"] = reg_to_basin_output["value"] * reg_to_basin_output["share"] + reg_to_basin_output = reg_to_basin_output.drop(columns=["share"]).dropna(subset=["value"]) + + # Add reg_to_basin parameters to results + results["input"] = pd.concat([results["input"], reg_to_basin_input]) + results["output"] = pd.concat([results["output"], reg_to_basin_output]) + # costs and historical parameters path1 = package_data_path("water", "ppl_cooling_tech", FILE1) cost = pd.read_csv(path1) @@ -966,11 +1037,11 @@ def cool_tech( ) # Set growth_new_capacity_up to 0 for __ot_saline technologies - if param_name == "growth_new_capacity_up": - df_param_share.loc[ - df_param_share["technology"].str.endswith("__ot_saline"), "value" - ] = 0 - print(f"setting growth up new cap 0 for {df_param_share['technology']}") + # if param_name == "growth_new_capacity_up": + # df_param_share.loc[ + # df_param_share["technology"].str.endswith("__ot_saline"), "value" + # ] = 0 + # print(f"setting growth up new cap 0 for {df_param_share['technology']}") results[param_name] = pd.concat( [results.get(param_name, pd.DataFrame()), df_param_share], ignore_index=True ) From b72e43bd97edb7d5f3d4ebf351ada03684bbb610 Mon Sep 17 00:00:00 2001 From: Vignesh Raghunathan Date: Mon, 8 Sep 2025 14:35:38 +0200 Subject: [PATCH 30/43] Update vtg filtering --- message_ix_models/data/water/set.yaml | 1 + .../model/water/data/water_for_ppl.py | 120 +++++++++++++----- .../model/water/data/water_supply.py | 4 +- .../model/water/data/test_water_for_ppl.py | 29 +++-- 4 files changed, 110 insertions(+), 44 deletions(-) diff --git a/message_ix_models/data/water/set.yaml b/message_ix_models/data/water/set.yaml index eacd61ad91..ac725710e6 100644 --- a/message_ix_models/data/water/set.yaml +++ b/message_ix_models/data/water/set.yaml @@ -1257,6 +1257,7 @@ nexus: - urban_disconnected - rural_mw - rural_disconnected + - surfacewater level: add: diff --git a/message_ix_models/model/water/data/water_for_ppl.py b/message_ix_models/model/water/data/water_for_ppl.py index 7a09ba9549..5a8961c110 100644 --- a/message_ix_models/model/water/data/water_for_ppl.py +++ b/message_ix_models/model/water/data/water_for_ppl.py @@ -10,7 +10,10 @@ from message_ix_models import Context from message_ix_models.model.water.data.water_supply import map_basin_region_wat -from message_ix_models.model.water.utils import m3_GJ_TO_MCM_GWa +from message_ix_models.model.water.utils import ( + m3_GJ_TO_MCM_GWa, + get_vintage_and_active_years, +) from message_ix_models.util import ( broadcast, make_matched_dfs, @@ -438,6 +441,18 @@ def cool_tech( # Convert year values into integers to be compatibel for model input_cool.year_vtg = input_cool.year_vtg.astype(int) input_cool.year_act = input_cool.year_act.astype(int) + + # Fix invalid year combinations (year_act < year_vtg) using proper vintage-active combinations + year_combinations = get_vintage_and_active_years(info, technical_lifetime=30, same_year_only=False) + + # Create a mapping of valid year combinations + valid_years = set(zip(year_combinations['year_vtg'], year_combinations['year_act'])) + + # Filter input_cool to only include valid year combinations + input_cool_valid_mask = input_cool.apply( + lambda row: (int(row['year_vtg']), int(row['year_act'])) in valid_years, axis=1 + ) + input_cool = input_cool[input_cool_valid_mask] # Drops extra technologies from the data. backwards compatibility input_cool = input_cool[ (input_cool["level"] != "water_supply") & (input_cool["level"] != "cooling") @@ -533,7 +548,7 @@ def cool_tech( year_act=icmse_df["year_act"], mode=icmse_df["mode"], node_origin=icmse_df["node_origin"], - commodity="freshwater", + commodity="surfacewater", level="water_supply", time="year", time_origin="year", @@ -660,10 +675,10 @@ def cool_tech( value=icmse_df["value_return"], unit="MCM/GWa", ) - + # Combine all outputs (share constraints + return flows) out = pd.concat([out, out_return]) - + # in any case save out into results results["output"] = out @@ -677,7 +692,12 @@ def cool_tech( inplace=True, ) df_sw["time_dest"] = df_sw["time_dest"].astype(str) - + + # Use get_vintage_and_active_years() with tl=10 and same_year_only=True + year_combinations = get_vintage_and_active_years( + info, technical_lifetime=1, same_year_only=True + ) + # reg_to_basin technology inputs (receives return flows) reg_to_basin_input = make_df( "input", @@ -687,34 +707,63 @@ def cool_tech( level="water_supply", time="year", time_origin="year", + node_origin=node_region, value=1, unit="MCM/GWa", mode="M1", - ).pipe(broadcast, year_vtg=year_wat, year_act=year_wat) - + ).pipe(broadcast, year_combinations) # reg_to_basin technology outputs (distributes to basins) + # Create base output dataframe + reg_to_basin_output_list = [] + + for region in node_region: + # Extract region code from node_loc (e.g., "R12_AFR" -> "AFR") + region_code = region.split("_")[-1] + + # Filter df_sw to only basins that match this region code + matching_basins = df_sw[ + df_sw["node_dest"].str.contains(region_code, na=False) + ] + + if not matching_basins.empty: + region_output = ( + make_df( + "output", + technology="reg_to_basin", + node_loc=region, + commodity="surfacewater_basin", + level="water_avail_basin", + time="year", + time_dest="year", + value=1, + unit="MCM/GWa", + mode="M1", + ) + .pipe(broadcast, year_combinations) + .pipe(broadcast, node_dest=matching_basins["node_dest"].unique()) + .merge( + matching_basins.drop_duplicates(["node_dest"])[["node_dest", "share"]], + on="node_dest", + how="left", + ) + ) + reg_to_basin_output_list.append(region_output) + + # Combine all region outputs reg_to_basin_output = ( - make_df( - "output", - technology="reg_to_basin", - node_loc=node_region, - commodity="surfacewater_basin", - level="water_avail_basin", - time="year", - time_dest="year", - value=1, - unit="MCM/GWa", - mode="M1", - ) - .pipe(broadcast, year_vtg=year_wat, year_act=year_wat) - .pipe(broadcast, node_dest=df_sw["node_dest"].unique()) - .merge(df_sw.drop_duplicates(["node_dest"]), on="node_dest", how="left") + pd.concat(reg_to_basin_output_list, ignore_index=True) + if reg_to_basin_output_list + else pd.DataFrame() ) - + # Apply basin availability shares to reg_to_basin outputs - reg_to_basin_output["value"] = reg_to_basin_output["value"] * reg_to_basin_output["share"] - reg_to_basin_output = reg_to_basin_output.drop(columns=["share"]).dropna(subset=["value"]) - + reg_to_basin_output["value"] = ( + reg_to_basin_output["value"] * reg_to_basin_output["share"] + ) + reg_to_basin_output = reg_to_basin_output.drop(columns=["share"]).dropna( + subset=["value"] + ) + # Add reg_to_basin parameters to results results["input"] = pd.concat([results["input"], reg_to_basin_input]) results["output"] = pd.concat([results["output"], reg_to_basin_output]) @@ -1037,11 +1086,16 @@ def cool_tech( ) # Set growth_new_capacity_up to 0 for __ot_saline technologies - # if param_name == "growth_new_capacity_up": - # df_param_share.loc[ - # df_param_share["technology"].str.endswith("__ot_saline"), "value" - # ] = 0 - # print(f"setting growth up new cap 0 for {df_param_share['technology']}") + if param_name == "growth_new_capacity_up": + df_param_share.loc[ + df_param_share["technology"].str.endswith("__ot_saline"), "value" + ] = 0 + print(f"setting growth up new cap 0 for {df_param_share['technology']}") + if param_name == "growth_activity_up": + df_param_share.loc[ + df_param_share["technology"].str.endswith("__ot_saline"), "value" + ] = 0 + print(f"setting growth up act 0 for {df_param_share['technology']}") results[param_name] = pd.concat( [results.get(param_name, pd.DataFrame()), df_param_share], ignore_index=True ) @@ -1121,14 +1175,14 @@ def non_cooling_tec(context: "Context", scenario=None) -> dict[str, pd.DataFrame # Input dataframe for non cooling technologies # only water withdrawals are being taken - # Only freshwater supply is assumed for simplicity + # Dedicated freshwater is assumed for simplicity inp_n_cool = make_df( "input", technology=n_cool_df_merge["technology"], value=n_cool_df_merge["value_y"], unit="MCM/GWa", level="water_supply", - commodity="freshwater", + commodity="surfacewater", time_origin="year", mode="M1", time="year", diff --git a/message_ix_models/model/water/data/water_supply.py b/message_ix_models/model/water/data/water_supply.py index fdd819ca86..7c8c6f15b3 100644 --- a/message_ix_models/model/water/data/water_supply.py +++ b/message_ix_models/model/water/data/water_supply.py @@ -1,10 +1,9 @@ """Prepare data for water use for cooling & energy technologies.""" -from typing import Tuple import numpy as np +import pandas as pd from message_ix import make_df - from message_ix_models.model.water.data.demands import read_water_availability from message_ix_models.model.water.utils import ( ANNUAL_CAPACITY_FACTOR, @@ -19,6 +18,7 @@ same_node, same_time, ) +from message_ix_models import Context, ScenarioInfo def map_basin_region_wat(context: "Context") -> pd.DataFrame: diff --git a/message_ix_models/tests/model/water/data/test_water_for_ppl.py b/message_ix_models/tests/model/water/data/test_water_for_ppl.py index 62124624a8..c8f0290aac 100644 --- a/message_ix_models/tests/model/water/data/test_water_for_ppl.py +++ b/message_ix_models/tests/model/water/data/test_water_for_ppl.py @@ -16,7 +16,7 @@ @pytest.mark.usefixtures("ssp_user_data") -@pytest.mark.parametrize("RCP", ["no_climate", "6p0"]) +@pytest.mark.parametrize("RCP", ["no_climate", "7p0"]) def test_cool_tec(request, test_context, RCP): mp = test_context.get_platform() scenario_info = { @@ -28,7 +28,7 @@ def test_cool_tec(request, test_context, RCP): s = Scenario(**scenario_info) s.add_horizon(year=[2020, 2030, 2040]) s.add_set("technology", ["gad_cc", "coal_ppl"]) - s.add_set("node", ["R11_CPA"]) + s.add_set("node", ["R12_CPA"]) s.add_set("year", [2020, 2030, 2040]) s.add_set("mode", ["M1", "M2"]) s.add_set("commodity", ["electricity", "gas"]) @@ -38,12 +38,12 @@ def test_cool_tec(request, test_context, RCP): # make a df for input df_add = pd.DataFrame( { - "node_loc": ["R11_CPA"], + "node_loc": ["R12_CPA"], "technology": ["coal_ppl"], "year_vtg": [2020], "year_act": [2020], "mode": ["M1"], - "node_origin": ["R11_CPA"], + "node_origin": ["R12_CPA"], "commodity": ["electricity"], "level": ["secondary"], "time": "year", @@ -55,7 +55,7 @@ def test_cool_tec(request, test_context, RCP): # make a df for historical activity df_ha = pd.DataFrame( { - "node_loc": ["R11_CPA"], + "node_loc": ["R12_CPA"], "technology": ["coal_ppl"], "year_act": [2020], "mode": ["M1"], @@ -66,7 +66,7 @@ def test_cool_tec(request, test_context, RCP): ) df_hnc = pd.DataFrame( { - "node_loc": ["R11_CPA"], + "node_loc": ["R12_CPA"], "technology": ["coal_ppl"], "year_vtg": [2020], "value": [1], @@ -91,7 +91,7 @@ def test_cool_tec(request, test_context, RCP): test_context.set_scenario(s) test_context["water build info"] = ScenarioInfo(scenario_obj=s) test_context.type_reg = "global" - test_context.regions = "R11" + test_context.regions = "R12" test_context.time = "year" test_context.nexus_set = "nexus" # TODO add @@ -101,6 +101,15 @@ def test_cool_tec(request, test_context, RCP): ssp="SSP2", ) + # Set up valid_basins for water_for_ppl functions + # Read all basins from the basin delineation file to avoid filtering + from message_ix_models.util import package_data_path + + basin_file = f"basins_by_region_simpl_{test_context.regions}.csv" + basin_path = package_data_path("water", "delineation", basin_file) + df_basins = pd.read_csv(basin_path) + test_context.valid_basins = set(df_basins["BCU_name"].astype(str)) + # TODO: only leaving this in so you can see which data you might want to assert to # be in the result. Please remove after adapting the assertions below: # Mock the DataFrame read from CSV @@ -123,7 +132,8 @@ def test_cool_tec(request, test_context, RCP): # Assert the results assert isinstance(result, dict) assert "input" in result - + result["input"].to_csv("input_result.csv", index=False) + result["output"].to_csv("output_result.csv", index=False) # Check for NaN values in input DataFrame assert not result["input"]["value"].isna().any(), ( "Input DataFrame contains NaN values" @@ -139,6 +149,7 @@ def test_cool_tec(request, test_context, RCP): f"Output DataFrame contains time values: {output_time_values}. " ) input_duplicates = result["input"].duplicated().sum() + print(result["input"].duplicated()) assert input_duplicates == 0, ( f"Input DataFrame contains {input_duplicates} duplicate rows" ) @@ -288,7 +299,7 @@ def test_apply_act_cap_multiplier( ) -@pytest.mark.parametrize("SSP, regions", [("SSP2", "R11"), ("LED", "R12")]) +@pytest.mark.parametrize("SSP, regions", [("SSP2", "R12"), ("LED", "R12")]) def test_cooling_shares_SSP_from_yaml(request, test_context, SSP, regions): test_context.model.regions = regions scenario = testing.bare_res(request, test_context) From 3a4d4c2831a9876a7daac065b33c7afec46c263e Mon Sep 17 00:00:00 2001 From: Vignesh Raghunathan Date: Mon, 8 Sep 2025 15:30:03 +0200 Subject: [PATCH 31/43] Add second basin_to_reg for irrigation --- message_ix_models/data/water/technology.yaml | 6 ++ .../model/water/data/water_supply.py | 102 ++++++++++++++++-- .../model/water/data/test_water_supply.py | 36 ++++++- 3 files changed, 128 insertions(+), 16 deletions(-) diff --git a/message_ix_models/data/water/technology.yaml b/message_ix_models/data/water/technology.yaml index 13764bccb0..25c7b64ea2 100644 --- a/message_ix_models/data/water/technology.yaml +++ b/message_ix_models/data/water/technology.yaml @@ -1101,6 +1101,12 @@ nexus: input: { commodity: freshwater_supply } + basin_to_reg_all: + description: >- + dummy technology to map freshwater basin supply to regional water supply for irrigation + + input: { commodity: freshwater_supply } + reg_to_basin: description: >- technology for distributing water return flows from fresh cooling technologies diff --git a/message_ix_models/model/water/data/water_supply.py b/message_ix_models/model/water/data/water_supply.py index 7c8c6f15b3..2df6e015d0 100644 --- a/message_ix_models/model/water/data/water_supply.py +++ b/message_ix_models/model/water/data/water_supply.py @@ -4,6 +4,7 @@ import pandas as pd from message_ix import make_df +from message_ix_models import Context, ScenarioInfo from message_ix_models.model.water.data.demands import read_water_availability from message_ix_models.model.water.utils import ( ANNUAL_CAPACITY_FACTOR, @@ -18,7 +19,6 @@ same_node, same_time, ) -from message_ix_models import Context, ScenarioInfo def map_basin_region_wat(context: "Context") -> pd.DataFrame: @@ -267,7 +267,7 @@ def add_water_supply(context: "Context") -> dict[str, pd.DataFrame]: "input", technology="return_flow", value=1, - unit="-", + unit="MCM", level="water_avail_basin", commodity="surfacewater_basin", mode="M1", @@ -290,7 +290,7 @@ def add_water_supply(context: "Context") -> dict[str, pd.DataFrame]: "input", technology="gw_recharge", value=1, - unit="-", + unit="MCM", level="water_avail_basin", commodity="groundwater_basin", mode="M1", @@ -315,7 +315,7 @@ def add_water_supply(context: "Context") -> dict[str, pd.DataFrame]: "input", technology="basin_to_reg", value=1, - unit="-", + unit="MCM", level="water_avail_basin", commodity="surfacewater_basin", mode=df_node["mode"], @@ -330,6 +330,30 @@ def add_water_supply(context: "Context") -> dict[str, pd.DataFrame]: .pipe(same_time), ] ) + + # input dataframe for basin_to_reg_all technology (irrigation freshwater) + inp = pd.concat( + [ + inp, + make_df( + "input", + technology="basin_to_reg_all", + value=1, + unit="MCM", + level="water_supply_basin", + commodity="freshwater_basin", + mode=df_node["mode"], + node_origin=df_node["node"], + node_loc=df_node["region"], + ) + .pipe( + broadcast, + year_vtg=year_wat, + time=pd.Series(sub_time), + ) + .pipe(same_time), + ] + ) inp["year_act"] = inp["year_vtg"] # # input data frame for slack technology balancing equality with demands # inp = pd.concat([inp, @@ -337,7 +361,7 @@ def add_water_supply(context: "Context") -> dict[str, pd.DataFrame]: # "input", # technology="salinewater_return", # value=1, - # unit="-", + # unit="MCM", # level="water_avail_basin", # commodity="salinewater_basin", # mode="M1", @@ -359,7 +383,7 @@ def add_water_supply(context: "Context") -> dict[str, pd.DataFrame]: "input", technology="extract_surfacewater", value=1, - unit="-", + unit="MCM", level="water_avail_basin", commodity="surfacewater_basin", mode="M1", @@ -385,7 +409,7 @@ def add_water_supply(context: "Context") -> dict[str, pd.DataFrame]: "input", technology="extract_groundwater", value=1, - unit="-", + unit="MCM", level="water_avail_basin", commodity="groundwater_basin", mode="M1", @@ -487,7 +511,7 @@ def add_water_supply(context: "Context") -> dict[str, pd.DataFrame]: "output", technology="extract_surfacewater", value=1, - unit="-", + unit="MCM", level="water_supply_basin", commodity="freshwater_basin", mode="M1", @@ -509,7 +533,7 @@ def add_water_supply(context: "Context") -> dict[str, pd.DataFrame]: "output", technology="extract_groundwater", value=1, - unit="-", + unit="MCM", level="water_supply_basin", commodity="freshwater_basin", mode="M1", @@ -533,7 +557,7 @@ def add_water_supply(context: "Context") -> dict[str, pd.DataFrame]: "output", technology="extract_gw_fossil", value=1, - unit="-", + unit="MCM", level="water_supply_basin", commodity="freshwater_basin", mode="M1", @@ -610,7 +634,7 @@ def add_water_supply(context: "Context") -> dict[str, pd.DataFrame]: "output", technology="basin_to_reg", value=1, - unit="-", + unit="MCM", level="water_supply", commodity="surfacewater", time_dest="year", @@ -621,6 +645,25 @@ def add_water_supply(context: "Context") -> dict[str, pd.DataFrame]: ] ) + # output data frame for basin_to_reg_all technology (irrigation freshwater) + output_df = pd.concat( + [ + output_df, + make_df( + "output", + technology="basin_to_reg_all", + value=1, + unit="MCM", + level="water_supply", + commodity="freshwater", + time_dest="year", + node_loc=df_node["region"], + node_dest=df_node["region"], + mode=df_node["mode"], + ).pipe(broadcast, year_vtg=year_wat, time=pd.Series(sub_time)), + ] + ) + output_df["year_act"] = output_df["year_vtg"] results["output"] = output_df @@ -635,6 +678,25 @@ def add_water_supply(context: "Context") -> dict[str, pd.DataFrame]: unit="USD/MCM", ).pipe(broadcast, year_vtg=year_wat, time=pd.Series(sub_time)) var["year_act"] = var["year_vtg"] + + # dummy variable cost for basin_to_reg_all technology (irrigation freshwater) + var = pd.concat( + [ + var, + make_df( + "var_cost", + technology="basin_to_reg_all", + mode=df_node["mode"], + node_loc=df_node["region"], + value=20 * USD_KM3_TO_USD_MCM, + unit="USD/MCM", + ).pipe(broadcast, year_vtg=year_wat, time=pd.Series(sub_time)), + ] + ) + basin_to_reg_all_mask = var["technology"] == "basin_to_reg_all" + var.loc[basin_to_reg_all_mask, "year_act"] = var.loc[ + basin_to_reg_all_mask, "year_vtg" + ] # # Dummy cost for extract surface ewater to prioritize water sources # var = pd.concat([var, make_df( # "var_cost", @@ -676,6 +738,24 @@ def add_water_supply(context: "Context") -> dict[str, pd.DataFrame]: year_act=df_sw["year"], ) + # share_mode_up for basin_to_reg_all technology (irrigation freshwater) + share = pd.concat( + [ + share, + make_df( + "share_mode_up", + shares="share_basin", + technology="basin_to_reg_all", + mode=df_sw["mode"], + node_share=df_sw["MSGREG"], + time=df_sw["time"], + value=df_sw["share"], + unit="%", + year_act=df_sw["year"], + ), + ] + ) + results["share_mode_up"] = share tl = ( diff --git a/message_ix_models/tests/model/water/data/test_water_supply.py b/message_ix_models/tests/model/water/data/test_water_supply.py index e732320ac6..ec5134f5cb 100644 --- a/message_ix_models/tests/model/water/data/test_water_supply.py +++ b/message_ix_models/tests/model/water/data/test_water_supply.py @@ -16,8 +16,8 @@ def test_map_basin_region_wat(test_context): # Personalize the context sets = {"year": [2020, 2030, 2040]} test_context["water build info"] = ScenarioInfo(y0=2020, set=sets) - test_context.type_reg = "country" - test_context.regions = "ZMB" + test_context.type_reg = "global" + test_context.regions = "R12" nodes = get_codes(f"node/{test_context.regions}") nodes = list(map(str, nodes[nodes.index("World")].child)) map_ISO_c = {test_context.regions: nodes[0]} @@ -25,6 +25,14 @@ def test_map_basin_region_wat(test_context): test_context.RCP = "2p6" test_context.REL = "med" test_context.time = "year" + # Set up valid_basins for water_for_ppl functions + # Read all basins from the basin delineation file to avoid filtering + from message_ix_models.util import package_data_path + + basin_file = f"basins_by_region_simpl_{test_context.regions}.csv" + basin_path = package_data_path("water", "delineation", basin_file) + df_basins = pd.read_csv(basin_path) + test_context.valid_basins = set(df_basins["BCU_name"].astype(str)) result = map_basin_region_wat(test_context) @@ -42,8 +50,8 @@ def test_add_water_supply(request, test_context): # Personalize the context sets = {"year": [2020, 2030, 2040]} test_context["water build info"] = ScenarioInfo(y0=2020, set=sets) - test_context.type_reg = "country" - test_context.regions = "ZMB" + test_context.type_reg = "global" + test_context.regions = "R12" nodes = get_codes(f"node/{test_context.regions}") nodes = list(map(str, nodes[nodes.index("World")].child)) map_ISO_c = {test_context.regions: nodes[0]} @@ -52,6 +60,14 @@ def test_add_water_supply(request, test_context): test_context.REL = "med" test_context.time = "year" test_context.nexus_set = "nexus" + # Set up valid_basins for water_for_ppl functions + # Read all basins from the basin delineation file to avoid filtering + from message_ix_models.util import package_data_path + + basin_file = f"basins_by_region_simpl_{test_context.regions}.csv" + basin_path = package_data_path("water", "delineation", basin_file) + df_basins = pd.read_csv(basin_path) + test_context.valid_basins = set(df_basins["BCU_name"].astype(str)) mp = test_context.get_platform() scenario_info = { @@ -73,7 +89,8 @@ def test_add_water_supply(request, test_context): test_context["water build info"] = ScenarioInfo(s) result = add_water_supply(test_context) - + result["input"].to_csv("supply_inp.csv", index=False) + result["output"].to_csv("supply_out.csv", index=False) # Assert the results assert isinstance(result, dict) assert "input" in result @@ -129,6 +146,15 @@ def test_add_e_flow(test_context): test_context.time = "year" test_context.SDG = True + # Set up valid_basins for water_for_ppl functions + # Read all basins from the basin delineation file to avoid filtering + from message_ix_models.util import package_data_path + + basin_file = f"basins_by_region_simpl_{test_context.regions}.csv" + basin_path = package_data_path("water", "delineation", basin_file) + df_basins = pd.read_csv(basin_path) + test_context.valid_basins = set(df_basins["BCU_name"].astype(str)) + # Call the function to be tested result = add_e_flow(test_context) From b3103e60bbc1ed83681e00548606e96397eddec4 Mon Sep 17 00:00:00 2001 From: Vignesh Raghunathan Date: Tue, 16 Sep 2025 10:42:30 +0200 Subject: [PATCH 32/43] Relabel basin_to_reg techs --- message_ix_models/data/water/technology.yaml | 12 +++---- .../model/water/data/water_supply.py | 31 ++++++++++--------- 2 files changed, 22 insertions(+), 21 deletions(-) diff --git a/message_ix_models/data/water/technology.yaml b/message_ix_models/data/water/technology.yaml index 25c7b64ea2..fae8e33197 100644 --- a/message_ix_models/data/water/technology.yaml +++ b/message_ix_models/data/water/technology.yaml @@ -1095,17 +1095,17 @@ nexus: # TODO verify description input: { commodity: saline_supply } - basin_to_reg: + basin_to_reg_core: description: >- - dummy technology to map basin technologies water supply to energy technologies + technology to map basin surface water availability directly to energy technologies - input: { commodity: freshwater_supply } + input: { commodity: surfacewater_basin } - basin_to_reg_all: + basin_to_reg_plus: description: >- - dummy technology to map freshwater basin supply to regional water supply for irrigation + technology to map basin freshwater to regional water supply for irrigation - input: { commodity: freshwater_supply } + input: { commodity: freshwater_basin } reg_to_basin: description: >- diff --git a/message_ix_models/model/water/data/water_supply.py b/message_ix_models/model/water/data/water_supply.py index 2df6e015d0..0fd47185d4 100644 --- a/message_ix_models/model/water/data/water_supply.py +++ b/message_ix_models/model/water/data/water_supply.py @@ -313,7 +313,7 @@ def add_water_supply(context: "Context") -> dict[str, pd.DataFrame]: inp, make_df( "input", - technology="basin_to_reg", + technology="basin_to_reg_core", value=1, unit="MCM", level="water_avail_basin", @@ -331,13 +331,13 @@ def add_water_supply(context: "Context") -> dict[str, pd.DataFrame]: ] ) - # input dataframe for basin_to_reg_all technology (irrigation freshwater) + # input dataframe for basin_to_reg_plus technology (irrigation freshwater) inp = pd.concat( [ inp, make_df( "input", - technology="basin_to_reg_all", + technology="basin_to_reg_plus", value=1, unit="MCM", level="water_supply_basin", @@ -632,7 +632,7 @@ def add_water_supply(context: "Context") -> dict[str, pd.DataFrame]: output_df, make_df( "output", - technology="basin_to_reg", + technology="basin_to_reg_core", value=1, unit="MCM", level="water_supply", @@ -645,13 +645,14 @@ def add_water_supply(context: "Context") -> dict[str, pd.DataFrame]: ] ) - # output data frame for basin_to_reg_all technology (irrigation freshwater) + # output data frame for basin_to_reg_plus technology (irrigation freshwater) + output_df = pd.concat( [ output_df, make_df( "output", - technology="basin_to_reg_all", + technology="basin_to_reg_plus", value=1, unit="MCM", level="water_supply", @@ -671,7 +672,7 @@ def add_water_supply(context: "Context") -> dict[str, pd.DataFrame]: # dummy variable cost for dummy water to energy technology var = make_df( "var_cost", - technology="basin_to_reg", + technology="basin_to_reg_core", mode=df_node["mode"], node_loc=df_node["region"], value=20 * USD_KM3_TO_USD_MCM, @@ -679,13 +680,13 @@ def add_water_supply(context: "Context") -> dict[str, pd.DataFrame]: ).pipe(broadcast, year_vtg=year_wat, time=pd.Series(sub_time)) var["year_act"] = var["year_vtg"] - # dummy variable cost for basin_to_reg_all technology (irrigation freshwater) + # dummy variable cost for basin_to_reg_plus technology (irrigation freshwater) var = pd.concat( [ var, make_df( "var_cost", - technology="basin_to_reg_all", + technology="basin_to_reg_plus", mode=df_node["mode"], node_loc=df_node["region"], value=20 * USD_KM3_TO_USD_MCM, @@ -693,9 +694,9 @@ def add_water_supply(context: "Context") -> dict[str, pd.DataFrame]: ).pipe(broadcast, year_vtg=year_wat, time=pd.Series(sub_time)), ] ) - basin_to_reg_all_mask = var["technology"] == "basin_to_reg_all" - var.loc[basin_to_reg_all_mask, "year_act"] = var.loc[ - basin_to_reg_all_mask, "year_vtg" + basin_to_reg_plus_mask = var["technology"] == "basin_to_reg_plus" + var.loc[basin_to_reg_plus_mask, "year_act"] = var.loc[ + basin_to_reg_plus_mask, "year_vtg" ] # # Dummy cost for extract surface ewater to prioritize water sources # var = pd.concat([var, make_df( @@ -729,7 +730,7 @@ def add_water_supply(context: "Context") -> dict[str, pd.DataFrame]: share = make_df( "share_mode_up", shares="share_basin", - technology="basin_to_reg", + technology="basin_to_reg_core", mode=df_sw["mode"], node_share=df_sw["MSGREG"], time=df_sw["time"], @@ -738,14 +739,14 @@ def add_water_supply(context: "Context") -> dict[str, pd.DataFrame]: year_act=df_sw["year"], ) - # share_mode_up for basin_to_reg_all technology (irrigation freshwater) + # share_mode_up for basin_to_reg_plus technology (irrigation freshwater) share = pd.concat( [ share, make_df( "share_mode_up", shares="share_basin", - technology="basin_to_reg_all", + technology="basin_to_reg_plus", mode=df_sw["mode"], node_share=df_sw["MSGREG"], time=df_sw["time"], From 634a2a0a3736aead525ab4cf75e402eb050f8f9b Mon Sep 17 00:00:00 2001 From: Vignesh Raghunathan Date: Wed, 24 Sep 2025 13:17:15 +0200 Subject: [PATCH 33/43] Fix double water return flows Now water return flows follow a single path: cooling techs -> water_return commodity -> reg_to_basin tech -> surfacewater_basin --- .../model/water/data/water_for_ppl.py | 38 ------------------- 1 file changed, 38 deletions(-) diff --git a/message_ix_models/model/water/data/water_for_ppl.py b/message_ix_models/model/water/data/water_for_ppl.py index 5a8961c110..b84004a3a5 100644 --- a/message_ix_models/model/water/data/water_for_ppl.py +++ b/message_ix_models/model/water/data/water_for_ppl.py @@ -620,44 +620,6 @@ def cool_tech( unit="-", ) - # add water return flows for cooling tecs - # Use share of basin availability to distribute the return flow from - df_sw = map_basin_region_wat(context) - df_sw.drop(columns={"mode", "date", "MSGREG"}, inplace=True) - df_sw.rename( - columns={"region": "node_dest", "time": "time_dest", "year": "year_act"}, - inplace=True, - ) - df_sw["time_dest"] = df_sw["time_dest"].astype(str) - if context.nexus_set == "nexus": - for nn in icmse_df.node_loc.unique(): - # input cooling fresh basin - icfb_df = icmse_df[icmse_df["node_loc"] == nn] - bs = list(df_node[df_node["region"] == nn]["node"]) - - out_t = ( - make_df( - "output", - node_loc=icfb_df["node_loc"], - technology=icfb_df["technology_name"], - year_vtg=icfb_df["year_vtg"], - year_act=icfb_df["year_act"], - mode=icfb_df["mode"], - # node_origin=icmse_df["node_origin"], - commodity="surfacewater_basin", - level="water_avail_basin", - time="year", - value=icfb_df["value_return"], - unit="MCM/GWa", - ) - .pipe(broadcast, node_dest=bs, time_dest=pd.Series(sub_time)) - .merge(df_sw, how="left") - ) - # multiply by basin water availability share - out_t["value"] = out_t["value"] * out_t["share"] - out_t.drop(columns={"share"}, inplace=True) - out = pd.concat([out, out_t]) - # Add water return flows output from fresh cooling technologies to reg_to_basin # Fresh cooling technologies output their return flows to reg_to_basin technology out_return = make_df( From 3adcc4929a4c669a56eb0d9f96a0147e4274bb91 Mon Sep 17 00:00:00 2001 From: Vignesh Raghunathan Date: Wed, 24 Sep 2025 14:33:51 +0200 Subject: [PATCH 34/43] Lower fossil gw TL --- message_ix_models/model/water/data/water_supply.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/message_ix_models/model/water/data/water_supply.py b/message_ix_models/model/water/data/water_supply.py index 0fd47185d4..f343e0c6a9 100644 --- a/message_ix_models/model/water/data/water_supply.py +++ b/message_ix_models/model/water/data/water_supply.py @@ -790,7 +790,7 @@ def add_water_supply(context: "Context") -> dict[str, pd.DataFrame]: make_df( "technical_lifetime", technology="extract_gw_fossil", - value=20, + value=1, # 1 Year TL to further discourage use. unit="y", ) .pipe(broadcast, year_vtg=year_wat, node_loc=df_node["node"]) From 00f3ddf4806c9bfeda3ee4812a8a2b407fb00714 Mon Sep 17 00:00:00 2001 From: Vignesh Raghunathan Date: Fri, 26 Sep 2025 11:06:57 +0200 Subject: [PATCH 35/43] Add bounds to extract_salinewater_cool Bound = histroical cap at last historical year. --- .../model/water/data/water_for_ppl.py | 91 +++++++++++++++++-- .../model/water/data/water_supply.py | 24 ++++- 2 files changed, 104 insertions(+), 11 deletions(-) diff --git a/message_ix_models/model/water/data/water_for_ppl.py b/message_ix_models/model/water/data/water_for_ppl.py index b84004a3a5..2d6fbf6b5f 100644 --- a/message_ix_models/model/water/data/water_for_ppl.py +++ b/message_ix_models/model/water/data/water_for_ppl.py @@ -283,6 +283,70 @@ def cooling_shares_SSP_from_yaml( return df_region +def _add_saline_extract_bounds(results: dict, info) -> None: + """Add dynamic bound_activity_up for extract_salinewater_cool based on historical saline cooling demand. + + Parameters + ---------- + results : dict + Dictionary of parameter DataFrames being built + info : + Water build info context containing model years + """ + if "historical_activity" not in results: + return + + hist_activity = results["historical_activity"] + + # Filter to saline cooling technologies + saline_hist = hist_activity[ + hist_activity["technology"].str.endswith("__ot_saline", na=False) + ] + + if saline_hist.empty: + return + + # Get last historical year + last_hist_year = saline_hist["year_act"].max() + + # Filter to last historical year and sum by region + last_year_saline = saline_hist[saline_hist["year_act"] == last_hist_year] + regional_bounds = last_year_saline.groupby("node_loc")["value"].sum().reset_index() + + # Create bound values for each region (fallback to 1e4 if no activity) + bound_values = [] + bound_regions = [] + + for _, row in regional_bounds.iterrows(): + region = row["node_loc"] + total_activity = row["value"] + bound_value = ( + total_activity if total_activity > 0 else 1e4 + ) # FIXME: Aribitrary 1e4 + bound_values.append(bound_value) + bound_regions.append(region) + + # Create bound_activity_up for extract_salinewater_cool + if bound_values: + saline_water_cool_cap = make_df( + "bound_activity_up", + technology="extract_salinewater_cool", + node_loc=bound_regions, + mode="M1", + time="year", + value=bound_values, + unit="MCM", + ).pipe(broadcast, year_act=info.Y) + + # Add to results (concatenate if bound_activity_up already exists) + if "bound_activity_up" in results: + results["bound_activity_up"] = pd.concat( + [results["bound_activity_up"], saline_water_cool_cap], ignore_index=True + ) + else: + results["bound_activity_up"] = saline_water_cool_cap + + def _compose_capacity_factor(inp: pd.DataFrame, context: "Context") -> pd.DataFrame: """Create the capacity_factor base on data in `inp` and `context. @@ -441,16 +505,18 @@ def cool_tech( # Convert year values into integers to be compatibel for model input_cool.year_vtg = input_cool.year_vtg.astype(int) input_cool.year_act = input_cool.year_act.astype(int) - + # Fix invalid year combinations (year_act < year_vtg) using proper vintage-active combinations - year_combinations = get_vintage_and_active_years(info, technical_lifetime=30, same_year_only=False) - + year_combinations = get_vintage_and_active_years( + info, technical_lifetime=30, same_year_only=False + ) + # Create a mapping of valid year combinations - valid_years = set(zip(year_combinations['year_vtg'], year_combinations['year_act'])) - + valid_years = set(zip(year_combinations["year_vtg"], year_combinations["year_act"])) + # Filter input_cool to only include valid year combinations input_cool_valid_mask = input_cool.apply( - lambda row: (int(row['year_vtg']), int(row['year_act'])) in valid_years, axis=1 + lambda row: (int(row["year_vtg"]), int(row["year_act"])) in valid_years, axis=1 ) input_cool = input_cool[input_cool_valid_mask] # Drops extra technologies from the data. backwards compatibility @@ -704,7 +770,9 @@ def cool_tech( .pipe(broadcast, year_combinations) .pipe(broadcast, node_dest=matching_basins["node_dest"].unique()) .merge( - matching_basins.drop_duplicates(["node_dest"])[["node_dest", "share"]], + matching_basins.drop_duplicates(["node_dest"])[ + ["node_dest", "share"] + ], on="node_dest", how="left", ) @@ -1009,7 +1077,7 @@ def cool_tech( "initial_activity_lo", "initial_new_capacity_up", "soft_activity_up", - "soft_activity_lo", + # "soft_activity_lo", #causes infeasibilty. "soft_new_capacity_up", "level_cost_activity_soft_up", "level_cost_activity_soft_lo", @@ -1051,12 +1119,12 @@ def cool_tech( if param_name == "growth_new_capacity_up": df_param_share.loc[ df_param_share["technology"].str.endswith("__ot_saline"), "value" - ] = 0 + ] = 1e-3 print(f"setting growth up new cap 0 for {df_param_share['technology']}") if param_name == "growth_activity_up": df_param_share.loc[ df_param_share["technology"].str.endswith("__ot_saline"), "value" - ] = 0 + ] = 1e-3 print(f"setting growth up act 0 for {df_param_share['technology']}") results[param_name] = pd.concat( [results.get(param_name, pd.DataFrame()), df_param_share], ignore_index=True @@ -1069,6 +1137,9 @@ def cool_tech( # pd concat to the existing results["share_commodity_up"] results["share_commodity_up"] = pd.concat([df_share], ignore_index=True) + # Add dynamic bound_activity_up for extract_salinewater_cool + _add_saline_extract_bounds(results, info) + return results diff --git a/message_ix_models/model/water/data/water_supply.py b/message_ix_models/model/water/data/water_supply.py index f343e0c6a9..bf5aea02d8 100644 --- a/message_ix_models/model/water/data/water_supply.py +++ b/message_ix_models/model/water/data/water_supply.py @@ -597,6 +597,23 @@ def add_water_supply(context: "Context") -> dict[str, pd.DataFrame]: ] ) + + # Technical lifetime for extract_salinewater_cool + saline_water_cool_tl = make_df( + "technical_lifetime", + technology="extract_salinewater_cool", + value=1, + unit="y", + ).pipe(broadcast, node_loc=node_region, year_vtg=year_wat) + + # Investment cost for extract_salinewater_cool + saline_water_cool_inv_cost = make_df( + "inv_cost", + technology="extract_salinewater_cool", + value=1e-2, + unit="USD/MCM", + ).pipe(broadcast, node_loc=node_region, year_vtg=year_wat) + hist_new_cap = make_df( "historical_new_capacity", node_loc=df_hist["BCU_name"], @@ -834,7 +851,12 @@ def add_water_supply(context: "Context") -> dict[str, pd.DataFrame]: ) results["inv_cost"] = inv_cost - + results["technical_lifetime"] = pd.concat( + [results["technical_lifetime"], saline_water_cool_tl] + ) + results["inv_cost"] = pd.concat( + [results["inv_cost"], saline_water_cool_inv_cost] + ) fix_cost = make_df( "fix_cost", technology="extract_gw_fossil", From 2dd4d3b0a0ebab4eed0f1ce3932e1e5b374cd019 Mon Sep 17 00:00:00 2001 From: Vignesh Raghunathan Date: Fri, 26 Sep 2025 11:45:56 +0200 Subject: [PATCH 36/43] Refactor add_cool_tech - Code was very messy --- .../model/water/data/water_for_ppl.py | 1680 +++++++++-------- 1 file changed, 904 insertions(+), 776 deletions(-) diff --git a/message_ix_models/model/water/data/water_for_ppl.py b/message_ix_models/model/water/data/water_for_ppl.py index 2d6fbf6b5f..9dedd7b05a 100644 --- a/message_ix_models/model/water/data/water_for_ppl.py +++ b/message_ix_models/model/water/data/water_for_ppl.py @@ -11,8 +11,8 @@ from message_ix_models import Context from message_ix_models.model.water.data.water_supply import map_basin_region_wat from message_ix_models.model.water.utils import ( - m3_GJ_TO_MCM_GWa, get_vintage_and_active_years, + m3_GJ_TO_MCM_GWa, ) from message_ix_models.util import ( broadcast, @@ -63,189 +63,876 @@ def missing_tech(x: pd.Series) -> pd.Series: return pd.Series({"value": x["value"], "level": x["level"]}) -def cooling_fr(x: pd.Series) -> float: - """Calculate cooling fraction +def _load_cooling_data( + context: "Context", scenario: Optional["Scenario"] = None +) -> dict: + """Load all cooling technology data files and scenario parameters. + + Parameters + ---------- + context : Context + Model context containing configuration + scenario : Scenario, optional + Scenario to extract data from Returns ------- - The calculated cooling fraction after for two categories; - 1. Technologies that produce heat as an output - cooling_fraction(h_cool) = input value(hi) - 1 - Simply subtract 1 from the heating value since the rest of the part is already - accounted in the heating value - 2. Rest of technologies - h_cool = hi -Hi* h_fg - 1, - where: - h_fg (flue gasses losses) = 0.1 (10% assumed losses) + dict + Dictionary containing loaded data: + - tech_performance_path: path to technology performance file + - cost_share_path: path to cost and share data file + - basin_delineation_path: path to basin delineation file + - df_node: processed basin delineation dataframe + - node_region: unique region nodes + - cooling_df: cooling technology dataframe with parent_tech column + - scenario: scenario object + - ref_input: combined input/output parameters from scenario """ - try: - if "hpl" in x["parent_tech"]: - return x["value"] - 1 - else: - return x["value"] - (x["value"] * 0.1) - 1 - except KeyError: - return x["value"] - (x["value"] * 0.1) - 1 + # File paths with sensible names + tech_performance_path = package_data_path( + "water", "ppl_cooling_tech", "tech_water_performance_ssp_msg.csv" + ) + cost_share_filename = ( + "cooltech_cost_and_shares_" + + (f"ssp_msg_{context.regions}" if context.type_reg == "global" else "country") + + ".csv" + ) + cost_share_path = package_data_path( + "water", "ppl_cooling_tech", cost_share_filename + ) -def shares( - x: pd.Series, - context: "Context", - search_cols_cooling_fraction: list, - hold_df: pd.DataFrame, - search_cols: list, -) -> pd.Series: - """Process share and cooling fraction. + basin_delineation_filename = f"basins_by_region_simpl_{context.regions}.csv" + basin_delineation_path = package_data_path( + "water", "delineation", basin_delineation_filename + ) - Returns - ------- - Product of value of shares of cooling technology types of regions with - corresponding cooling fraction - """ - for col in search_cols_cooling_fraction: - col2 = context.map_ISO_c[col] if context.type_reg == "country" else col + # Load and process basin delineation + df_node = pd.read_csv(basin_delineation_path) + df_node = df_node[df_node["BCU_name"].isin(context.valid_basins)] - # Filter the cooling fraction - cooling_fraction = hold_df[ - (hold_df["node_loc"] == col2) - & (hold_df["technology_name"] == x["technology"]) - ]["cooling_fraction"] + # Assign proper nomenclature to basin data + df_node["node"] = "B" + df_node["BCU_name"].astype(str) + df_node["mode"] = "M" + df_node["BCU_name"].astype(str) + df_node["region"] = ( + context.map_ISO_c[context.regions] + if context.type_reg == "country" + else f"{context.regions}_" + df_node["REGION"].astype(str) + ) + node_region = df_node["region"].unique() - # Log unmatched rows - if cooling_fraction.empty: - log.info( - f"No cooling_fraction found for node_loc: {col2}, " - f"technology: {x['technology']}" - ) - cooling_fraction = pd.Series([0]) + # Load cooling technology performance data + cooling_tech_df = pd.read_csv(tech_performance_path) + cooling_df = cooling_tech_df.loc[ + cooling_tech_df["technology_group"] == "cooling" + ].copy() - # Ensure the Series is not empty before accessing its first element - # # Default to 0 if cooling_fraction is empty - x[col] = ( - x[col] * cooling_fraction.iloc[0] - if not cooling_fraction.empty - else x[col] * 0 - ) + # Extract parent technology names + cooling_df["parent_tech"] = ( + cooling_df["technology_name"] + .apply(lambda x: pd.Series(str(x).split("__"))) + .drop(columns=1) + ) - # Construct the output - results = [] - for i in x: - if isinstance(i, str): - results.append(i) - else: - results.append(float(i) if not isinstance(i, pd.Series) else i.iloc[0]) + # Get scenario and extract parent technology parameters + scen = scenario or context.get_scenario() - return pd.Series(results, index=search_cols) + # Extract input parameters for parent technologies + ref_input = scen.par("input", {"technology": cooling_df["parent_tech"]}) + # Handle missing technologies (some only have outputs, like CSP) + missing_tech_list = cooling_df["parent_tech"][ + ~cooling_df["parent_tech"].isin(ref_input["technology"]) + ] + ref_output = scen.par("output", {"technology": missing_tech_list}) + ref_output.columns = ref_input.columns + ref_input = pd.concat([ref_input, ref_output]) -def apply_act_cap_multiplier( - df: pd.DataFrame, - hold_cost: pd.DataFrame, - cap_fact_parent: Optional[pd.DataFrame] = None, - param_name: str = "", -) -> pd.DataFrame: - """ - Generalized function to apply hold_cost factors and optionally divide by cap factor. - hold cost contain the share per cooling technologies and their activity factors - compared to parent technologies. + return { + "tech_performance_path": tech_performance_path, + "cost_share_path": cost_share_path, + "basin_delineation_path": basin_delineation_path, + "df_node": df_node, + "node_region": node_region, + "cooling_df": cooling_df, + "scenario": scen, + "ref_input": ref_input, + } + + +def _process_cooling_data(cooling_data: dict, context: "Context", info) -> dict: + """Process and clean cooling technology data. Parameters ---------- - df : pd.DataFrame - The input dataframe in long format, containing 'node_loc', 'technology', and - 'value'. - hold_cost : pd.DataFrame - DataFrame with 'utype', region-specific multipliers (wide format), and - 'technology'. - cap_fact_parent : pd.DataFrame, optional - DataFrame with capacity factors, used only if 'capacity' is in param_name. - param_name : str, optional - The name of the parameter being processed. + cooling_data : dict + Data dictionary from _load_cooling_data + context : Context + Model context + info : + Water build info context Returns ------- - pd.DataFrame - The modified dataframe. + dict + Dictionary containing processed data: + - input_cool: main processed cooling dataframe + - electr: electricity-requiring technologies + - saline_df: saline water technologies + - icmse_df: freshwater technologies (excluding saline and air) """ + cooling_df = cooling_data["cooling_df"] + ref_input = cooling_data["ref_input"] - # Melt hold_cost to long format - hold_cost_long = hold_cost.melt( - id_vars=["utype", "technology"], var_name="node_loc", value_name="multiplier" + # Apply missing technology fixes and merge data + ref_input[["value", "level"]] = ref_input.apply(missing_tech, axis=1) + + # Combine cooling data with input parameters from parent technologies + input_cool = ( + cooling_df.set_index("parent_tech") + .combine_first(ref_input.set_index("technology")) + .reset_index() ) - # Merge and apply hold_cost multipliers: share * addon_factor - # ACT,c = ACT,p * share * addon_factor - df = df.merge(hold_cost_long, how="left") - df["value"] *= df["multiplier"] + # Clean data + input_cool = input_cool.dropna(subset=["value"]) + input_cool.year_vtg = input_cool.year_vtg.astype(int) + input_cool.year_act = input_cool.year_act.astype(int) - # filter with value > 0 - df = df[df["value"] > 0] + # Fix invalid year combinations using proper vintage-active combinations + year_combinations = get_vintage_and_active_years( + info, technical_lifetime=30, same_year_only=False + ) + valid_years = set(zip(year_combinations["year_vtg"], year_combinations["year_act"])) - # If parameter is capacity-related, multiply by cap_fact - # CAP,c * cf,c(=1) = CAP,p * share * addon_factor * cf,p - if "capacity" in param_name and cap_fact_parent is not None: - df = df.merge(cap_fact_parent, how="left") - df["value"] *= df["cap_fact"] * 1.2 # flexibility - df.drop(columns="cap_fact", inplace=True) - # remove if there are Nan values, but write a log that inform on the parameter and - # the head of the data - # Identify missing or invalid values - missing_values = ( - df["value"].isna() - | (df["value"] == "") - | (df["value"].astype(str).str.strip() == "") + input_cool_valid_mask = input_cool.apply( + lambda row: (int(row["year_vtg"]), int(row["year_act"])) in valid_years, axis=1 ) + input_cool = input_cool[input_cool_valid_mask] - if missing_values.any(): - print("diobo") - log.warning( - f"Missing or empty values found in {param_name}.head(1):\n" - f"{df[missing_values].head(1)}" - ) - df = df[~missing_values] # Remove rows with missing/empty values + # Filter out unwanted technologies for backwards compatibility + input_cool = input_cool[ + (input_cool["level"] != "water_supply") & (input_cool["level"] != "cooling") + ] + # Heat plants need no cooling + input_cool = input_cool[ + ~input_cool["technology_name"].str.contains("hpl", na=False) + ] - df.drop(columns=["utype", "multiplier"], inplace=True) + # Handle global region swapping + global_region = f"{context.regions}_GLB" + input_cool.loc[input_cool["node_loc"] == global_region, "node_loc"] = input_cool[ + "node_origin" + ] + input_cool.loc[input_cool["node_origin"] == global_region, "node_origin"] = ( + input_cool["node_loc"] + ) - return df + # Calculate cooling fractions + input_cool["cooling_fraction"] = input_cool.apply(cooling_fr, axis=1) + # Convert water withdrawal units and calculate rates + input_cool["value_cool"] = ( + input_cool["water_withdrawal_mid_m3_per_output"] + * m3_GJ_TO_MCM_GWa + / input_cool["cooling_fraction"] + ) + input_cool["value_cool"] = np.where( + input_cool["value_cool"] < 0, 1e-6, input_cool["value_cool"] + ) -def cooling_shares_SSP_from_yaml( - context: "Context", # Aligning with the style of the functions provided -) -> pd.DataFrame: - """ - Populate a DataFrame for 'share_commodity_up' from a YAML configuration file. + input_cool["return_rate"] = 1 - ( + input_cool["water_consumption_mid_m3_per_output"] + / input_cool["water_withdrawal_mid_m3_per_output"] + ) + input_cool["consumption_rate"] = ( + input_cool["water_consumption_mid_m3_per_output"] + / input_cool["water_withdrawal_mid_m3_per_output"] + ) + + input_cool["value_return"] = input_cool["return_rate"] * input_cool["value_cool"] + input_cool["value_consumption"] = ( + input_cool["consumption_rate"] * input_cool["value_cool"] + ) + + # Create technology-specific dataframes + electr = input_cool[input_cool["parasitic_electricity_demand_fraction"] > 0.0] + electr["value_cool"] = ( + electr["parasitic_electricity_demand_fraction"] / electr["cooling_fraction"] + ) + electr["value_cool"] = np.where( + electr["value_cool"] < 0, 1e-6, electr["value_cool"] + ) + + saline_df = input_cool[ + input_cool["technology_name"].str.endswith("ot_saline", na=False) + ] + + # Fresh water technologies (excluding saline and air cooling) + con1 = input_cool["technology_name"].str.endswith("ot_saline", na=False) + con2 = input_cool["technology_name"].str.endswith("air", na=False) + icmse_df = input_cool[(~con1) & (~con2)] + + return { + "input_cool": input_cool, + "electr": electr, + "saline_df": saline_df, + "icmse_df": icmse_df, + "con2": con2, # Needed for emission processing + } + + +def _process_share_constraints( + input_cool: pd.DataFrame, cost_share_path: str, context: "Context" +) -> dict: + """Process share constraints and historical data backfilling. Parameters ---------- + input_cool : pd.DataFrame + Processed cooling technology dataframe + cost_share_path : str + Path to cost and share data file context : Context - Context object containing SSP information (e.g., context.SSP) + Model context Returns ------- - pd.DataFrame - A DataFrame populated with values from the YAML configuration file. + dict + Dictionary containing: + - share_constraints: DataFrame with share constraint data + - hold_cost: processed cost data with regional factors + - input_cool_2015: historical data for 2015 """ - # Load the YAML file - FILE = "ssp.yaml" - yaml_file_path = package_data_path("water", FILE) - try: - with open(yaml_file_path, "r") as file: - yaml_data = yaml.safe_load(file) - except FileNotFoundError: - log.warning(f"YAML file '{FILE}' not found. Please, check your data.") + # Load cost and share data + cost = pd.read_csv(cost_share_path) + cost["technology"] = cost["utype"] + "__" + cost["cooling"] + cost["share"] = cost["utype"] + "_" + cost["cooling"] - # Read the SSP from the context - ssp = context.ssp + # Process share constraints + share_filtered = cost.loc[ + :, + ["utype", "share"] + [col for col in cost.columns if col.startswith("mix_")], + ] - # Navigate to the scenarios section in the YAML file - macro_regions_data = yaml_data.get("macro-regions", {}) - scenarios = yaml_data.get("scenarios", {}) + share_long = share_filtered.melt( + id_vars=["utype", "share"], var_name="node_share", value_name="value" + ) + share_long = share_long[ + share_long["utype"].isin(input_cool["parent_tech"].unique()) + ].reset_index(drop=True) - # Validate that the SSP exists in the YAML data - if ssp not in scenarios: - log.warning( - f"SSP '{ssp}' not found in the 'scenarios' section of the YAML file." - ) - return pd.DataFrame() + # Clean share data + share_long["node_share"] = share_long["node_share"].str.replace( + "mix_", "", regex=False + ) + share_long["value"] = share_long["value"] * 1.05 # flexibility + share_long["value"] = share_long["value"].replace(0, 0.0001) + + share_long["shares"] = "share_calib_" + share_long["share"] + share_long.drop(columns={"utype", "share"}, inplace=True) + cost.drop(columns="share", inplace=True) + share_long["time"] = "year" + share_long["unit"] = "-" + + # FIXME: Temporarily commenting out share calib constraints. + # Causes 4X size explosion. Likely problematic. + # share_calib = share_long.copy() + # # Expand for years [2020, 2025] + # share_calib = share_calib.loc[share_calib.index.repeat(2)].reset_index(drop=True) + # years_calib = [2020, 2025] + # share_calib["year_act"] = years_calib * (len(share_calib) // 2) + # # take year in info.N but not years_calib + # years_fut = [year for year in info.Y if year not in years_calib] + # share_fut = share_long.copy() + # share_fut = share_fut.loc[share_fut.index.repeat(len(years_fut))].reset_index( + # drop=True + # ) + # share_fut["year_act"] = years_fut * (len(share_fut) // len(years_fut)) + # # filter only shares that contain "ot_saline" + # share_fut = share_fut[share_fut["shares"].str.contains("ot_saline")] + # # if value < 0.4 set to 0.4, not so allow too much saline where there is no + # share_fut["value"] = np.where(share_fut["value"] < 0.45, 0.45, share_fut["value"]) + # # keep only after 2050 + # share_fut = share_fut[share_fut["year_act"] >= 2050] + # # append share_calib and (share_fut only to add constraints on ot_saline) + # results["share_commodity_up"] = pd.concat([share_calib]) + + # Historical data backfilling logic + input_cool_2015 = input_cool[ + (input_cool["year_act"] == 2015) & (input_cool["year_vtg"] == 2015) + ] + input_cool_set = set(zip(input_cool["parent_tech"], input_cool["node_loc"])) + year_list = [2020, 2010, 2030, 2050, 2000, 2080, 1990] + + for year in year_list: + input_cool_2015_set = set( + # FIXME: This should have been a one off script for debugging. + zip(input_cool_2015["parent_tech"], input_cool_2015["node_loc"]) + ) + missing_combinations = input_cool_set - input_cool_2015_set + + if not missing_combinations: + break + + missing_rows = input_cool[ + (input_cool["year_act"] == year) + & (input_cool["year_vtg"] == year) + & input_cool.apply( + lambda row: (row["parent_tech"], row["node_loc"]) + in missing_combinations, + axis=1, + ) + ] + + if not missing_rows.empty: + missing_rows = missing_rows.copy() + missing_rows["year_act"] = 2015 + missing_rows["year_vtg"] = 2015 + input_cool_2015 = pd.concat( + [input_cool_2015, missing_rows], ignore_index=True + ) + + # Final check for missing combinations + input_cool_2015_set = set( + # FIXME: This should have been a one off script for debugging. + zip(input_cool_2015["parent_tech"], input_cool_2015["node_loc"]) + ) + still_missing = input_cool_set - input_cool_2015_set + + if still_missing: + log.warning( + f"Warning: Some combinations are still missing even after trying all " + f"years: {still_missing}" + ) + + # Process regional share factors + cost.rename(columns=lambda name: name.replace("mix_", ""), inplace=True) + search_cols = [ + col + for col in cost.columns + if context.regions in col or col in ["technology", "utype"] + ] + hold_df = input_cool_2015[ + ["node_loc", "technology_name", "cooling_fraction"] + ].drop_duplicates() + search_cols_cooling_fraction = [ + col for col in search_cols if col not in ["technology", "utype"] + ] + + # Apply cooling factors to regional shares + hold_cost = cost[search_cols].apply( + shares, + axis=1, + context=context, + search_cols_cooling_fraction=search_cols_cooling_fraction, + hold_df=hold_df, + search_cols=search_cols, + ) + + # SSP-based share constraints + ssp_share_constraints = cooling_shares_SSP_from_yaml(context) + + return { + "share_constraints": ssp_share_constraints, + "hold_cost": hold_cost, + "input_cool_2015": input_cool_2015, + } + + +def _create_cooling_parameters( + processed_data: dict, node_region: list, context: "Context", info +) -> dict: + """Create basic MESSAGEix parameters for cooling technologies. + + Parameters + ---------- + processed_data : dict + Processed cooling data from _process_cooling_data + node_region : list + List of regional nodes + context : Context + Model context + info : + Water build info context + + Returns + ------- + dict + Dictionary of parameter DataFrames + """ + input_cool = processed_data["input_cool"] + electr = processed_data["electr"] + saline_df = processed_data["saline_df"] + icmse_df = processed_data["icmse_df"] + con2 = processed_data["con2"] + + results = {} + + # Create input parameters + # Electricity inputs for parasitic demand + inp = make_df( + "input", + node_loc=electr["node_loc"], + technology=electr["technology_name"], + year_vtg=electr["year_vtg"], + year_act=electr["year_act"], + mode=electr["mode"], + node_origin=electr["node_origin"], + commodity="electr", + level="secondary", + time="year", + time_origin="year", + value=electr["value_cool"], + unit="GWa", + ) + + # Fresh water inputs (once-through and closed-loop) + inp = pd.concat( + [ + inp, + make_df( + "input", + node_loc=icmse_df["node_loc"], + technology=icmse_df["technology_name"], + year_vtg=icmse_df["year_vtg"], + year_act=icmse_df["year_act"], + mode=icmse_df["mode"], + node_origin=icmse_df["node_origin"], + commodity="surfacewater", + level="water_supply", + time="year", + time_origin="year", + value=icmse_df["value_cool"], + unit="MCM/GWa", + ), + ] + ) + + # Saline water inputs + inp = pd.concat( + [ + inp, + make_df( + "input", + node_loc=saline_df["node_loc"], + technology=saline_df["technology_name"], + year_vtg=saline_df["year_vtg"], + year_act=saline_df["year_act"], + mode=saline_df["mode"], + node_origin=saline_df["node_origin"], + commodity="saline_ppl", + level="saline_supply", + time="year", + time_origin="year", + value=saline_df["value_cool"], + unit="MCM/GWa", + ), + ] + ) + + inp = inp.dropna(subset=["value"]) + results["input"] = inp + + # Create emission factors for water return + emiss_df = input_cool[(~con2)] + emi = make_df( + "emission_factor", + node_loc=emiss_df["node_loc"], + technology=emiss_df["technology_name"], + year_vtg=emiss_df["year_vtg"], + year_act=emiss_df["year_act"], + mode=emiss_df["mode"], + emission="fresh_return", + value=emiss_df["value_return"], + unit="MCM/GWa", + ) + results["emission_factor"] = emi + + # Create output parameters + # Share constraints output + out = make_df( + "output", + node_loc=input_cool["node_loc"], + technology=input_cool["technology_name"], + year_vtg=input_cool["year_vtg"], + year_act=input_cool["year_act"], + mode=input_cool["mode"], + node_dest=input_cool["node_origin"], + commodity=input_cool["technology_name"].str.split("__").str[1], + level="share", + time="year", + time_dest="year", + value=1, + unit="-", + ) + + # Water return flows output + out_return = make_df( + "output", + node_loc=icmse_df["node_loc"], + technology=icmse_df["technology_name"], + year_vtg=icmse_df["year_vtg"], + year_act=icmse_df["year_act"], + mode=icmse_df["mode"], + node_dest=icmse_df["node_origin"], + commodity="water_return", + level="water_supply", + time="year", + time_dest="year", + value=icmse_df["value_return"], + unit="MCM/GWa", + ) + + out = pd.concat([out, out_return]) + results["output"] = out + + # Create addon conversion parameters + adon_df = input_cool.copy() + adon_df["tech"] = "cooling__" + adon_df["parent_tech"].astype(str) + addon_df = make_df( + "addon_conversion", + node=adon_df["node_loc"], + technology=adon_df["parent_tech"], + year_vtg=adon_df["year_vtg"], + year_act=adon_df["year_act"], + mode=adon_df["mode"], + time="year", + type_addon=adon_df["tech"], + value=adon_df["cooling_fraction"], + unit="-", + ) + results["addon_conversion"] = addon_df + + # Addon lower bound (allows 100% activity of parent technologies) + addon_lo = make_matched_dfs(addon_df, addon_lo=1) + results["addon_lo"] = addon_lo["addon_lo"] + + # Technical lifetime + year = info.yv_ya.year_vtg.drop_duplicates() + year = year[year >= 1990] + + tl = ( + make_df( + "technical_lifetime", + technology=inp["technology"].drop_duplicates(), + value=30, + unit="year", + ) + .pipe(broadcast, year_vtg=year, node_loc=node_region) + .pipe(same_node) + ) + results["technical_lifetime"] = tl + + # Capacity factors + results["capacity_factor"] = _compose_capacity_factor(inp=inp, context=context) + + return results + + +def _expand_parent_parameters( + scenario, cooling_df: pd.DataFrame, hold_cost: pd.DataFrame +) -> dict: + """Expand parent technology parameters across cooling variants. + + Parameters + ---------- + scenario : Scenario + MESSAGEix scenario object + cooling_df : pd.DataFrame + Cooling technology dataframe with parent_tech column + hold_cost : pd.DataFrame + Processed cost data with regional factors + + Returns + ------- + dict + Dictionary of expanded parameter DataFrames + """ + results = {} + + # Process capacity factors from parent technologies + cap_fact_parent = scenario.par( + "capacity_factor", {"technology": cooling_df["parent_tech"]} + ) + # cap_fact_parent = cap_fact_parent[ + # (cap_fact_parent["node_loc"] == "R12_NAM") + # & (cap_fact_parent["technology"] == "coal_ppl_u") # nuc_lc + # ] + + # Split capacity factors by model periods + cap_fact_parent1 = cap_fact_parent[ + ["node_loc", "technology", "year_vtg", "value"] + ].drop_duplicates() + cap_fact_parent1 = cap_fact_parent1[ + cap_fact_parent1["year_vtg"] < scenario.firstmodelyear + ] + cap_fact_parent1 = cap_fact_parent1.groupby( + ["node_loc", "technology", "year_vtg"], as_index=False + ).min() + + cap_fact_parent2 = cap_fact_parent[ + ["node_loc", "technology", "year_act", "value"] + ].drop_duplicates() + cap_fact_parent2 = cap_fact_parent2[ + cap_fact_parent2["year_act"] >= scenario.firstmodelyear + ] + cap_fact_parent2 = cap_fact_parent2.groupby( + ["node_loc", "technology", "year_act"], as_index=False + ).min() + cap_fact_parent2.rename(columns={"year_act": "year_vtg"}, inplace=True) + + cap_fact_parent_combined = pd.concat([cap_fact_parent1, cap_fact_parent2]) + cap_fact_parent_combined.rename( + columns={"value": "cap_fact", "technology": "utype"}, inplace=True + ) + + # Parameter names to expand + param_names = [ + "historical_activity", + "historical_new_capacity", + "initial_activity_up", + "initial_activity_lo", + "initial_new_capacity_up", + "soft_activity_up", + # "soft_activity_lo", #causes infeasibilty. + "soft_new_capacity_up", + "level_cost_activity_soft_up", + "level_cost_activity_soft_lo", + # "growth_activity_lo", #cause infeasibility + "growth_activity_up", + "growth_new_capacity_up", + ] + + # Parameters that need multiplier application + multip_list = [ + "historical_activity", + "historical_new_capacity", + "initial_activity_up", + "initial_activity_lo", + "initial_new_capacity_up", + ] + + # Extract parameters from parent technologies + list_params = [ + (scenario.par(p, {"technology": cooling_df["parent_tech"]}), p) + for p in param_names + ] + + # Cooling technology suffixes + suffixes = ["__ot_fresh", "__cl_fresh", "__air", "__ot_saline"] + + # Expand each parameter across cooling variants + for df, param_name in list_params: + df_param = pd.DataFrame() + for suffix in suffixes: + df_add = df.copy() + df_add["technology"] = df_add["technology"] + suffix + df_param = pd.concat([df_param, df_add]) + + # Apply multipliers if needed + df_param_share = ( + apply_act_cap_multiplier( + df_param, hold_cost, cap_fact_parent_combined, param_name + ) + if param_name in multip_list + else df_param + ) + + # Special handling for growth parameters on saline technologies + if param_name in ["growth_new_capacity_up", "growth_activity_up"]: + df_param_share.loc[ + df_param_share["technology"].str.endswith("__ot_saline"), "value" + ] = 1e-3 + + results[param_name] = df_param_share + + return results + + +def cooling_fr(x: pd.Series) -> float: + """Calculate cooling fraction + + Returns + ------- + The calculated cooling fraction after for two categories; + 1. Technologies that produce heat as an output + cooling_fraction(h_cool) = input value(hi) - 1 + Simply subtract 1 from the heating value since the rest of the part is already + accounted in the heating value + 2. Rest of technologies + h_cool = hi -Hi* h_fg - 1, + where: + h_fg (flue gasses losses) = 0.1 (10% assumed losses) + """ + try: + if "hpl" in x["parent_tech"]: + return x["value"] - 1 + else: + return x["value"] - (x["value"] * 0.1) - 1 + except KeyError: + return x["value"] - (x["value"] * 0.1) - 1 + + +def shares( + x: pd.Series, + context: "Context", + search_cols_cooling_fraction: list, + hold_df: pd.DataFrame, + search_cols: list, +) -> pd.Series: + """Process share and cooling fraction. + + Returns + ------- + Product of value of shares of cooling technology types of regions with + corresponding cooling fraction + """ + for col in search_cols_cooling_fraction: + col2 = context.map_ISO_c[col] if context.type_reg == "country" else col + + # Filter the cooling fraction + cooling_fraction = hold_df[ + (hold_df["node_loc"] == col2) + & (hold_df["technology_name"] == x["technology"]) + ]["cooling_fraction"] + + # Log unmatched rows + if cooling_fraction.empty: + log.info( + f"No cooling_fraction found for node_loc: {col2}, " + f"technology: {x['technology']}" + ) + cooling_fraction = pd.Series([0]) + + # Ensure the Series is not empty before accessing its first element + # # Default to 0 if cooling_fraction is empty + x[col] = ( + x[col] * cooling_fraction.iloc[0] + if not cooling_fraction.empty + else x[col] * 0 + ) + + # Construct the output + results = [] + for i in x: + if isinstance(i, str): + results.append(i) + else: + results.append(float(i) if not isinstance(i, pd.Series) else i.iloc[0]) + + return pd.Series(results, index=search_cols) + + +def apply_act_cap_multiplier( + df: pd.DataFrame, + hold_cost: pd.DataFrame, + cap_fact_parent: Optional[pd.DataFrame] = None, + param_name: str = "", +) -> pd.DataFrame: + """ + Generalized function to apply hold_cost factors and optionally divide by cap factor. + hold cost contain the share per cooling technologies and their activity factors + compared to parent technologies. + + Parameters + ---------- + df : pd.DataFrame + The input dataframe in long format, containing 'node_loc', 'technology', and + 'value'. + hold_cost : pd.DataFrame + DataFrame with 'utype', region-specific multipliers (wide format), and + 'technology'. + cap_fact_parent : pd.DataFrame, optional + DataFrame with capacity factors, used only if 'capacity' is in param_name. + param_name : str, optional + The name of the parameter being processed. + + Returns + ------- + pd.DataFrame + The modified dataframe. + """ + + # Melt hold_cost to long format + hold_cost_long = hold_cost.melt( + id_vars=["utype", "technology"], var_name="node_loc", value_name="multiplier" + ) + + # Merge and apply hold_cost multipliers: share * addon_factor + # ACT,c = ACT,p * share * addon_factor + df = df.merge(hold_cost_long, how="left") + df["value"] *= df["multiplier"] + + # filter with value > 0 + df = df[df["value"] > 0] + + # If parameter is capacity-related, multiply by cap_fact + # CAP,c * cf,c(=1) = CAP,p * share * addon_factor * cf,p + if "capacity" in param_name and cap_fact_parent is not None: + df = df.merge(cap_fact_parent, how="left") + df["value"] *= df["cap_fact"] * 1.2 # flexibility + df.drop(columns="cap_fact", inplace=True) + # remove if there are Nan values, but write a log that inform on the parameter and + # the head of the data + # Identify missing or invalid values + missing_values = ( + df["value"].isna() + | (df["value"] == "") + | (df["value"].astype(str).str.strip() == "") + ) + + if missing_values.any(): + print("diobo") + log.warning( + f"Missing or empty values found in {param_name}.head(1):\n" + f"{df[missing_values].head(1)}" + ) + df = df[~missing_values] # Remove rows with missing/empty values + + df.drop(columns=["utype", "multiplier"], inplace=True) + + return df + + +def cooling_shares_SSP_from_yaml( + context: "Context", # Aligning with the style of the functions provided +) -> pd.DataFrame: + """ + Populate a DataFrame for 'share_commodity_up' from a YAML configuration file. + + Parameters + ---------- + context : Context + Context object containing SSP information (e.g., context.SSP) + + Returns + ------- + pd.DataFrame + A DataFrame populated with values from the YAML configuration file. + """ + # Load the YAML file + FILE = "ssp.yaml" + yaml_file_path = package_data_path("water", FILE) + try: + with open(yaml_file_path, "r") as file: + yaml_data = yaml.safe_load(file) + except FileNotFoundError: + log.warning(f"YAML file '{FILE}' not found. Please, check your data.") + + # Read the SSP from the context + ssp = context.ssp + + # Navigate to the scenarios section in the YAML file + macro_regions_data = yaml_data.get("macro-regions", {}) + scenarios = yaml_data.get("scenarios", {}) + + # Validate that the SSP exists in the YAML data + if ssp not in scenarios: + log.warning( + f"SSP '{ssp}' not found in the 'scenarios' section of the YAML file." + ) + return pd.DataFrame() # Extract data for the specified SSP ssp_data = scenarios[ssp]["cooling_tech"] @@ -284,7 +971,8 @@ def cooling_shares_SSP_from_yaml( def _add_saline_extract_bounds(results: dict, info) -> None: - """Add dynamic bound_activity_up for extract_salinewater_cool based on historical saline cooling demand. + """Add dynamic bound_activity_up for extract_salinewater_cool based on + historical saline cooling demand. Parameters ---------- @@ -419,298 +1107,36 @@ def cool_tech( ---------- context : .Context scenario : .Scenario, optional - Scenario to use. If not provided, uses context.get_scenario(). - - Returns - ------- - data : dict of (str -> pandas.DataFrame) - Keys are MESSAGE parameter names such as 'input', 'fix_cost'. - Values are data frames ready for :meth:`~.Scenario.add_par`. - Years in the data include the model horizon indicated by - ``context["water build info"]``, plus the additional year 2010. - """ - #: Name of the input file. - # The input file mentions water withdrawals and emission heating fractions for - # cooling technologies alongwith parent technologies: - FILE = "tech_water_performance_ssp_msg.csv" - # Investment costs & regional shares of hist. activities of cooling - # technologies - FILE1 = ( - "cooltech_cost_and_shares_" - + (f"ssp_msg_{context.regions}" if context.type_reg == "global" else "country") - + ".csv" - ) - - # define an empty dictionary - results = {} - - # Reference to the water configuration - info = context["water build info"] - sub_time = context.time - - # reading basin_delineation - FILE2 = f"basins_by_region_simpl_{context.regions}.csv" - PATH = package_data_path("water", "delineation", FILE2) - - df_node = pd.read_csv(PATH) - # Assigning proper nomenclature - df_node["node"] = "B" + df_node["BCU_name"].astype(str) - df_node["mode"] = "M" + df_node["BCU_name"].astype(str) - df_node["region"] = ( - context.map_ISO_c[context.regions] - if context.type_reg == "country" - else f"{context.regions}_" + df_node["REGION"].astype(str) - ) - - node_region = df_node["region"].unique() - # reading ppl cooling tech dataframe - path = package_data_path("water", "ppl_cooling_tech", FILE) - df = pd.read_csv(path) - cooling_df = df.loc[df["technology_group"] == "cooling"].copy() - # Separate a column for parent technologies of respective cooling - # techs - cooling_df["parent_tech"] = ( - cooling_df["technology_name"] - .apply(lambda x: pd.Series(str(x).split("__"))) - .drop(columns=1) - ) - - scen = scenario or context.get_scenario() - - # Extracting input database from scenario for parent technologies - ref_input = scen.par("input", {"technology": cooling_df["parent_tech"]}) - # list of tec in cooling_df["parent_tech"] that are not in ref_input - missing_tec = cooling_df["parent_tech"][ - ~cooling_df["parent_tech"].isin(ref_input["technology"]) - ] - # some techs only have output, like csp - ref_output = scen.par("output", {"technology": missing_tec}) - # set columns names of ref_output to be the same as ref_input - ref_output.columns = ref_input.columns - # merge ref_input and ref_output - ref_input = pd.concat([ref_input, ref_output]) - - ref_input[["value", "level"]] = ref_input.apply(missing_tech, axis=1) - - # Combines the input df of parent_tech with water withdrawal data - input_cool = ( - cooling_df.set_index("parent_tech") - .combine_first(ref_input.set_index("technology")) - .reset_index() - ) - - # Drops NA values from the value column - input_cool = input_cool.dropna(subset=["value"]) - - # Convert year values into integers to be compatibel for model - input_cool.year_vtg = input_cool.year_vtg.astype(int) - input_cool.year_act = input_cool.year_act.astype(int) - - # Fix invalid year combinations (year_act < year_vtg) using proper vintage-active combinations - year_combinations = get_vintage_and_active_years( - info, technical_lifetime=30, same_year_only=False - ) - - # Create a mapping of valid year combinations - valid_years = set(zip(year_combinations["year_vtg"], year_combinations["year_act"])) - - # Filter input_cool to only include valid year combinations - input_cool_valid_mask = input_cool.apply( - lambda row: (int(row["year_vtg"]), int(row["year_act"])) in valid_years, axis=1 - ) - input_cool = input_cool[input_cool_valid_mask] - # Drops extra technologies from the data. backwards compatibility - input_cool = input_cool[ - (input_cool["level"] != "water_supply") & (input_cool["level"] != "cooling") - ] - # heat plants need no cooling - input_cool = input_cool[ - ~input_cool["technology_name"].str.contains("hpl", na=False) - ] - # Swap node_loc if node_loc equals "{context.regions}_GLB" - input_cool.loc[input_cool["node_loc"] == f"{context.regions}_GLB", "node_loc"] = ( - input_cool["node_origin"] - ) - # Swap node_origin if node_origin equals "{context.regions}_GLB" - input_cool.loc[ - input_cool["node_origin"] == f"{context.regions}_GLB", "node_origin" - ] = input_cool["node_loc"] - - input_cool["cooling_fraction"] = input_cool.apply(cooling_fr, axis=1) - - # Converting water withdrawal units from m^3/GJ to MCM/GWa - # this refers to activity per cooling requirement (heat) - input_cool["value_cool"] = ( - input_cool["water_withdrawal_mid_m3_per_output"] - * m3_GJ_TO_MCM_GWa - / input_cool["cooling_fraction"] - ) - # set to 1e-6 if value_cool is negative - input_cool["value_cool"] = np.where( - input_cool["value_cool"] < 0, 1e-6, input_cool["value_cool"] - ) - input_cool["return_rate"] = 1 - ( - input_cool["water_consumption_mid_m3_per_output"] - / input_cool["water_withdrawal_mid_m3_per_output"] - ) - # consumption to be saved in emissions rates for reporting purposes - input_cool["consumption_rate"] = ( - input_cool["water_consumption_mid_m3_per_output"] - / input_cool["water_withdrawal_mid_m3_per_output"] - ) - - input_cool["value_return"] = input_cool["return_rate"] * input_cool["value_cool"] - - # only for reporting purposes - input_cool["value_consumption"] = ( - input_cool["consumption_rate"] * input_cool["value_cool"] - ) - - # Filter out technologies that requires parasitic electricity - electr = input_cool[input_cool["parasitic_electricity_demand_fraction"] > 0.0] - - # Make a new column 'value_cool' for calculating values against technologies - electr["value_cool"] = ( - electr["parasitic_electricity_demand_fraction"] / electr["cooling_fraction"] - ) - # set to 1e-6 if value_cool is negative - electr["value_cool"] = np.where( - electr["value_cool"] < 0, 1e-6, electr["value_cool"] - ) - # Filters out technologies requiring saline water supply - saline_df = input_cool[ - input_cool["technology_name"].str.endswith("ot_saline", na=False) - ] - - # input_cool_minus_saline_elec_df - con1 = input_cool["technology_name"].str.endswith("ot_saline", na=False) - con2 = input_cool["technology_name"].str.endswith("air", na=False) - icmse_df = input_cool[(~con1) & (~con2)] - # electricity inputs - inp = make_df( - "input", - node_loc=electr["node_loc"], - technology=electr["technology_name"], - year_vtg=electr["year_vtg"], - year_act=electr["year_act"], - mode=electr["mode"], - node_origin=electr["node_origin"], - commodity="electr", - level="secondary", - time="year", - time_origin="year", - value=electr["value_cool"], - unit="GWa", - ) - # once through and closed loop freshwater - inp = pd.concat( - [ - inp, - make_df( - "input", - node_loc=icmse_df["node_loc"], - technology=icmse_df["technology_name"], - year_vtg=icmse_df["year_vtg"], - year_act=icmse_df["year_act"], - mode=icmse_df["mode"], - node_origin=icmse_df["node_origin"], - commodity="surfacewater", - level="water_supply", - time="year", - time_origin="year", - value=icmse_df["value_cool"], - unit="MCM/GWa", - ), - ] - ) - # saline cooling technologies - inp = pd.concat( - [ - inp, - make_df( - "input", - node_loc=saline_df["node_loc"], - technology=saline_df["technology_name"], - year_vtg=saline_df["year_vtg"], - year_act=saline_df["year_act"], - mode=saline_df["mode"], - node_origin=saline_df["node_origin"], - commodity="saline_ppl", - level="saline_supply", - time="year", - time_origin="year", - value=saline_df["value_cool"], - unit="MCM/GWa", - ), - ] - ) - - # Drops NA values from the value column - inp = inp.dropna(subset=["value"]) - - # append the input data to results - results["input"] = inp - - # add water consumption as emission factor, also for saline tecs - emiss_df = input_cool[(~con2)] - emi = make_df( - "emission_factor", - node_loc=emiss_df["node_loc"], - technology=emiss_df["technology_name"], - year_vtg=emiss_df["year_vtg"], - year_act=emiss_df["year_act"], - mode=emiss_df["mode"], - emission="fresh_return", - value=emiss_df["value_return"], - unit="MCM/GWa", - ) - - results["emission_factor"] = emi - - # add output for share contraints to introduce SSP assumptions - # also in the nexus case, the share contraints are at the macro-regions - - out = make_df( - "output", - node_loc=input_cool["node_loc"], - technology=input_cool["technology_name"], - year_vtg=input_cool["year_vtg"], - year_act=input_cool["year_act"], - mode=input_cool["mode"], - node_dest=input_cool["node_origin"], - commodity=input_cool["technology_name"].str.split("__").str[1], - level="share", - time="year", - time_dest="year", - value=1, - unit="-", - ) - - # Add water return flows output from fresh cooling technologies to reg_to_basin - # Fresh cooling technologies output their return flows to reg_to_basin technology - out_return = make_df( - "output", - node_loc=icmse_df["node_loc"], - technology=icmse_df["technology_name"], - year_vtg=icmse_df["year_vtg"], - year_act=icmse_df["year_act"], - mode=icmse_df["mode"], - node_dest=icmse_df["node_origin"], - commodity="water_return", - level="water_supply", - time="year", - time_dest="year", - value=icmse_df["value_return"], - unit="MCM/GWa", - ) + Scenario to use. If not provided, uses context.get_scenario(). - # Combine all outputs (share constraints + return flows) - out = pd.concat([out, out_return]) + Returns + ------- + data : dict of (str -> pandas.DataFrame) + Keys are MESSAGE parameter names such as 'input', 'fix_cost'. + Values are data frames ready for :meth:`~.Scenario.add_par`. + Years in the data include the model horizon indicated by + ``context["water build info"]``, plus the additional year 2010. + """ + # Get water build info + info = context["water build info"] - # in any case save out into results - results["output"] = out + # Step 1: Load all cooling data files and scenario parameters + cooling_data = _load_cooling_data(context, scenario) + + # Step 2: Process and clean cooling technology data + processed_data = _process_cooling_data(cooling_data, context, info) + + # Step 3: Process share constraints and historical data backfilling + share_data = _process_share_constraints( + processed_data["input_cool"], cooling_data["cost_share_path"], context + ) + + # Step 4: Create basic MESSAGEix parameters + results = _create_cooling_parameters( + processed_data, cooling_data["node_region"], context, info + ) - # Create reg_to_basin technology for distributing return flows to basins + # Step 5: Handle nexus-specific logic (basin-region distribution) if context.nexus_set == "nexus": # Get basin-region mapping df_sw = map_basin_region_wat(context) @@ -721,72 +1147,66 @@ def cool_tech( ) df_sw["time_dest"] = df_sw["time_dest"].astype(str) - # Use get_vintage_and_active_years() with tl=10 and same_year_only=True year_combinations = get_vintage_and_active_years( info, technical_lifetime=1, same_year_only=True ) - # reg_to_basin technology inputs (receives return flows) + # Create reg_to_basin technology for distributing return flows reg_to_basin_input = make_df( "input", technology="reg_to_basin", - node_loc=node_region, + node_loc=cooling_data["node_region"], commodity="water_return", level="water_supply", time="year", time_origin="year", - node_origin=node_region, + node_origin=cooling_data["node_region"], value=1, unit="MCM/GWa", mode="M1", ).pipe(broadcast, year_combinations) - # reg_to_basin technology outputs (distributes to basins) - # Create base output dataframe - reg_to_basin_output_list = [] - for region in node_region: - # Extract region code from node_loc (e.g., "R12_AFR" -> "AFR") + reg_to_basin_output_list = [] + for region in cooling_data["node_region"]: region_code = region.split("_")[-1] - - # Filter df_sw to only basins that match this region code matching_basins = df_sw[ df_sw["node_dest"].str.contains(region_code, na=False) ] - if not matching_basins.empty: - region_output = ( - make_df( - "output", - technology="reg_to_basin", - node_loc=region, - commodity="surfacewater_basin", - level="water_avail_basin", - time="year", - time_dest="year", - value=1, - unit="MCM/GWa", - mode="M1", - ) - .pipe(broadcast, year_combinations) - .pipe(broadcast, node_dest=matching_basins["node_dest"].unique()) - .merge( - matching_basins.drop_duplicates(["node_dest"])[ - ["node_dest", "share"] - ], - on="node_dest", - how="left", - ) + if matching_basins.empty: + continue + + region_output = ( + make_df( + "output", + technology="reg_to_basin", + node_loc=region, + commodity="surfacewater_basin", + level="water_avail_basin", + time="year", + time_dest="year", + value=1, + unit="MCM/GWa", + mode="M1", + ) + .pipe(broadcast, year_combinations) + .pipe(broadcast, node_dest=matching_basins["node_dest"].unique()) + .merge( + matching_basins.drop_duplicates(["node_dest"])[ + ["node_dest", "share"] + ], + on="node_dest", + how="left", ) - reg_to_basin_output_list.append(region_output) + ) + reg_to_basin_output_list.append(region_output) - # Combine all region outputs reg_to_basin_output = ( pd.concat(reg_to_basin_output_list, ignore_index=True) if reg_to_basin_output_list else pd.DataFrame() ) - # Apply basin availability shares to reg_to_basin outputs reg_to_basin_output["value"] = ( reg_to_basin_output["value"] * reg_to_basin_output["share"] ) @@ -794,193 +1214,14 @@ def cool_tech( subset=["value"] ) - # Add reg_to_basin parameters to results + # Add nexus parameters to results results["input"] = pd.concat([results["input"], reg_to_basin_input]) results["output"] = pd.concat([results["output"], reg_to_basin_output]) - # costs and historical parameters - path1 = package_data_path("water", "ppl_cooling_tech", FILE1) - cost = pd.read_csv(path1) - # Combine technology name to get full cooling tech names - cost["technology"] = cost["utype"] + "__" + cost["cooling"] - cost["share"] = cost["utype"] + "_" + cost["cooling"] - - # add contraint with relation, based on shares - # Keep only "utype", "technology", and columns starting with "mix_" - share_filtered = cost.loc[ - :, - ["utype", "share"] + [col for col in cost.columns if col.startswith("mix_")], - ] - - # Melt to long format - share_long = share_filtered.melt( - id_vars=["utype", "share"], var_name="node_share", value_name="value" - ) - # filter with uypt in cooling_df["parent_tech"] - share_long = share_long[ - share_long["utype"].isin(input_cool["parent_tech"].unique()) - ].reset_index(drop=True) - - # Remove "mix_" prefix from region names - share_long["node_share"] = share_long["node_share"].str.replace( - "mix_", "", regex=False - ) - # Replace 0 values with 0.0001 - share_long["value"] = share_long["value"] * 1.05 # give some flexibility - share_long["value"] = share_long["value"].replace(0, 0.0001) - - share_long["shares"] = "share_calib_" + share_long["share"] - share_long.drop(columns={"utype", "share"}, inplace=True) - # restore cost as it was for future use - cost.drop(columns="share", inplace=True) - share_long["time"] = "year" - share_long["unit"] = "-" - # FIXME : Temporarily commenting out share calib constraints. - # Causes 4X size explosion. Likely problematic. - # share_calib = share_long.copy() - # # Expand for years [2020, 2025] - # share_calib = share_calib.loc[share_calib.index.repeat(2)].reset_index(drop=True) - # years_calib = [2020, 2025] - # share_calib["year_act"] = years_calib * (len(share_calib) // 2) - # # take year in info.N but not years_calib - # years_fut = [year for year in info.Y if year not in years_calib] - # share_fut = share_long.copy() - # share_fut = share_fut.loc[share_fut.index.repeat(len(years_fut))].reset_index( - # drop=True - # ) - # share_fut["year_act"] = years_fut * (len(share_fut) // len(years_fut)) - # # filter only shares that contain "ot_saline" - # share_fut = share_fut[share_fut["shares"].str.contains("ot_saline")] - # # if value < 0.4 set to 0.4, not so allow too much saline where there is no - # share_fut["value"] = np.where(share_fut["value"] < 0.45, 0.45, share_fut["value"]) - # # keep only after 2050 - # share_fut = share_fut[share_fut["year_act"] >= 2050] - # # append share_calib and (share_fut only to add constraints on ot_saline) - # results["share_commodity_up"] = pd.concat([share_calib]) - - # Filtering out 2015 data to use for historical values - input_cool_2015 = input_cool[ - (input_cool["year_act"] == 2015) & (input_cool["year_vtg"] == 2015) - ] - # set of parent_tech and node_loc for input_cool - input_cool_set = set(zip(input_cool["parent_tech"], input_cool["node_loc"])) - year_list = [2020, 2010, 2030, 2050, 2000, 2080, 1990] - - for year in year_list: - log.debug(f"cool_tech() for year '{year}'") - # Identify missing combinations in the current aggregate - input_cool_2015_set = set( - # FIXME : This should have been a one off script for debugging. - zip(input_cool_2015["parent_tech"], input_cool_2015["node_loc"]) - ) - missing_combinations = input_cool_set - input_cool_2015_set - - if not missing_combinations: - break # Stop if no missing combinations remain - - # Extract missing rows from input_cool with the current year - missing_rows = input_cool[ - (input_cool["year_act"] == year) - & (input_cool["year_vtg"] == year) - & input_cool.apply( - lambda row: (row["parent_tech"], row["node_loc"]) - in missing_combinations, - axis=1, - ) - ] - - if not missing_rows.empty: - # Modify year columns to 2015 - missing_rows = missing_rows.copy() - missing_rows["year_act"] = 2015 - missing_rows["year_vtg"] = 2015 - - # Append to the aggregated dataset - input_cool_2015 = pd.concat( - [input_cool_2015, missing_rows], ignore_index=True - ) - - # Final check if there are still missing combinations - input_cool_2015_set = set( - # FIXME : This should have been a one off script for debugging. - zip(input_cool_2015["parent_tech"], input_cool_2015["node_loc"]) - ) - still_missing = input_cool_set - input_cool_2015_set - - if still_missing: - log.warning( - f"Warning: Some combinations are still missing even after trying all " - f"years: {still_missing}" - ) - - # Filter out columns that contain 'mix' in column name - # Rename column names to match with the previous df - cost.rename(columns=lambda name: name.replace("mix_", ""), inplace=True) - search_cols = [ - col - for col in cost.columns - if context.regions in col or col in ["technology", "utype"] - ] - hold_df = input_cool_2015[ - ["node_loc", "technology_name", "cooling_fraction"] - ].drop_duplicates() - search_cols_cooling_fraction = [ - col for col in search_cols if col not in ["technology", "utype"] - ] - # multiplication factor with cooling factor and shares - hold_cost = cost[search_cols].apply( - shares, - axis=1, - context=context, - search_cols_cooling_fraction=search_cols_cooling_fraction, - hold_df=hold_df, - search_cols=search_cols, - ) - - # hist cap to be divided by cap_factor of the parent tec - cap_fact_parent = scen.par( - "capacity_factor", {"technology": cooling_df["parent_tech"]} - ) - # cap_fact_parent = cap_fact_parent[ - # (cap_fact_parent["node_loc"] == "R12_NAM") - # & (cap_fact_parent["technology"] == "coal_ppl_u") # nuc_lc - # ] - # keep node_loc, technology , year_vtg and value - cap_fact_parent1 = cap_fact_parent[ - ["node_loc", "technology", "year_vtg", "value"] - ].drop_duplicates() - cap_fact_parent1 = cap_fact_parent1[ - cap_fact_parent1["year_vtg"] < scen.firstmodelyear - ] - # group by "node_loc", "technology", "year_vtg" and get the minimum value - cap_fact_parent1 = cap_fact_parent1.groupby( - ["node_loc", "technology", "year_vtg"], as_index=False - ).min() - # filter for values that have year_act < sc.firstmodelyear - - # in some cases the capacity parameters are used with year_all - # (e.g. initial_new_capacity_up). need year_Act for this - cap_fact_parent2 = cap_fact_parent[ - ["node_loc", "technology", "year_act", "value"] - ].drop_duplicates() - cap_fact_parent2 = cap_fact_parent2[ - cap_fact_parent2["year_act"] >= scen.firstmodelyear - ] - # group by "node_loc", "technology", "year_vtg" and get the minimum value - cap_fact_parent2 = cap_fact_parent2.groupby( - ["node_loc", "technology", "year_act"], as_index=False - ).min() - cap_fact_parent2.rename(columns={"year_act": "year_vtg"}, inplace=True) - - cap_fact_parent = pd.concat([cap_fact_parent1, cap_fact_parent2]) - - # rename value to cap_fact - cap_fact_parent.rename( - columns={"value": "cap_fact", "technology": "utype"}, inplace=True - ) + # Step 6: Add investment cost projections + from message_ix_models.tools.costs.config import MODULE, Config + from message_ix_models.tools.costs.projections import create_cost_projections - # Manually removing extra technologies not required - # TODO make it automatic to not include the names manually techs_to_remove = [ "mw_ppl__ot_fresh", "mw_ppl__ot_saline", @@ -996,148 +1237,35 @@ def cool_tech( "nuc_htemp__air", ] - from message_ix_models.tools.costs.config import MODULE, Config - from message_ix_models.tools.costs.projections import create_cost_projections - - # Set config for cost projections - # Using GDP method for cost projections cfg = Config( module=MODULE.cooling, scenario=context.ssp, method="gdp", node=context.regions ) - - # Get projected investment and fixed o&m costs cost_proj = create_cost_projections(cfg) - - # Get only the investment costs for cooling technologies inv_cost = cost_proj["inv_cost"][ ["year_vtg", "node_loc", "technology", "value", "unit"] ] - - # Remove technologies that are not required inv_cost = inv_cost[~inv_cost["technology"].isin(techs_to_remove)] - - # Only keep cooling module technologies by filtering for technologies with "__" inv_cost = inv_cost[inv_cost["technology"].str.contains("__")] - - # Add the investment costs to the results results["inv_cost"] = inv_cost - # Addon conversion - adon_df = input_cool.copy() - # Add 'cooling_' before name of parent technologies that are type_addon - # nomenclature - adon_df["tech"] = "cooling__" + adon_df["parent_tech"].astype(str) - # technology : 'parent technology' and type_addon is type of addons such - # as 'cooling__bio_hpl' - addon_df = make_df( - "addon_conversion", - node=adon_df["node_loc"], - technology=adon_df["parent_tech"], - year_vtg=adon_df["year_vtg"], - year_act=adon_df["year_act"], - mode=adon_df["mode"], - time="year", - type_addon=adon_df["tech"], - value=adon_df["cooling_fraction"], - unit="-", # from electricity to thermal - ) - - results["addon_conversion"] = addon_df - - # Addon_lo will remain 1 for all cooling techs so it allows 100% activity of - # parent technologies - addon_lo = make_matched_dfs(addon_df, addon_lo=1) - results["addon_lo"] = addon_lo["addon_lo"] - - # technical lifetime - year = info.yv_ya.year_vtg.drop_duplicates() - year = year[year >= 1990] - - tl = ( - make_df( - "technical_lifetime", - technology=inp["technology"].drop_duplicates(), - value=30, - unit="year", - ) - .pipe(broadcast, year_vtg=year, node_loc=node_region) - .pipe(same_node) + # Step 7: Expand parent technology parameters across cooling variants + expanded_params = _expand_parent_parameters( + cooling_data["scenario"], cooling_data["cooling_df"], share_data["hold_cost"] ) - results["technical_lifetime"] = tl - - results["capacity_factor"] = _compose_capacity_factor(inp=inp, context=context) - - # Extract inand expand some paramenters from parent technologies - # Define parameter names to be extracted - param_names = [ - "historical_activity", - "historical_new_capacity", - "initial_activity_up", - "initial_activity_lo", - "initial_new_capacity_up", - "soft_activity_up", - # "soft_activity_lo", #causes infeasibilty. - "soft_new_capacity_up", - "level_cost_activity_soft_up", - "level_cost_activity_soft_lo", - "growth_activity_lo", - "growth_activity_up", - "growth_new_capacity_up", - ] - - multip_list = [ - "historical_activity", - "historical_new_capacity", - "initial_activity_up", - "initial_activity_lo", - "initial_new_capacity_up", - ] - - # Extract parameters dynamically - list_params = [ - (scen.par(p, {"technology": cooling_df["parent_tech"]}), p) for p in param_names - ] - - # Expand parameters for cooling technologies - suffixes = ["__ot_fresh", "__cl_fresh", "__air", "__ot_saline"] - - for df, param_name in list_params: - df_param = pd.DataFrame() - for suffix in suffixes: - df_add = df.copy() - df_add["technology"] = df_add["technology"] + suffix - df_param = pd.concat([df_param, df_add]) - - df_param_share = ( - apply_act_cap_multiplier(df_param, hold_cost, cap_fact_parent, param_name) - if param_name in multip_list - else df_param - ) - - # Set growth_new_capacity_up to 0 for __ot_saline technologies - if param_name == "growth_new_capacity_up": - df_param_share.loc[ - df_param_share["technology"].str.endswith("__ot_saline"), "value" - ] = 1e-3 - print(f"setting growth up new cap 0 for {df_param_share['technology']}") - if param_name == "growth_activity_up": - df_param_share.loc[ - df_param_share["technology"].str.endswith("__ot_saline"), "value" - ] = 1e-3 - print(f"setting growth up act 0 for {df_param_share['technology']}") + # Merge expanded parameters into results + for param_name, param_df in expanded_params.items(): results[param_name] = pd.concat( - [results.get(param_name, pd.DataFrame()), df_param_share], ignore_index=True + [results.get(param_name, pd.DataFrame()), param_df], ignore_index=True ) - # add share constraints for cooling technologies based on SSP assumptions - df_share = cooling_shares_SSP_from_yaml(context) - - if not df_share.empty: - # pd concat to the existing results["share_commodity_up"] - results["share_commodity_up"] = pd.concat([df_share], ignore_index=True) + # Step 8: Add SSP share constraints + if not share_data["share_constraints"].empty: + results["share_commodity_up"] = pd.concat( + [share_data["share_constraints"]], ignore_index=True + ) - # Add dynamic bound_activity_up for extract_salinewater_cool + # Step 9: Add dynamic saline extraction bounds _add_saline_extract_bounds(results, info) return results From 54699ce165194a81b19aa23a3451d186db3e66f0 Mon Sep 17 00:00:00 2001 From: Vignesh Raghunathan Date: Fri, 26 Sep 2025 12:14:35 +0200 Subject: [PATCH 37/43] Fix filtering --- message_ix_models/model/water/data/water_for_ppl.py | 1 - 1 file changed, 1 deletion(-) diff --git a/message_ix_models/model/water/data/water_for_ppl.py b/message_ix_models/model/water/data/water_for_ppl.py index 9dedd7b05a..6b8c307f72 100644 --- a/message_ix_models/model/water/data/water_for_ppl.py +++ b/message_ix_models/model/water/data/water_for_ppl.py @@ -109,7 +109,6 @@ def _load_cooling_data( # Load and process basin delineation df_node = pd.read_csv(basin_delineation_path) - df_node = df_node[df_node["BCU_name"].isin(context.valid_basins)] # Assign proper nomenclature to basin data df_node["node"] = "B" + df_node["BCU_name"].astype(str) From 3174e7547f807e2bbfd7ab3617d8329190ebd232 Mon Sep 17 00:00:00 2001 From: Vignesh Raghunathan Date: Mon, 29 Sep 2025 16:13:40 +0200 Subject: [PATCH 38/43] Restore feasibility --- .../model/water/data/water_for_ppl.py | 28 +++++++++---------- .../model/water/data/water_supply.py | 5 ++-- 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/message_ix_models/model/water/data/water_for_ppl.py b/message_ix_models/model/water/data/water_for_ppl.py index 6b8c307f72..32ce5a79bd 100644 --- a/message_ix_models/model/water/data/water_for_ppl.py +++ b/message_ix_models/model/water/data/water_for_ppl.py @@ -690,26 +690,26 @@ def _expand_parent_parameters( param_names = [ "historical_activity", "historical_new_capacity", - "initial_activity_up", - "initial_activity_lo", - "initial_new_capacity_up", - "soft_activity_up", - # "soft_activity_lo", #causes infeasibilty. - "soft_new_capacity_up", - "level_cost_activity_soft_up", - "level_cost_activity_soft_lo", - # "growth_activity_lo", #cause infeasibility - "growth_activity_up", - "growth_new_capacity_up", + # "initial_activity_up", + # "initial_activity_lo", + # "initial_new_capacity_up", + # "soft_activity_up", + # # "soft_activity_lo", #causes infeasibilty. + # "soft_new_capacity_up", + # "level_cost_activity_soft_up", + # "level_cost_activity_soft_lo", + # # "growth_activity_lo", #cause infeasibility + # "growth_activity_up", + # "growth_new_capacity_up", ] # Parameters that need multiplier application multip_list = [ "historical_activity", "historical_new_capacity", - "initial_activity_up", - "initial_activity_lo", - "initial_new_capacity_up", + # "initial_activity_up", + # "initial_activity_lo", + # "initial_new_capacity_up", ] # Extract parameters from parent technologies diff --git a/message_ix_models/model/water/data/water_supply.py b/message_ix_models/model/water/data/water_supply.py index bf5aea02d8..31c2a078c4 100644 --- a/message_ix_models/model/water/data/water_supply.py +++ b/message_ix_models/model/water/data/water_supply.py @@ -597,7 +597,6 @@ def add_water_supply(context: "Context") -> dict[str, pd.DataFrame]: ] ) - # Technical lifetime for extract_salinewater_cool saline_water_cool_tl = make_df( "technical_lifetime", @@ -780,7 +779,7 @@ def add_water_supply(context: "Context") -> dict[str, pd.DataFrame]: make_df( "technical_lifetime", technology="extract_surfacewater", - value=50, + value=30, unit="y", ) .pipe(broadcast, year_vtg=year_wat, node_loc=df_node["node"]) @@ -807,7 +806,7 @@ def add_water_supply(context: "Context") -> dict[str, pd.DataFrame]: make_df( "technical_lifetime", technology="extract_gw_fossil", - value=1, # 1 Year TL to further discourage use. + value=5, # 5 Year TL to further discourage use. unit="y", ) .pipe(broadcast, year_vtg=year_wat, node_loc=df_node["node"]) From 94e17940fa406dd9da4a540c20fa66d738c6849a Mon Sep 17 00:00:00 2001 From: Vignesh Raghunathan Date: Tue, 30 Sep 2025 15:17:44 +0200 Subject: [PATCH 39/43] Refactor test --- .../model/water/data/test_infrastructure.py | 561 ++++++------------ 1 file changed, 169 insertions(+), 392 deletions(-) diff --git a/message_ix_models/tests/model/water/data/test_infrastructure.py b/message_ix_models/tests/model/water/data/test_infrastructure.py index 1635cf0657..bd8654b675 100644 --- a/message_ix_models/tests/model/water/data/test_infrastructure.py +++ b/message_ix_models/tests/model/water/data/test_infrastructure.py @@ -1,9 +1,6 @@ import pandas as pd import pytest -from message_ix import Scenario -from message_ix_models import ScenarioInfo -from message_ix_models.model.structure import get_codes from message_ix_models.model.water.data.infrastructure import ( add_desalination, add_infrastructure_techs, @@ -53,20 +50,7 @@ def _get_technology_categories(): def _get_required_columns(function_type): """Get required column definitions for input and output DataFrames.""" - # Common base columns for all function types - base_input_cols = [ - "technology", - "value", - "unit", - "level", - "commodity", - "mode", - "node_loc", - "year_vtg", - "year_act", - ] - - base_output_cols = [ + base_cols = [ "technology", "value", "unit", @@ -79,433 +63,226 @@ def _get_required_columns(function_type): ] if function_type == "infrastructure": - # Infrastructure-specific additions - input_required_cols = base_input_cols + ["time", "time_origin", "node_origin"] - output_required_cols = base_output_cols + ["time", "time_dest", "node_dest"] + input_cols = base_cols + ["time", "time_origin", "node_origin"] + output_cols = base_cols + ["time", "time_dest", "node_dest"] else: # desalination - # Desalination-specific additions - input_required_cols = base_input_cols + ["time_origin", "node_origin"] - output_required_cols = base_output_cols + ["time"] - - return input_required_cols, output_required_cols - - -@pytest.fixture(scope="function") -def water_function_test_data(test_context, request): - """Unified fixture for testing both infrastructure and desalination functions.""" - # Parse test parameters: (function_type, sdg_config) - function_type, sdg_config = request.param - - # Setup test context - if sdg_config: - test_context.SDG = sdg_config - test_context.time = "year" - test_context.type_reg = "country" if function_type == "infrastructure" else "global" - test_context.regions = "R12" - nodes = get_codes(f"node/{test_context.regions}") - nodes = list(map(str, nodes[nodes.index("World")].child)) - test_context.map_ISO_c = {test_context.regions: nodes[0]} - - # Add RCP for desalination - if function_type == "desalination": - test_context.RCP = "6p0" # Use RCP that exists in R12 data - - # Create scenario - mp = test_context.get_platform() - scenario_info = { - "mp": mp, - "model": f"{request.node.name}/test water model", - "scenario": f"{request.node.name}/test water scenario", - "version": "new", - } - s = Scenario(**scenario_info) - s.add_horizon(year=[2020, 2030, 2040]) - s.add_set("technology", ["tech1", "tech2"]) - s.add_set("year", [2020, 2030, 2040]) - s.commit(comment=f"basic water {function_type} test model") + input_cols = base_cols + ["time_origin", "node_origin"] + output_cols = base_cols + ["time"] - test_context.set_scenario(s) - test_context["water build info"] = ScenarioInfo(s) + return input_cols, output_cols - # Call appropriate function - if function_type == "infrastructure": - result = add_infrastructure_techs(context=test_context) - else: # desalination - result = add_desalination(context=test_context) - return { - "result": result, - "function_type": function_type, - "sdg_config": sdg_config, - "context": test_context, - } +def _validate_dataframe(df, df_name, function_type): + """Validate a DataFrame for NaN values, duplicates, and time format.""" + # NaN check + assert not df["value"].isna().any(), ( + f"{function_type}: {df_name} DataFrame contains NaN values" + ) + # Time format validation + if "time" in df.columns: + time_values = df["time"].unique() + invalid_times = [val for val in time_values if len(str(val)) == 1] + assert not invalid_times, ( + f"{function_type}: {df_name} DataFrame has invalid time values: " + f"{invalid_times}" + ) + + # Duplicate detection + duplicates = df.duplicated().sum() + assert duplicates == 0, ( + f"{function_type}: {df_name} DataFrame contains {duplicates} duplicate rows" + ) -@pytest.mark.parametrize( - "water_function_test_data", - [ - ("infrastructure", "baseline"), - ("infrastructure", "not_baseline"), - ("desalination", None), - ], - indirect=True, -) -def test_water_data_structure(water_function_test_data): - """Test for data structure, integrity, and configuration-specific behavior.""" - data = water_function_test_data - result = data["result"] - function_type = data["function_type"] - data["sdg_config"] +# Assertion helper functions + + +def assert_data_structure(result, function_type): + """Test for data structure, integrity, and configuration-specific behavior.""" # Basic structure checks assert isinstance(result, dict), f"{function_type}: Result must be a dictionary" assert "input" in result, f"{function_type}: Result must contain 'input' key" assert "output" in result, f"{function_type}: Result must contain 'output' key" - # Get required columns based on function type - input_required_cols, output_required_cols = _get_required_columns(function_type) - # Column validation - missing_input_cols = set(input_required_cols) - set(result["input"].columns) - assert not missing_input_cols, ( - f"{function_type}: Input DataFrame missing columns: {missing_input_cols}" - ) - - missing_output_cols = set(output_required_cols) - set(result["output"].columns) - assert not missing_output_cols, ( - f"{function_type}: Output DataFrame missing columns: {missing_output_cols}" - ) - - # Data integrity checks - assert not result["input"]["value"].isna().any(), ( - f"{function_type}: Input DataFrame contains NaN values" - ) - assert not result["output"]["value"].isna().any(), ( - f"{function_type}: Output DataFrame contains NaN values" - ) - - # Time format validation (catches single-character time bug) - input_time_values = ( - result["input"]["time"].unique() if "time" in result["input"].columns else [] - ) - invalid_input_times = [val for val in input_time_values if len(str(val)) == 1] - assert not invalid_input_times, ( - f"{function_type}: Input DataFrame has invalid time values: " - f"{invalid_input_times}" - ) + input_cols, output_cols = _get_required_columns(function_type) - output_time_values = ( - result["output"]["time"].unique() if "time" in result["output"].columns else [] - ) - invalid_output_times = [val for val in output_time_values if len(str(val)) == 1] - assert not invalid_output_times, ( - f"{function_type}: Output DataFrame has invalid time values: " - f"{invalid_output_times}" + missing_input = set(input_cols) - set(result["input"].columns) + assert not missing_input, ( + f"{function_type}: Input DataFrame missing columns: {missing_input}" ) - # Duplicate detection - input_duplicates = result["input"].duplicated().sum() - assert input_duplicates == 0, ( - f"{function_type}: Input DataFrame contains {input_duplicates} duplicate rows" + missing_output = set(output_cols) - set(result["output"].columns) + assert not missing_output, ( + f"{function_type}: Output DataFrame missing columns: {missing_output}" ) - output_duplicates = result["output"].duplicated().sum() - assert output_duplicates == 0, ( - f"{function_type}: Output DataFrame contains {output_duplicates} duplicate rows" - ) + # Data integrity validation + _validate_dataframe(result["input"], "Input", function_type) + _validate_dataframe(result["output"], "Output", function_type) -@pytest.mark.parametrize( - "water_function_test_data", - [ - ("infrastructure", "baseline"), - ("infrastructure", "not_baseline"), - ("desalination", None), - ], - indirect=True, -) -def test_water_technology(water_function_test_data): - """Test for technology completeness, data pairing, and catch early return bugs.""" - data = water_function_test_data - result = data["result"] - function_type = data["function_type"] - sdg_config = data["sdg_config"] +def assert_technology_completeness(result, function_type, sdg_config=None): + """Test for technology completeness, data pairing, and mode consistency.""" tech_categories = _get_technology_categories()[function_type] input_techs = set(result["input"]["technology"].unique()) output_techs = set(result["output"]["technology"].unique()) if function_type == "infrastructure": - # Distribution technology completeness (catches early return bug) - expected_dist_techs = set(tech_categories["distribution"]) - missing_dist_input = expected_dist_techs - input_techs - assert ( - not missing_dist_input - ), f"""{function_type}: Distribution technologies missing - from input (early return bug): {missing_dist_input}""" + distribution_techs = set(tech_categories["distribution"]) - # Electric/non-electric pairing - elec_techs = set( - result["input"][result["input"]["commodity"] == "electr"][ - "technology" - ].unique() - ) - non_elec_techs = set( - result["input"][result["input"]["commodity"] != "electr"][ - "technology" - ].unique() + # Distribution technology completeness + missing_dist = distribution_techs - input_techs + assert not missing_dist, ( + f"{function_type}: Distribution technologies missing from input: " + f"{missing_dist}" ) + + # Electric/non-electric pairing + input_df = result["input"] + elec_filter = input_df["commodity"] == "electr" + elec_techs = set(input_df[elec_filter]["technology"].unique()) + non_elec_filter = input_df["commodity"] != "electr" + non_elec_techs = set(input_df[non_elec_filter]["technology"].unique()) missing_non_elec = elec_techs - non_elec_techs - assert ( - not missing_non_elec - ), f"""{function_type}: Technologies with electricity input - missing non-electric input: {missing_non_elec}""" - - # Input/output mode pairing (catches missing Mf inputs bug) - output_tech_modes = { - (row["technology"], row["mode"]) for _, row in result["output"].iterrows() + assert not missing_non_elec, ( + f"{function_type}: Technologies with electricity input missing " + f"non-electric input: {missing_non_elec}" + ) + + # Input/output mode pairing + output_modes = { + (r["technology"], r["mode"]) for _, r in result["output"].iterrows() } - input_tech_modes = { - (row["technology"], row["mode"]) for _, row in result["input"].iterrows() + input_modes = {(r["technology"], r["mode"]) for _, r in result["input"].iterrows()} + missing = { + (t, m) + for t, m in (output_modes - input_modes) + if "extract_salinewater" not in t } - missing_inputs = output_tech_modes - input_tech_modes - if missing_inputs: - missing_by_mode = {} - for tech, mode in missing_inputs: - missing_by_mode.setdefault(mode, []).append(tech) - - error_details = "\\n".join( - [f" {mode} mode: {techs}" for mode, techs in missing_by_mode.items()] + if missing: + by_mode = {} + for tech, mode in missing: + by_mode.setdefault(mode, []).append(tech) + details = "\n".join([f" {mode}: {techs}" for mode, techs in by_mode.items()]) + assert False, ( + f"{function_type}: Output modes missing corresponding inputs:\n{details}" ) - error_msg = f"""{function_type}: Technologies with output modes missing - corresponding input modes:\\n{error_details}""" - - assert False, error_msg - # Mode consistency validation between input and output for infrastructure - if function_type == "infrastructure": - common_techs = input_techs.intersection(output_techs) + # Mode consistency for infrastructure + if function_type == "infrastructure" and sdg_config is not None: distribution_techs = set(tech_categories["distribution"]) - - if common_techs: - for tech in common_techs: - # Distribution technologies should have both M1 and Mf in baseline, - # only Mf in non-baseline - # Non-distribution technologies should only have M1 - if tech in distribution_techs: - expected_modes = ( - {"M1", "Mf"} if sdg_config == "baseline" else {"Mf"} - ) - else: - expected_modes = {"M1"} - - input_modes = set( - result["input"][result["input"]["technology"] == tech][ - "mode" - ].unique() - ) - output_modes = set( - result["output"][result["output"]["technology"] == tech][ - "mode" - ].unique() - ) - - assert input_modes == expected_modes, ( - f"{function_type}: Technology {tech} has incorrect input " - f"modes for {sdg_config} configuration. " - f"Expected: {expected_modes}, Found: {input_modes}" - ) - assert output_modes == expected_modes, ( - f"{function_type}: Technology {tech} has incorrect output " - f"modes for {sdg_config} configuration. " - f"Expected: {expected_modes}, Found: {output_modes}" - ) - - -@pytest.mark.parametrize( - "water_function_test_data", - [ - ("infrastructure", "baseline"), - ("infrastructure", "not_baseline"), - ("desalination", None), - ], - indirect=True, -) -def test_water_parameter(water_function_test_data): - """Test for parameter consistency and technology-specific uniqueness. - - Catches variable reference bugs. - """ - data = water_function_test_data - result = data["result"] - function_type = data["function_type"] - data["sdg_config"] - tech_categories = _get_technology_categories()[function_type] - - # Check for bound constraints in desalination - if function_type == "desalination": - # Check for bound_total_capacity_up - assert "bound_total_capacity_up" in result, ( - "desalination: Missing 'bound_total_capacity_up' constraint" - ) - assert not result["bound_total_capacity_up"].empty, ( - "desalination: 'bound_total_capacity_up' DataFrame is empty" - ) - - # Check for bound_activity_lo - assert "bound_activity_lo" in result, ( - "desalination: Missing 'bound_activity_lo' constraint" - ) - assert not result["bound_activity_lo"].empty, ( - "desalination: 'bound_activity_lo' DataFrame is empty" - ) - - # Check if bound_capacity exists (might be expected but missing) - if "bound_capacity" in result: - assert not result["bound_capacity"].empty, ( - "desalination: 'bound_capacity' DataFrame exists but is empty" - ) - else: - # Note: bound_capacity is not present in the output - # This assertion documents the current behavior - assert "bound_capacity" not in result, ( - "desalination: 'bound_capacity' constraint is missing from output" + for tech in input_techs & output_techs: + is_dist = tech in distribution_techs + is_baseline = sdg_config == "baseline" + expected = ( + {"M1", "Mf"} + if is_dist and is_baseline + else {"Mf"} + if is_dist + else {"M1"} ) - # Variable cost consistency (catches variable reference bug) - if "var_cost" in result and not result["var_cost"].empty: - var_cost_df = result["var_cost"] - tech_cost_patterns = {} + inp_filter = result["input"]["technology"] == tech + inp_modes = set(result["input"][inp_filter]["mode"].unique()) + out_filter = result["output"]["technology"] == tech + out_modes = set(result["output"][out_filter]["mode"].unique()) - for tech in var_cost_df["technology"].unique(): - tech_data = var_cost_df[var_cost_df["technology"] == tech].sort_values( - [col for col in ["node_loc", "year_act"] if col in var_cost_df.columns] - ) - cost_pattern = tuple(tech_data["value"].values) - tech_cost_patterns.setdefault(cost_pattern, []).append(tech) - - shared_patterns = { - pattern: techs - for pattern, techs in tech_cost_patterns.items() - if len(techs) > 1 - } - - if shared_patterns: - # Check against raw CSV data - this is required - raw_data = tech_categories.get("raw_data") - assert raw_data is not None, ( - f"{function_type}: Raw data not available for validation" - ) - assert "var_cost_mid" in raw_data.columns, ( - f"{function_type}: var_cost_mid column missing from raw data" + assert inp_modes == expected, ( + f"{function_type}: {tech} input modes {inp_modes} != " + f"expected {expected} ({sdg_config})" ) - - # Get unique var_cost_mid values from raw data - raw_var_costs = raw_data[["tec", "var_cost_mid"]].dropna() - unique_costs = raw_var_costs.groupby("tec")["var_cost_mid"].first() - - # If all technologies have the same cost in raw data, it's not a bug - if len(unique_costs.unique()) == 1: - # All technologies have the same cost in source data - # this is intentional - pass - else: - # Different costs in source but identical in output - this is a bug - max_shared = max(len(techs) for techs in shared_patterns.values()) - total_techs = len(var_cost_df["technology"].unique()) - - assert max_shared / total_techs < 0.7, ( - f"{function_type}: Variable reference bug detected -" - f"""{max_shared}/{total_techs} technologies - have identical cost patterns""" - f"but source data shows different costs" - ) - - # Technical lifetime consistency (catches stale variable bug) - if "technical_lifetime" in result and not result["technical_lifetime"].empty: - lifetime_df = result["technical_lifetime"] - - if function_type == "infrastructure": - tech_categories = _get_technology_categories()[function_type] - dist_techs = set(tech_categories["distribution"]) - available_dist_techs = dist_techs.intersection( - set(lifetime_df["technology"].unique()) + assert out_modes == expected, ( + f"{function_type}: {tech} output modes {out_modes} != " + f"expected {expected} ({sdg_config})" ) - non_dist_techs = set(lifetime_df["technology"].unique()) - dist_techs - - if len(available_dist_techs) >= 2 and non_dist_techs: - dist_lifetimes = [ - lifetime_df[lifetime_df["technology"] == tech]["value"].iloc[0] - for tech in available_dist_techs - ] - non_dist_lifetime = lifetime_df[ - lifetime_df["technology"] == list(non_dist_techs)[0] - ]["value"].iloc[0] - identical_to_non_dist = sum( - 1 for lt in dist_lifetimes if lt == non_dist_lifetime - ) - assert identical_to_non_dist < len(dist_lifetimes), ( - f"{function_type}: Stale variable bug detected - " - f"""all distribution technologies have lifetime - {non_dist_lifetime} identical to non-distribution technology""" - ) +def assert_parameter_consistency(result, function_type): + """Test for parameter consistency and expected constraints.""" + if function_type == "desalination": + for param in ["bound_total_capacity_up", "bound_activity_lo"]: + assert param in result, f"desalination: Missing '{param}' constraint" + assert not result[param].empty, ( + f"desalination: '{param}' DataFrame is empty" + ) -@pytest.mark.parametrize( - "water_function_test_data", [("infrastructure", "baseline")], indirect=True -) -def test_efficiency_mode_mapping(water_function_test_data): - """Test that Mf mode represents higher efficiency. +def assert_mode_mapping(result, function_type): + """Test that Mf mode represents higher efficiency than M1. - Only tests baseline configuration where both M1 and Mf modes exist. - Since output coefficients now reflect efficiency, Mf should have higher output than M1. + Baseline configuration has both M1 and Mf modes. + Output coefficients should show Mf > M1 for distribution technologies. """ - data = water_function_test_data - result = data["result"] - function_type = data["function_type"] - output_df = result["output"] tech_categories = _get_technology_categories()[function_type] distribution_techs = set(tech_categories["distribution"]) failures = [] - - # Check distribution technologies with both M1 and Mf modes for tech in distribution_techs: - tech_outputs = output_df[output_df["technology"] == tech] - if tech_outputs.empty: + tech_out = output_df[output_df["technology"] == tech] + if tech_out.empty or not {"M1", "Mf"}.issubset(set(tech_out["mode"].unique())): continue - modes = set(tech_outputs["mode"].unique()) - if {"M1", "Mf"}.issubset(modes): - # Get output coefficients for both modes - m1_outputs = tech_outputs[tech_outputs["mode"] == "M1"] - mf_outputs = tech_outputs[tech_outputs["mode"] == "Mf"] - - if not m1_outputs.empty and not mf_outputs.empty: - m1_coeff = m1_outputs["value"].iloc[0] - mf_coeff = mf_outputs["value"].iloc[0] - - # Mf should be more efficient (higher output coefficient) - if mf_coeff <= m1_coeff: - failures.append( - { - "tech": tech, - "m1_coeff": m1_coeff, - "mf_coeff": mf_coeff, - "issue": "Mf output not higher than M1 (efficiency not reflected)", - } - ) - - # Report findings from actual function outputs + m1_val = tech_out[tech_out["mode"] == "M1"]["value"].iloc[0] + mf_val = tech_out[tech_out["mode"] == "Mf"]["value"].iloc[0] + + if mf_val <= m1_val: + failures.append(f"{tech}: M1={m1_val}, Mf={mf_val}") + if failures: - failure_details = "\n".join( - [ - f" {f['tech']}: M1={f['m1_coeff']}, Mf={f['mf_coeff']} - {f['issue']}" - for f in failures - ] - ) + details = "\n ".join(failures) + assert False, f"Mf output should exceed M1 (efficiency):\n {details}" + + +# Test functions + + +@pytest.mark.parametrize( + "water_scenario", + [ + {"regions": "R12", "type_reg": "country", "time": "year", "SDG": "baseline"}, + { + "regions": "R12", + "type_reg": "country", + "time": "year", + "SDG": "not_baseline", + }, + ], + indirect=True, +) +def test_add_infrastructure_techs(water_scenario): + """Test add_infrastructure_techs function with different SDG configurations.""" + context = water_scenario["context"] + result = add_infrastructure_techs(context=context) + + sdg_config = context.SDG + + # Use helper assertions + assert_data_structure(result, "infrastructure") + assert_technology_completeness(result, "infrastructure", sdg_config) + assert_parameter_consistency(result, "infrastructure") + + # Only test mode mapping for baseline configuration + if sdg_config == "baseline": + assert_mode_mapping(result, "infrastructure") - assert False, f"Efficiency mapping violations (output coefficients should show Mf > M1):\n{failure_details}\n\n" + +@pytest.mark.parametrize( + "water_scenario", + [ + {"regions": "R12", "type_reg": "global", "time": "year", "RCP": "7p0"}, + ], + indirect=True, +) +def test_add_desalination(water_scenario): + """Test add_desalination function.""" + context = water_scenario["context"] + result = add_desalination(context=context) + + # Use helper assertions + assert_data_structure(result, "desalination") + assert_technology_completeness(result, "desalination") + assert_parameter_consistency(result, "desalination") From e3a7829e1d12940e6aa65ff2ddb9e174202e48fc Mon Sep 17 00:00:00 2001 From: Vignesh Raghunathan Date: Tue, 30 Sep 2025 15:19:41 +0200 Subject: [PATCH 40/43] Add conftest for water --- .../tests/model/water/conftest.py | 115 ++++++++++++++++++ 1 file changed, 115 insertions(+) create mode 100644 message_ix_models/tests/model/water/conftest.py diff --git a/message_ix_models/tests/model/water/conftest.py b/message_ix_models/tests/model/water/conftest.py new file mode 100644 index 0000000000..58dfbd30d7 --- /dev/null +++ b/message_ix_models/tests/model/water/conftest.py @@ -0,0 +1,115 @@ +"""Common fixtures for water module tests. + +This conftest provides shared fixtures to reduce test boilerplate and ensure +consistent scenario and context setup across water module tests. +""" + +import pandas as pd +import pytest +from message_ix import Scenario + +from message_ix_models import ScenarioInfo +from message_ix_models.model.structure import get_codes +from message_ix_models.util import package_data_path + + +@pytest.fixture(scope="function") +def water_scenario(request, test_context): + """Create a water module test scenario with standardized setup. + + This fixture handles common setup for water module tests: + - Creates a basic scenario with standard sets + - Configures context with water-specific parameters + - Computes nodes from region codelists + - Sets up basin mappings when needed + + Parameters are passed via indirect parametrization: + + @pytest.mark.parametrize( + "water_scenario", + [ + {"regions": "R12", "type_reg": "global", "RCP": "6p0"}, + {"regions": "ZMB", "type_reg": "country", "SDG": "baseline"}, + ], + indirect=True, + ) + def test_something(water_scenario): + scenario = water_scenario["scenario"] + context = water_scenario["context"] + + Supported parameters: + - regions: str, default "R12" (e.g., "R11", "R12", "ZMB", "R14") + - type_reg: str, default "global" (options: "global", "country") + - time: str, default "year" (options: "year", "month") + - RCP: str, optional (e.g., "2p6", "6p0", "7p0", "no_climate") + - REL: str, optional (e.g., "low", "med", "high") + - SDG: str/bool, optional (e.g., "baseline", "not_baseline", "ambitious", True) + - nexus_set: str, optional (e.g., "nexus", "cooling") + - setup_basins: bool, default False - whether to setup valid_basins + + Returns + ------- + dict + Dictionary with keys: + - "scenario": message_ix.Scenario + - "context": message_ix_models.Context + """ + # Extract parameters from request.param or use defaults + if hasattr(request, "param"): + params = request.param if isinstance(request.param, dict) else {} + else: + params = {} + + regions = params.get("regions", "R12") + type_reg = params.get("type_reg", "global") + time = params.get("time", "year") + RCP = params.get("RCP") + REL = params.get("REL") + SDG = params.get("SDG") + nexus_set = params.get("nexus_set") + setup_basins = params.get("setup_basins", False) + + # Setup context + test_context.type_reg = type_reg + test_context.regions = regions + test_context.time = time + + if RCP is not None: + test_context.RCP = RCP + if REL is not None: + test_context.REL = REL + if SDG is not None: + test_context.SDG = SDG + if nexus_set is not None: + test_context.nexus_set = nexus_set + + # Compute nodes from codes + nodes = get_codes(f"node/{regions}") + nodes = list(map(str, nodes[nodes.index("World")].child)) + test_context.map_ISO_c = {regions: nodes[0]} + + # Setup valid basins if requested + if setup_basins: + basin_file = f"basins_by_region_simpl_{regions}.csv" + basin_path = package_data_path("water", "delineation", basin_file) + df_basins = pd.read_csv(basin_path) + test_context.valid_basins = set(df_basins["BCU_name"].astype(str)) + + # Create scenario + mp = test_context.get_platform() + scenario_info = { + "mp": mp, + "model": f"{request.node.name}/test water model", + "scenario": f"{request.node.name}/test water scenario", + "version": "new", + } + s = Scenario(**scenario_info) + s.add_horizon(year=[2020, 2030, 2040]) + s.add_set("technology", ["tech1", "tech2"]) + s.add_set("year", [2020, 2030, 2040]) + s.commit(comment="basic water test model") + + test_context.set_scenario(s) + test_context["water build info"] = ScenarioInfo(s) + + return {"scenario": s, "context": test_context} \ No newline at end of file From 94f4539ac073cc7a021ecb84d4609ccec75745df Mon Sep 17 00:00:00 2001 From: Vignesh Raghunathan Date: Mon, 6 Oct 2025 13:47:35 +0200 Subject: [PATCH 41/43] Handle cooling inp commodity case --- message_ix_models/model/water/data/water_for_ppl.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/message_ix_models/model/water/data/water_for_ppl.py b/message_ix_models/model/water/data/water_for_ppl.py index 32ce5a79bd..b13d4b3108 100644 --- a/message_ix_models/model/water/data/water_for_ppl.py +++ b/message_ix_models/model/water/data/water_for_ppl.py @@ -467,7 +467,9 @@ def _create_cooling_parameters( con2 = processed_data["con2"] results = {} - + commodity_water_inp = ( + "surfacewater" if context.nexus_set == "nexus" else "freshwater" + ) # Create input parameters # Electricity inputs for parasitic demand inp = make_df( @@ -498,7 +500,7 @@ def _create_cooling_parameters( year_act=icmse_df["year_act"], mode=icmse_df["mode"], node_origin=icmse_df["node_origin"], - commodity="surfacewater", + commodity=commodity_water_inp, level="water_supply", time="year", time_origin="year", @@ -1336,13 +1338,16 @@ def non_cooling_tec(context: "Context", scenario=None) -> dict[str, pd.DataFrame # Input dataframe for non cooling technologies # only water withdrawals are being taken # Dedicated freshwater is assumed for simplicity + commodity_water_inp = ( + "surfacewater" if context.nexus_set == "nexus" else "freshwater" + ) inp_n_cool = make_df( "input", technology=n_cool_df_merge["technology"], value=n_cool_df_merge["value_y"], unit="MCM/GWa", level="water_supply", - commodity="surfacewater", + commodity=commodity_water_inp, time_origin="year", mode="M1", time="year", From ffd146e3e6d720edd4f9768abb04766bfbce6ebf Mon Sep 17 00:00:00 2001 From: Vignesh Raghunathan Date: Wed, 8 Oct 2025 13:01:13 +0200 Subject: [PATCH 42/43] Patch back parent cool tech params Add growth up for extract surface water --- .../model/water/data/water_for_ppl.py | 16 ++++++++-------- .../model/water/data/water_supply.py | 10 ++++++++++ 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/message_ix_models/model/water/data/water_for_ppl.py b/message_ix_models/model/water/data/water_for_ppl.py index b13d4b3108..bdd4c347a5 100644 --- a/message_ix_models/model/water/data/water_for_ppl.py +++ b/message_ix_models/model/water/data/water_for_ppl.py @@ -692,26 +692,26 @@ def _expand_parent_parameters( param_names = [ "historical_activity", "historical_new_capacity", - # "initial_activity_up", - # "initial_activity_lo", - # "initial_new_capacity_up", + "initial_activity_up", + "initial_activity_lo", + "initial_new_capacity_up", # "soft_activity_up", # # "soft_activity_lo", #causes infeasibilty. # "soft_new_capacity_up", # "level_cost_activity_soft_up", # "level_cost_activity_soft_lo", # # "growth_activity_lo", #cause infeasibility - # "growth_activity_up", - # "growth_new_capacity_up", + "growth_activity_up", + "growth_new_capacity_up", ] # Parameters that need multiplier application multip_list = [ "historical_activity", "historical_new_capacity", - # "initial_activity_up", - # "initial_activity_lo", - # "initial_new_capacity_up", + "initial_activity_up", + "initial_activity_lo", + "initial_new_capacity_up", ] # Extract parameters from parent technologies diff --git a/message_ix_models/model/water/data/water_supply.py b/message_ix_models/model/water/data/water_supply.py index 31c2a078c4..61a7a5000d 100644 --- a/message_ix_models/model/water/data/water_supply.py +++ b/message_ix_models/model/water/data/water_supply.py @@ -886,6 +886,16 @@ def add_water_supply(context: "Context") -> dict[str, pd.DataFrame]: else: results["var_cost"] = var_cost_fossil + # Add growth constraint for extract_surfacewater (10% annual growth limit) + growth_activity_up = make_df( + "growth_activity_up", + technology="extract_surfacewater", + value=0.1, + unit="-", + ).pipe(broadcast, year_act=year_wat, node_loc=df_node["node"]) + + results["growth_activity_up"] = growth_activity_up + # Remove duplicates and NaN values from all DataFrames in results for key, df in results.items(): results[key] = df.dropna().drop_duplicates().reset_index(drop=True) From 13d1502ec87b99c16bf9ee39b3a102b3ca6f3113 Mon Sep 17 00:00:00 2001 From: Vignesh Raghunathan Date: Wed, 8 Oct 2025 17:11:13 +0200 Subject: [PATCH 43/43] deactivate saline bounds --- message_ix_models/model/water/data/water_for_ppl.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/message_ix_models/model/water/data/water_for_ppl.py b/message_ix_models/model/water/data/water_for_ppl.py index bdd4c347a5..2f27f32280 100644 --- a/message_ix_models/model/water/data/water_for_ppl.py +++ b/message_ix_models/model/water/data/water_for_ppl.py @@ -1267,7 +1267,7 @@ def cool_tech( ) # Step 9: Add dynamic saline extraction bounds - _add_saline_extract_bounds(results, info) + # _add_saline_extract_bounds(results, info) return results