"""Parameter selector variables"""

import os
import math

import pyomo.environ as pyo

from utils.data import get_case_data

def define_sets(m, data):
    """Define sets"""

    # Nodes
    m.OMEGA_N = pyo.Set(initialize=data['S_NODES'])

    # Generators
    m.OMEGA_G = pyo.Set(initialize=data['S_GENERATORS'])

    # AC edges
    m.OMEGA_NM = pyo.Set(initialize=data['S_AC_EDGES'])

    # Sets of branches for which aggregate AC interconnector limits are defined
    m.OMEGA_J = pyo.Set(initialize=data['S_AC_AGGREGATED_EDGES'])

    # HVDC links
    m.OMEGA_H = pyo.Set(initialize=data['S_HVDC_EDGES'])

    # Operating scenarios
    m.OMEGA_S = pyo.Set(initialize=data['S_SCENARIOS'])

    # NEM regions
    m.OMEGA_R = pyo.Set(initialize=data['S_REGIONS'])

    # Branches which constitute AC interconnectors in the network
    m.OMEGA_L = pyo.Set(initialize=data['S_INTERCONNECTORS'])

    # Set of integers used to select discretised baseline
    m.OMEGA_U = pyo.Set(initialize=data['S_BINARY_EXPANSION_INTEGERS'])

    return m

def define_network_parameters(m, data):
    """Define network parameters"""

    # Max voltage angle difference between connected nodes
    m.P_NETWORK_VOLTAGE_ANGLE_MAX_DIFFERENCE = pyo.Param(initialize=float(math.pi / 2), mutable=True)

    # Branch susceptance matrix elements
    m.P_NETWORK_BRANCH_SUSCEPTANCE = pyo.Param(m.OMEGA_NM, initialize=data['P_NETWORK_BRANCH_SUSCEPTANCE'],
                                               mutable=True)

    # HVDC power flow limits
    m.P_NETWORK_HVDC_FORWARD_LIMIT = pyo.Param(m.OMEGA_H, initialize=data['P_NETWORK_HVDC_FORWARD_LIMIT'], mutable=True)
    m.P_NETWORK_HVDC_REVERSE_LIMIT = pyo.Param(m.OMEGA_H, initialize=data['P_NETWORK_HVDC_REVERSE_LIMIT'], mutable=True)

    # Reference node indicator
    m.P_NETWORK_REFERENCE_NODE_INDICATOR = pyo.Param(m.OMEGA_N, initialize=data['P_NETWORK_REFERENCE_NODE_INDICATOR'])

    # HVDC incidence matrix
    m.P_NETWORK_HVDC_INCIDENCE_MAT = pyo.Param(m.OMEGA_N, m.OMEGA_H, initialize=data['P_NETWORK_HVDC_INCIDENCE_MAT'])

    # AC interconnector incidence matrix
    m.P_NETWORK_INTERCONNECTOR_INCIDENCE_MAT = pyo.Param(m.OMEGA_N, m.OMEGA_L,
                                                         initialize=data['P_NETWORK_INTERCONNECTOR_INCIDENCE_MAT'])

    # Aggregate AC interconnector flow limits
    m.P_NETWORK_INTERCONNECTOR_LIMIT = pyo.Param(m.OMEGA_J, initialize=data['P_NETWORK_INTERCONNECTOR_LIMIT'],
                                                 mutable=True)

    # Fixed nodal power injections
    m.P_NETWORK_FIXED_INJECTION = pyo.Param(m.OMEGA_S, m.OMEGA_N, initialize=data['P_NETWORK_FIXED_INJECTION'],
                                            mutable=True)

    # Network demand
    m.P_NETWORK_DEMAND = pyo.Param(m.OMEGA_S, m.OMEGA_N, initialize=data['P_NETWORK_DEMAND'], mutable=True)

    # Proportion of total demand consumed in each region
    m.P_NETWORK_REGION_DEMAND_PROPORTION = pyo.Param(m.OMEGA_S, m.OMEGA_R,
                                                     initialize=data['P_NETWORK_REGION_DEMAND_PROPORTION'])

    # Network graph describing connections between nodes
    m.P_NETWORK_GRAPH = pyo.Param(m.OMEGA_N, initialize=data['P_NETWORK_GRAPH'], within=pyo.Any)

    # Branches associated with each interconnector
    m.P_NETWORK_INTERCONNECTOR_BRANCH_ID_MAP = pyo.Param(m.OMEGA_J,
                                                         initialize=data['P_NETWORK_INTERCONNECTOR_BRANCH_ID_MAP'],
                                                         within=pyo.Any)

    # Mapping between branch IDs and nodes
    m.P_NETWORK_INTERCONNECTOR_BRANCH_NODES_MAP = pyo.Param(
        m.OMEGA_L, initialize=data['P_NETWORK_INTERCONNECTOR_BRANCH_NODES_MAP'], within=pyo.Any)

    # Mapping between HVDC link ID and its respective 'from' and 'to' nodes
    m.P_NETWORK_HVDC_FROM_NODE = pyo.Param(m.OMEGA_H, initialize=data['P_NETWORK_HVDC_FROM_NODE'])
    m.P_NETWORK_HVDC_TO_NODE = pyo.Param(m.OMEGA_H, initialize=data['P_NETWORK_HVDC_TO_NODE'])

    # List of generators assigned to each node
    m.P_NETWORK_NODE_GENERATOR_MAP = pyo.Param(m.OMEGA_N, initialize=data['P_NETWORK_NODE_GENERATOR_MAP'],
                                               within=pyo.Any)

    # Base power
    m.P_NETWORK_BASE_POWER = pyo.Param(initialize=100)

    # Regional reference node IDs for each region
    m.P_REGION_RRN_NODE_MAP = pyo.Param(m.OMEGA_R, initialize=data['P_REGION_RRN_NODE_MAP'])

    return m

def define_scenario_parameters(m, data):
    """Define scenario parameters"""

    # Relative scenario duration
    m.P_SCENARIO_DURATION = pyo.Param(m.OMEGA_S, initialize=data['P_SCENARIO_DURATION'])

    return m

def define_generator_parameters(m, data):
    """Define generator parameters"""

    # Maximum generator output
    m.P_GENERATOR_MAX_OUTPUT = pyo.Param(m.OMEGA_G, initialize=data['P_GENERATOR_MAX_OUTPUT'], mutable=True)

    # Minimum generator output (set to 0)
    m.P_GENERATOR_MIN_OUTPUT = pyo.Param(m.OMEGA_G, initialize=data['P_GENERATOR_MIN_OUTPUT'])

    # Generator short-run marginal costs
    m.P_GENERATOR_SRMC = pyo.Param(m.OMEGA_G, initialize=data['P_GENERATOR_SRMC'], mutable=True)

    # Generator emissions intensities
    m.P_GENERATOR_EMISSIONS_INTENSITY = pyo.Param(m.OMEGA_G, initialize=data['P_GENERATOR_EMISSIONS_INTENSITY'])

    # Node to which generator is assigned
    m.P_GENERATOR_NODE = pyo.Param(m.OMEGA_G, initialize=data['P_GENERATOR_NODE'])

    return m

def define_policy_parameters(m, data):
    """Define policy parameters"""

    # Emissions intensity baseline (fixed)
    m.P_POLICY_FIXED_BASELINE = pyo.Param(initialize=data['P_POLICY_FIXED_BASELINE'], mutable=True)

    # Permit price target
    m.P_POLICY_PERMIT_PRICE_TARGET = pyo.Param(initialize=data['P_POLICY_PERMIT_PRICE_TARGET'], mutable=True)

    # Weighted RRN price target
    m.P_POLICY_WEIGHTED_RRN_PRICE_TARGET = pyo.Param(initialize=data['P_POLICY_WEIGHTED_RRN_PRICE_TARGET'],
                                                     mutable=True)

    return m

def define_big_m_parameters(m):
    """Define Big-M parameters"""

    def m_11_rule(m, g):
        return m.P_GENERATOR_MAX_OUTPUT[g] - m.P_GENERATOR_MIN_OUTPUT[g]

    m.P_M_11 = pyo.Param(m.OMEGA_G, rule=m_11_rule, mutable=True)
    m.P_M_12 = pyo.Param(m.OMEGA_G, initialize=1e3, mutable=True)

    def m_21_rule(m, g):
        return m.P_GENERATOR_MAX_OUTPUT[g] - m.P_GENERATOR_MIN_OUTPUT[g]

    m.P_M_21 = pyo.Param(m.OMEGA_G, rule=m_21_rule, mutable=True)
    m.P_M_22 = pyo.Param(m.OMEGA_G, initialize=1e3, mutable=True)

    m.P_M_31 = pyo.Param(m.OMEGA_NM, initialize=float(math.pi), mutable=True)
    m.P_M_32 = pyo.Param(m.OMEGA_NM, initialize=1e3, mutable=True)

    def m_41_rule(m, j):
        if 'REVERSE' in j:
            new_index = j.replace('REVERSE', 'FORWARD')
        elif 'FORWARD' in j:
            new_index = j.replace('FORWARD', 'REVERSE')
        else:
            raise (Exception('REVERSE / FORWARD not in index name'))
        return m.P_NETWORK_INTERCONNECTOR_LIMIT[j] + m.P_NETWORK_INTERCONNECTOR_LIMIT[new_index]

    m.P_M_41 = pyo.Param(m.OMEGA_J, rule=m_41_rule, mutable=True)
    m.P_M_42 = pyo.Param(m.OMEGA_J, initialize=1e3, mutable=True)

    def m_51_rule(m, h):
        return m.P_NETWORK_HVDC_FORWARD_LIMIT[h] - m.P_NETWORK_HVDC_REVERSE_LIMIT[h]

    m.P_M_51 = pyo.Param(m.OMEGA_H, rule=m_51_rule, mutable=True)
    m.P_M_52 = pyo.Param(m.OMEGA_H, initialize=1e3, mutable=True)

    def m_61_rule(m, h):
        return m.P_NETWORK_HVDC_FORWARD_LIMIT[h] - m.P_NETWORK_HVDC_REVERSE_LIMIT[h]

    m.P_M_61 = pyo.Param(m.OMEGA_H, rule=m_61_rule, mutable=True)
    m.P_M_62 = pyo.Param(m.OMEGA_H, initialize=1e3, mutable=True)

    m.P_M_71 = pyo.Param(initialize=1e4, mutable=True)
    m.P_M_72 = pyo.Param(rule=1e4, mutable=True)

    return m

def define_binary_expansion_parameters(m, data):
    """Parameters used when implementing binary expansion discretisation"""

    # Largest integer for baseline selection parameter index
    m.P_BIN_EXP_U = pyo.Param(initialize=data['P_BINARY_EXPANSION_LARGEST_INTEGER'])

    # Minimum emissions intensity baseline
    m.P_BIN_EXP_MIN_BASELINE = pyo.Param(initialize=float(0.8))

    # Maximum emissions intensity baseline
    m.P_BIN_EXP_MAX_BASELINE = pyo.Param(initialize=float(1.3))

    # Emissions intensity baseline increment
    m.P_BIN_EXP_BASELINE_DELTA = pyo.Param(
        initialize=float((m.P_BIN_EXP_MAX_BASELINE - m.P_BIN_EXP_MIN_BASELINE) / (2 ** m.P_BIN_EXP_U)))

    def two_pow_u_rule(m, u):
        """Parameter equal 2^u used when selecting discretised emissions intensity baseline"""
        return float(2 ** u)

    m.P_BIN_EXP_TWO_POW_U = pyo.Param(m.OMEGA_U, rule=two_pow_u_rule)

    # Big-M parameter used used to ensure Z_1=0 when PSI=0, and Z_1=V_DUAL_PERMIT_MARKET when PSI=1
    m.P_BIN_EXP_L_1 = pyo.Param(initialize=1e3)

    def l_2_rule(m, g):
        """ Big-M parameter used to make Z_2=0 when PSI=0, and Z_2=p when PSI=1"""
        return m.P_GENERATOR_MAX_OUTPUT[g] - m.P_GENERATOR_MIN_OUTPUT[g]

    m.P_BIN_EXP_L_2 = pyo.Param(m.OMEGA_G, rule=l_2_rule)

    return m

def define_parameters(m, data):
    """Define parameters"""

    # Policy, network, and generator parameters
    m = define_policy_parameters(m, data)
    m = define_network_parameters(m, data)
    m = define_generator_parameters(m, data)
    m = define_scenario_parameters(m, data)
    m = define_big_m_parameters(m)

    # Binary expansion parameters
    m = define_binary_expansion_parameters(m, data)

    return m

def define_binary_expansion_variables(m):
    """Binary expansion variables"""

    # Binary variables used to determine discretised emissions intensity baseline choice
    m.V_BIN_EXP_PSI = pyo.Var(m.OMEGA_U, within=pyo.Binary)

    # Composite variable - PSI x tau - used to linearise bi-linear term
    m.V_BIN_EXP_Z_1 = pyo.Var(m.OMEGA_U)

    # Composite variable - PSI x p - used to linearise bi-linear term
    m.V_BIN_EXP_Z_2 = pyo.Var(m.OMEGA_S, m.OMEGA_U * m.OMEGA_G)

    return m

def define_primal_variables(m):
    """Define primal variables"""

    # Generator output
    m.V_PRIMAL_GENERATOR_POWER = pyo.Var(m.OMEGA_S, m.OMEGA_G)

    # HVDC link flow
    m.V_PRIMAL_HVDC_FLOW = pyo.Var(m.OMEGA_S, m.OMEGA_H)

    # Node voltage angle
    m.V_PRIMAL_VOLTAGE_ANGLE = pyo.Var(m.OMEGA_S, m.OMEGA_N)

    return m

def define_dual_variables(m):
    """Define dual variables"""

    # Permit market constraint dual variable
    m.V_DUAL_PERMIT_MARKET = pyo.Var()

    # Min power output constraint dual variable
    m.V_DUAL_MU_1 = pyo.Var(m.OMEGA_S, m.OMEGA_G)

    # Max power output constraint dual variable
    m.V_DUAL_MU_2 = pyo.Var(m.OMEGA_S, m.OMEGA_G)

    # Max voltage angle difference constraint dual variable
    m.V_DUAL_MU_3 = pyo.Var(m.OMEGA_S, m.OMEGA_NM)

    # AC link power flow constraint dual variable
    m.V_DUAL_MU_4 = pyo.Var(m.OMEGA_S, m.OMEGA_J)

    # Min HVDC flow constraint dual variable
    m.V_DUAL_MU_5 = pyo.Var(m.OMEGA_S, m.OMEGA_H)

    # Max HVDC flow constraint dual variable
    m.V_DUAL_MU_6 = pyo.Var(m.OMEGA_S, m.OMEGA_H)

    # Reference node voltage angle constraint dual variable
    m.V_DUAL_NU_1 = pyo.Var(m.OMEGA_S, m.OMEGA_N)

    # Node power balance constraint dual variable
    m.V_DUAL_LAMBDA = pyo.Var(m.OMEGA_S, m.OMEGA_N)

    return m

def define_complementarity_constraint_variables(m):
    """Binary variables used in Big-M linearisation"""

    # Permit market constraint binary variable
    m.V_BINARY_PERMIT_MARKET = pyo.Var(within=pyo.Binary)

    # Min power output binary variable
    m.V_BINARY_GAMMA_1 = pyo.Var(m.OMEGA_S, m.OMEGA_G, within=pyo.Binary)

    # Max power output binary variable
    m.V_BINARY_GAMMA_2 = pyo.Var(m.OMEGA_S, m.OMEGA_G, within=pyo.Binary)

    # Max voltage angle difference binary variable
    m.V_BINARY_GAMMA_3 = pyo.Var(m.OMEGA_S, m.OMEGA_NM, within=pyo.Binary)

    # AC link power flow dual variable
    m.V_BINARY_GAMMA_4 = pyo.Var(m.OMEGA_S, m.OMEGA_J, within=pyo.Binary)

    # Min HVDC flow binary variable
    m.V_BINARY_GAMMA_5 = pyo.Var(m.OMEGA_S, m.OMEGA_H, within=pyo.Binary)

    # Max HVDC flow binary variable
    m.V_BINARY_GAMMA_6 = pyo.Var(m.OMEGA_S, m.OMEGA_H, within=pyo.Binary)

    return m

def define_dummy_variables(m):
    """Dummy variables used as a placeholder in objective function"""

    # Dummy variable used in object feasibility mode objective
    m.V_DUMMY = pyo.Var(bounds=(0, 1))

    # Dummy variables used to target given permit price
    m.V_DUMMY_PERMIT_PRICE_TARGET_X_1 = pyo.Var(within=pyo.NonNegativeReals)
    m.V_DUMMY_PERMIT_PRICE_TARGET_X_2 = pyo.Var(within=pyo.NonNegativeReals)

    # Dummy variables used to minimise difference between average price and price target
    m.V_DUMMY_WEIGHTED_RRN_PRICE_X_1 = pyo.Var(within=pyo.NonNegativeReals)
    m.V_DUMMY_WEIGHTED_RRN_PRICE_X_2 = pyo.Var(within=pyo.NonNegativeReals)

    return m

def define_variables(m):
    """Define model variables"""

    # Define primal and dual variables
    m = define_primal_variables(m)
    m = define_dual_variables(m)

    # Variables used in linearised complementarity constraints
    m = define_complementarity_constraint_variables(m)

    # Variables used in binary expansion formulation
    m = define_binary_expansion_variables(m)

    # Dummy variables that may be used as a placeholder within an objective function
    m = define_dummy_variables(m)

    return m

def define_binary_expansion_expressions(m):
    """Binary expansion expressions"""

    # Discretised emissions intensity baseline value
    m.E_BIN_EXP_DISCRETISED_BASELINE = pyo.Expression(
        expr=m.P_BIN_EXP_MIN_BASELINE + (
                m.P_BIN_EXP_BASELINE_DELTA * sum(m.P_BIN_EXP_TWO_POW_U[u] * m.V_BIN_EXP_PSI[u] for u in m.OMEGA_U))
    )

    return m

def define_price_target_expressions(m):
    """Expressions use to compute price targets"""

    # Total revenue from electricity sales
    m.E_TOTAL_REVENUE = pyo.Expression(
        expr=sum(m.P_SCENARIO_DURATION[s] * m.V_DUAL_LAMBDA[s, n] * m.P_NETWORK_DEMAND[s, n]
                 for s in m.OMEGA_S for n in m.OMEGA_N))

    # Total demand
    m.E_TOTAL_DEMAND = pyo.Expression(expr=sum(m.P_SCENARIO_DURATION[s] * m.P_NETWORK_DEMAND[s, n]
                                               for s in m.OMEGA_S for n in m.OMEGA_N))

    # Average price
    m.E_AVERAGE_ELECTRICITY_PRICE = pyo.Expression(expr=m.E_TOTAL_REVENUE / m.E_TOTAL_DEMAND)

    # Weighted RRN price
    m.E_WEIGHTED_RRN_PRICE = pyo.Expression(
        expr=sum(m.P_SCENARIO_DURATION[s] * m.P_NETWORK_REGION_DEMAND_PROPORTION[s, r]
                 * m.V_DUAL_LAMBDA[s, m.P_REGION_RRN_NODE_MAP[r]] for s in m.OMEGA_S for r in m.OMEGA_R))

    return m

def define_expressions(m):
    """Define expressions"""

    # Binary expansion expressions
    m = define_binary_expansion_expressions(m)

    # Expressions used in price targeting objective functions
    m = define_price_target_expressions(m)

    return m

def define_binary_expansion_constraints(m):
    """Constraints used in binary expansion formulation"""

    # Constraints ensures Z_1=0 when PSI=0 and Z_1=permit_price when PSI=1
    def z_1_constraint_1_rule(m, u):
        return 0 <= m.V_DUAL_PERMIT_MARKET - m.V_BIN_EXP_Z_1[u]

    m.C_Z_1_CONSTRAINT_1 = pyo.Constraint(m.OMEGA_U, rule=z_1_constraint_1_rule)

    def z_1_constraint_2_rule(m, u):
        return m.V_DUAL_PERMIT_MARKET - m.V_BIN_EXP_Z_1[u] <= m.P_BIN_EXP_L_1 * (1 - m.V_BIN_EXP_PSI[u])

    m.C_Z_1_CONSTRAINT_2 = pyo.Constraint(m.OMEGA_U, rule=z_1_constraint_2_rule)

    def z_1_constraint_3_rule(m, u):
        return 0 <= m.V_BIN_EXP_Z_1[u]

    m.C_Z_1_CONSTRAINT_3 = pyo.Constraint(m.OMEGA_U, rule=z_1_constraint_3_rule)

    def z_1_constraint_4_rule(m, u):
        return m.V_BIN_EXP_Z_1[u] <= m.P_BIN_EXP_L_1 * m.V_BIN_EXP_PSI[u]

    m.C_Z_1_CONSTRAINT_4 = pyo.Constraint(m.OMEGA_U, rule=z_1_constraint_4_rule)

    # Constraints ensuring z_2=0 when PSI=0, and z_2=p when PSI=1
    def z_2_constraint_1_rule(m, s, u, g):
        return 0 <= m.V_PRIMAL_GENERATOR_POWER[s, g] - m.V_BIN_EXP_Z_2[s, u, g]

    m.C_Z_2_CONSTRAINT_1 = pyo.Constraint(m.OMEGA_S, m.OMEGA_U * m.OMEGA_G, rule=z_2_constraint_1_rule)

    def z_2_constraint_2_rule(m, s, u, g):
        return m.V_PRIMAL_GENERATOR_POWER[s, g] - m.V_BIN_EXP_Z_2[s, u, g] <= m.P_BIN_EXP_L_2[g] * (
                1 - m.V_BIN_EXP_PSI[u])

    m.C_Z_2_CONSTRAINT_2 = pyo.Constraint(m.OMEGA_S, m.OMEGA_U * m.OMEGA_G, rule=z_2_constraint_2_rule)

    def z_2_constraint_3_rule(m, s, u, g):
        return 0 <= m.V_BIN_EXP_Z_2[s, u, g]

    m.C_Z_2_CONSTRAINT_3 = pyo.Constraint(m.OMEGA_S, m.OMEGA_U * m.OMEGA_G, rule=z_2_constraint_3_rule)

    def z_2_constraint_4_rule(m, s, u, g):
        return m.V_BIN_EXP_Z_2[s, u, g] <= m.P_BIN_EXP_L_2[g] * m.V_BIN_EXP_PSI[u]

    m.C_Z_2_CONSTRAINT_4 = pyo.Constraint(m.OMEGA_S, m.OMEGA_U * m.OMEGA_G, rule=z_2_constraint_4_rule)

    return m

def define_first_order_condition_constraints(m):
    """Define constraints constituting the model's first order conditions"""

    def foc_1_rule(m, s, g):
        """To be activated if baseline is fixed"""
        return (m.P_GENERATOR_SRMC[g]
                + ((m.P_GENERATOR_EMISSIONS_INTENSITY[g] - m.P_POLICY_FIXED_BASELINE) * m.V_DUAL_PERMIT_MARKET)
                - m.V_DUAL_MU_1[s, g]
                + m.V_DUAL_MU_2[s, g]
                - m.V_DUAL_LAMBDA[s, m.P_GENERATOR_NODE[g]] == 0)

    m.C_FOC_1 = pyo.Constraint(m.OMEGA_S, m.OMEGA_G, rule=foc_1_rule)

    def foc_1_linearised_rule(m, s, g):
        """To be activated if baseline is discretised"""
        return (m.P_GENERATOR_SRMC[g]
                + ((m.P_GENERATOR_EMISSIONS_INTENSITY[g] - m.P_BIN_EXP_MIN_BASELINE) * m.V_DUAL_PERMIT_MARKET)
                - (m.P_BIN_EXP_BASELINE_DELTA * sum(m.P_BIN_EXP_TWO_POW_U[u] * m.V_BIN_EXP_Z_1[u] for u in m.OMEGA_U))
                - m.V_DUAL_MU_1[s, g]
                + m.V_DUAL_MU_2[s, g]
                - m.V_DUAL_LAMBDA[s, m.P_GENERATOR_NODE[g]]
                == 0)

    m.C_FOC_1_LINEARISED = pyo.Constraint(m.OMEGA_S, m.OMEGA_G, rule=foc_1_linearised_rule)

    def foc_2_rule(m, s, n):
        """Constraint relating to voltage angles"""

        term_1 = sum(m.V_DUAL_MU_3[s, n, j]
                     - m.V_DUAL_MU_3[s, j, n]
                     + (m.V_DUAL_LAMBDA[s, n] * m.P_NETWORK_BRANCH_SUSCEPTANCE[n, j])
                     - (m.V_DUAL_LAMBDA[s, j] * m.P_NETWORK_BRANCH_SUSCEPTANCE[j, n]) for j in m.P_NETWORK_GRAPH[n])

        term_2 = m.V_DUAL_NU_1[s, n] * m.P_NETWORK_REFERENCE_NODE_INDICATOR[n]

        term_3 = sum(
            m.P_NETWORK_BRANCH_SUSCEPTANCE[m.P_NETWORK_INTERCONNECTOR_BRANCH_NODES_MAP[l]]
            * m.V_DUAL_MU_4[s, j]
            * m.P_NETWORK_INTERCONNECTOR_INCIDENCE_MAT[n, l]
            for j in m.OMEGA_J for l in m.P_NETWORK_INTERCONNECTOR_BRANCH_ID_MAP[j])

        return term_1 + term_2 + term_3 == 0

    m.C_FOC_2 = pyo.Constraint(m.OMEGA_S, m.OMEGA_N, rule=foc_2_rule)

    def foc_3_rule(m, s, h):
        """Constraint relating to HVDC flows"""

        # From and to nodes for given link, h
        from_node = m.P_NETWORK_HVDC_FROM_NODE[h]
        to_node = m.P_NETWORK_HVDC_TO_NODE[h]

        return ((m.P_NETWORK_HVDC_INCIDENCE_MAT[from_node, h] * m.V_DUAL_LAMBDA[s, from_node])
                + (m.P_NETWORK_HVDC_INCIDENCE_MAT[to_node, h] * m.V_DUAL_LAMBDA[s, to_node])
                - m.V_DUAL_MU_5[s, h]
                + m.V_DUAL_MU_6[s, h] == 0)

    m.C_FOC_3 = pyo.Constraint(m.OMEGA_S, m.OMEGA_H, rule=foc_3_rule)

    return m

def define_network_constraint(m):
    """Define network constraints"""

    def reference_node_voltage_angle_rule(m, s, n):
        """Fix reference node voltage angles to 0"""

        if m.P_NETWORK_REFERENCE_NODE_INDICATOR[n] == 1:
            return m.V_PRIMAL_VOLTAGE_ANGLE[s, n] == 0
        else:
            return pyo.Constraint.Skip

    m.C_REFERENCE_NODE_VOLTAGE_ANGLE = pyo.Constraint(m.OMEGA_S, m.OMEGA_N, rule=reference_node_voltage_angle_rule)

    def power_balance_rule(m, s, n):
        """Power balance at each node"""

        # Total injection from generators connected to node
        generator_injection = sum(m.V_PRIMAL_GENERATOR_POWER[s, g] for g in m.P_NETWORK_NODE_GENERATOR_MAP[n])

        # Injection from AC branches
        ac_injection = sum(
            m.P_NETWORK_BRANCH_SUSCEPTANCE[n, j] * (m.V_PRIMAL_VOLTAGE_ANGLE[s, n] - m.V_PRIMAL_VOLTAGE_ANGLE[s, j])
            for j in m.P_NETWORK_GRAPH[n])

        # Injection from HVDC branches
        hvdc_injection = sum(m.P_NETWORK_HVDC_INCIDENCE_MAT[n, h] * m.V_PRIMAL_HVDC_FLOW[s, h] for h in m.OMEGA_H)

        return (m.P_NETWORK_DEMAND[s, n]
                - m.P_NETWORK_FIXED_INJECTION[s, n]
                - generator_injection
                + ac_injection
                + hvdc_injection
                == 0)

    m.C_POWER_BALANCE = pyo.Constraint(m.OMEGA_S, m.OMEGA_N, rule=power_balance_rule)

    return m

def define_linearised_complementarity_constraints(m):
    """Linearised complementarity constraints"""

    def lin_comp_1_1_rule(m, s, g):
        """Min power output constraint 1"""

        return m.P_GENERATOR_MIN_OUTPUT[g] - m.V_PRIMAL_GENERATOR_POWER[s, g] <= 0

    m.C_LIN_COMP_1_1 = pyo.Constraint(m.OMEGA_S, m.OMEGA_G, rule=lin_comp_1_1_rule)

    def lin_comp_1_2_rule(m, s, g):
        """Min power output constraint 2"""

        return m.V_DUAL_MU_1[s, g] >= 0

    m.C_LIN_COMP_1_2 = pyo.Constraint(m.OMEGA_S, m.OMEGA_G, rule=lin_comp_1_2_rule)

    def lin_comp_1_3_rule(m, s, g):
        """Min power output constraint 3"""

        return m.V_PRIMAL_GENERATOR_POWER[s, g] - m.P_GENERATOR_MIN_OUTPUT[g] <= m.V_BINARY_GAMMA_1[s, g] * m.P_M_11[g]

    m.C_LIN_COMP_1_3 = pyo.Constraint(m.OMEGA_S, m.OMEGA_G, rule=lin_comp_1_3_rule)

    def lin_comp_1_4_rule(m, s, g):
        """Min power output constraint 4"""

        return m.V_DUAL_MU_1[s, g] <= (1 - m.V_BINARY_GAMMA_1[s, g]) * m.P_M_12[g]

    m.C_LIN_COMP_1_4 = pyo.Constraint(m.OMEGA_S, m.OMEGA_G, rule=lin_comp_1_4_rule)

    def lin_comp_2_1_rule(m, s, g):
        """Max power output constraint 1"""

        return m.V_PRIMAL_GENERATOR_POWER[s, g] - m.P_GENERATOR_MAX_OUTPUT[g] <= 0

    m.C_LIN_COMP_2_1 = pyo.Constraint(m.OMEGA_S, m.OMEGA_G, rule=lin_comp_2_1_rule)

    def lin_comp_2_2_rule(m, s, g):
        """Max power output constraint 2"""

        return m.V_DUAL_MU_2[s, g] >= 0

    m.C_LIN_COMP_2_2 = pyo.Constraint(m.OMEGA_S, m.OMEGA_G, rule=lin_comp_2_2_rule)

    def lin_comp_2_3_rule(m, s, g):
        """Max power output constraint 3"""

        return (m.P_GENERATOR_MAX_OUTPUT[g] - m.V_PRIMAL_GENERATOR_POWER[s, g]
                <= m.V_BINARY_GAMMA_2[s, g] * m.P_M_21[g])

    m.C_LIN_COMP_2_3 = pyo.Constraint(m.OMEGA_S, m.OMEGA_G, rule=lin_comp_2_3_rule)

    def lin_comp_2_4_rule(m, s, g):
        """Max power output constraint 4"""

        return m.V_DUAL_MU_2[s, g] <= (1 - m.V_BINARY_GAMMA_2[s, g]) * m.P_M_22[g]

    m.C_LIN_COMP_2_4 = pyo.Constraint(m.OMEGA_S, m.OMEGA_G, rule=lin_comp_2_4_rule)

    def lin_comp_3_1_rule(m, s, n, j):
        """Max voltage angle difference between connected nodes constraint 1"""

        return (m.V_PRIMAL_VOLTAGE_ANGLE[s, n] - m.V_PRIMAL_VOLTAGE_ANGLE[s, j]
                - m.P_NETWORK_VOLTAGE_ANGLE_MAX_DIFFERENCE
                <= 0)

    m.C_LIN_COMP_3_1 = pyo.Constraint(m.OMEGA_S, m.OMEGA_NM, rule=lin_comp_3_1_rule)

    def lin_comp_3_2_rule(m, s, n, j):
        """Max voltage angle difference between connected nodes constraint 2"""

        return m.V_DUAL_MU_3[s, n, j] >= 0

    m.C_LIN_COMP_3_2 = pyo.Constraint(m.OMEGA_S, m.OMEGA_NM, rule=lin_comp_3_2_rule)

    def lin_comp_3_3_rule(m, s, n, j):
        """Max voltage angle difference between connected nodes constraint 3"""

        return (m.P_NETWORK_VOLTAGE_ANGLE_MAX_DIFFERENCE + m.V_PRIMAL_VOLTAGE_ANGLE[s, j]
                - m.V_PRIMAL_VOLTAGE_ANGLE[s, n] <= m.V_BINARY_GAMMA_3[s, n, j] * m.P_M_31[n, j])

    m.C_LIN_COMP_3_3 = pyo.Constraint(m.OMEGA_S, m.OMEGA_NM, rule=lin_comp_3_3_rule)

    def lin_comp_3_4_rule(m, s, n, j):
        """Max voltage angle difference between connected nodes constraint 4"""

        return m.V_DUAL_MU_3[s, n, j] <= (1 - m.V_BINARY_GAMMA_3[s, n, j]) * m.P_M_32[n, j]

    m.C_LIN_COMP_3_4 = pyo.Constraint(m.OMEGA_S, m.OMEGA_NM, rule=lin_comp_3_4_rule)

    def lin_comp_4_1_rule(m, s, j):
        """Interconnector flow limits constraint 1"""

        # Links constituting interconnector, j
        branches = m.P_NETWORK_INTERCONNECTOR_BRANCH_ID_MAP[j]
        branch_links = [m.P_NETWORK_INTERCONNECTOR_BRANCH_NODES_MAP[i] for i in branches]

        return (sum(m.P_NETWORK_BRANCH_SUSCEPTANCE[n, p]
                    * (m.V_PRIMAL_VOLTAGE_ANGLE[s, n] - m.V_PRIMAL_VOLTAGE_ANGLE[s, p])
                    for n, p in branch_links) - m.P_NETWORK_INTERCONNECTOR_LIMIT[j]
                <= 0)

    m.C_LIN_COMP_4_1 = pyo.Constraint(m.OMEGA_S, m.OMEGA_J, rule=lin_comp_4_1_rule)

    def lin_comp_4_2_rule(m, s, j):
        """Interconnector flow limits constraint 2"""

        return m.V_DUAL_MU_4[s, j] >= 0

    m.C_LIN_COMP_4_2 = pyo.Constraint(m.OMEGA_S, m.OMEGA_J, rule=lin_comp_4_2_rule)

    def lin_comp_4_3_rule(m, s, j):
        """Interconnector flow limits constraint 3"""

        # Links constituting interconnector, j
        branches = m.P_NETWORK_INTERCONNECTOR_BRANCH_ID_MAP[j]
        branch_links = [m.P_NETWORK_INTERCONNECTOR_BRANCH_NODES_MAP[i] for i in branches]

        return (m.P_NETWORK_INTERCONNECTOR_LIMIT[j]
                - sum(m.P_NETWORK_BRANCH_SUSCEPTANCE[n, p]
                      * (m.V_PRIMAL_VOLTAGE_ANGLE[s, n] - m.V_PRIMAL_VOLTAGE_ANGLE[s, p]) for n, p in branch_links)
                <= m.V_BINARY_GAMMA_4[s, j] * m.P_M_41[j])

    m.C_LIN_COMP_4_3 = pyo.Constraint(m.OMEGA_S, m.OMEGA_J, rule=lin_comp_4_3_rule)

    def lin_comp_4_4_rule(m, s, j):
        """Interconnector flow limits constraint 4"""

        return m.V_DUAL_MU_4[s, j] <= (1 - m.V_BINARY_GAMMA_4[s, j]) * m.P_M_42[j]

    m.C_LIN_COMP_4_4 = pyo.Constraint(m.OMEGA_S, m.OMEGA_J, rule=lin_comp_4_4_rule)

    def lin_comp_5_1_rule(m, s, h):
        """HVDC reverse flow limits constraint 1"""

        return m.P_NETWORK_HVDC_REVERSE_LIMIT[h] - m.V_PRIMAL_HVDC_FLOW[s, h] <= 0

    m.C_LIN_COMP_5_1 = pyo.Constraint(m.OMEGA_S, m.OMEGA_H, rule=lin_comp_5_1_rule)

    def lin_comp_5_2_rule(m, s, h):
        """HVDC reverse flow limits constraint 2"""

        return m.V_DUAL_MU_5[s, h] >= 0

    m.C_LIN_COMP_5_2 = pyo.Constraint(m.OMEGA_S, m.OMEGA_H, rule=lin_comp_5_2_rule)

    def lin_comp_5_3_rule(m, s, h):
        """HVDC reverse flow limits constraint 3"""

        return m.V_PRIMAL_HVDC_FLOW[s, h] - m.P_NETWORK_HVDC_REVERSE_LIMIT[h] <= m.V_BINARY_GAMMA_5[s, h] * m.P_M_51[h]

    m.C_LIN_COMP_5_3 = pyo.Constraint(m.OMEGA_S, m.OMEGA_H, rule=lin_comp_5_3_rule)

    def lin_comp_5_4_rule(m, s, h):
        """HVDC reverse flow limits constraint 4"""

        return m.V_DUAL_MU_5[s, h] <= (1 - m.V_BINARY_GAMMA_5[s, h]) * m.P_M_52[h]

    m.C_LIN_COMP_5_4 = pyo.Constraint(m.OMEGA_S, m.OMEGA_H, rule=lin_comp_5_4_rule)

    def lin_comp_6_1_rule(m, s, h):
        """HVDC forward flow limits constraint 1"""

        return m.V_PRIMAL_HVDC_FLOW[s, h] - m.P_NETWORK_HVDC_FORWARD_LIMIT[h] <= 0

    m.C_LIN_COMP_6_1 = pyo.Constraint(m.OMEGA_S, m.OMEGA_H, rule=lin_comp_6_1_rule)

    def lin_comp_6_2_rule(m, s, h):
        """HVDC forward flow limits constraint 2"""

        return m.V_DUAL_MU_6[s, h] >= 0

    m.C_LIN_COMP_6_2 = pyo.Constraint(m.OMEGA_S, m.OMEGA_H, rule=lin_comp_6_2_rule)

    def lin_comp_6_3_rule(m, s, h):
        """HVDC forward flow limits constraint 3"""

        return m.P_NETWORK_HVDC_FORWARD_LIMIT[h] - m.V_PRIMAL_HVDC_FLOW[s, h] <= m.V_BINARY_GAMMA_6[s, h] * m.P_M_61[h]

    m.C_LIN_COMP_6_3 = pyo.Constraint(m.OMEGA_S, m.OMEGA_H, rule=lin_comp_6_3_rule)

    def lin_comp_6_4_rule(m, s, h):
        """HVDC forward flow limits constraint 4"""

        return m.V_DUAL_MU_6[s, h] <= (1 - m.V_BINARY_GAMMA_6[s, h]) * m.P_M_62[h]

    m.C_LIN_COMP_6_4 = pyo.Constraint(m.OMEGA_S, m.OMEGA_H, rule=lin_comp_6_4_rule)

    return m

def define_permit_market_constraints(m):
    """Define permit market constraints"""

    def permit_market_1_rule(m):
        """Permit market complementarity constraint 1 - use when baseline is fixed"""

        return (sum(m.P_SCENARIO_DURATION[s] * ((m.P_GENERATOR_EMISSIONS_INTENSITY[g] - m.P_POLICY_FIXED_BASELINE)
                                                * m.V_PRIMAL_GENERATOR_POWER[s, g])
                    for g in m.OMEGA_G for s in m.OMEGA_S)
                <= 0)

    m.C_PERMIT_MARKET_1 = pyo.Constraint(rule=permit_market_1_rule)

    def permit_market_1_linearised_rule(m):
        """Permit market complementarity constraint 1 - use when baseline is variable"""

        return (sum(m.P_SCENARIO_DURATION[s]
                    * (((m.P_GENERATOR_EMISSIONS_INTENSITY[g] - m.P_BIN_EXP_MIN_BASELINE)
                        * m.V_PRIMAL_GENERATOR_POWER[s, g])
                       - (m.P_BIN_EXP_BASELINE_DELTA * sum(m.P_BIN_EXP_TWO_POW_U[u] * m.V_BIN_EXP_Z_2[s, u, g]
                                                           for u in m.OMEGA_U)))
                    for g in m.OMEGA_G for s in m.OMEGA_S)
                <= 0)

    m.C_PERMIT_MARKET_1_LINEARISED = pyo.Constraint(rule=permit_market_1_linearised_rule)

    def permit_market_2_rule(m):
        """Permit market complementarity constraint 2"""

        return m.V_DUAL_PERMIT_MARKET >= 0

    m.C_PERMIT_MARKET_2 = pyo.Constraint(rule=permit_market_2_rule)

    def permit_market_3_rule(m):
        """Permit market complementarity constraint 3"""

        return sum(m.P_SCENARIO_DURATION[s]
                   * ((m.P_POLICY_FIXED_BASELINE - m.P_GENERATOR_EMISSIONS_INTENSITY[g])
                      * m.V_PRIMAL_GENERATOR_POWER[s, g])
                   for g in m.OMEGA_G for s in m.OMEGA_S) <= (m.V_BINARY_PERMIT_MARKET * m.P_M_71)

    m.C_PERMIT_MARKET_3 = pyo.Constraint(rule=permit_market_3_rule)

    def permit_market_3_linearised_rule(m):
        """Permit market complementarity constraint 3 - linearised"""

        return (sum(m.P_SCENARIO_DURATION[s] * (((m.P_BIN_EXP_MIN_BASELINE - m.P_GENERATOR_EMISSIONS_INTENSITY[g])
                                                 * m.V_PRIMAL_GENERATOR_POWER[s, g])
                                                + (m.P_BIN_EXP_BASELINE_DELTA
                                                   * sum(m.P_BIN_EXP_TWO_POW_U[u] * m.V_BIN_EXP_Z_2[s, u, g]
                                                         for u in m.OMEGA_U))) for g in m.OMEGA_G for s in m.OMEGA_S)
                <= m.V_BINARY_PERMIT_MARKET * m.P_M_71)

    m.C_PERMIT_MARKET_3_LINEARISED = pyo.Constraint(rule=permit_market_3_linearised_rule)

    def permit_market_4_rule(m):
        """Permit market complementarity constraint 4"""

        return m.V_DUAL_PERMIT_MARKET <= (1 - m.V_BINARY_PERMIT_MARKET) * m.P_M_72

    m.C_PERMIT_MARKET_4 = pyo.Constraint(rule=permit_market_4_rule)

    return m

def define_permit_price_targeting_constraints(m):
    """Constraints used to get the absolute difference between the permit price and some target"""

    # Constraints to minimise difference between permit price and target
    m.C_PERMIT_PRICE_TARGET_CONSTRAINT_1 = pyo.Constraint(
        expr=m.V_DUMMY_PERMIT_PRICE_TARGET_X_1 >= m.P_POLICY_PERMIT_PRICE_TARGET - m.V_DUAL_PERMIT_MARKET)

    m.C_PERMIT_PRICE_TARGET_CONSTRAINT_2 = pyo.Constraint(
        expr=m.V_DUMMY_PERMIT_PRICE_TARGET_X_2 >= m.V_DUAL_PERMIT_MARKET - m.P_POLICY_PERMIT_PRICE_TARGET)

    return m

def define_weighted_rrn_price_targeting_constraints(m):
    """Constraints used to get absolute difference between weighted RRN price and some target"""

    # Constraints used to minimise difference between RRN price target and RRN price
    m.C_WEIGHTED_RRN_PRICE_TARGET_CONSTRAINT_1 = pyo.Constraint(
        expr=m.V_DUMMY_WEIGHTED_RRN_PRICE_X_1 >= m.E_WEIGHTED_RRN_PRICE - m.P_POLICY_WEIGHTED_RRN_PRICE_TARGET)

    m.C_WEIGHTED_RRN_PRICE_TARGET_CONSTRAINT_2 = pyo.Constraint(
        expr=m.V_DUMMY_WEIGHTED_RRN_PRICE_X_2 >= m.P_POLICY_WEIGHTED_RRN_PRICE_TARGET - m.E_WEIGHTED_RRN_PRICE)

    return m

def define_constraints(m):
    """Define constraints"""

    m = define_binary_expansion_constraints(m)
    m = define_first_order_condition_constraints(m)
    m = define_network_constraint(m)
    m = define_linearised_complementarity_constraints(m)
    m = define_permit_market_constraints(m)

    # Constraints used to obtain absolute values between variables and some target
    m = define_permit_price_targeting_constraints(m)
    m = define_weighted_rrn_price_targeting_constraints(m)

    return m

def define_objective_functions(m):
    """Define objective functions"""

    # Use if trying to find a feasible solution for a fixed baseline
    m.O_FEASIBILITY = pyo.Objective(expr=m.V_DUMMY, sense=pyo.minimize)

    # Objective function
    m.O_PERMIT_PRICE_TARGET = pyo.Objective(expr=m.V_DUMMY_PERMIT_PRICE_TARGET_X_1 + m.V_DUMMY_PERMIT_PRICE_TARGET_X_2)

    # Weighted RRN price targeting objective function
    m.O_WEIGHTED_RRN_PRICE_TARGET = pyo.Objective(
        expr=m.V_DUMMY_WEIGHTED_RRN_PRICE_X_1 + m.V_DUMMY_WEIGHTED_RRN_PRICE_X_2)

    return m

def apply_pu_scaling(m):
    """Attempt to improve numerical stability by scaling selected parameters"""

    # Scale branch susceptance
    for i in m.P_NETWORK_BRANCH_SUSCEPTANCE.keys():
        m.P_NETWORK_BRANCH_SUSCEPTANCE[i] = m.P_NETWORK_BRANCH_SUSCEPTANCE[i] / m.P_NETWORK_BASE_POWER

    # HVDC limits
    for i in m.P_NETWORK_HVDC_FORWARD_LIMIT.keys():
        m.P_NETWORK_HVDC_FORWARD_LIMIT[i] = m.P_NETWORK_HVDC_FORWARD_LIMIT[i] / m.P_NETWORK_BASE_POWER

    for i in m.P_NETWORK_HVDC_REVERSE_LIMIT.keys():
        m.P_NETWORK_HVDC_REVERSE_LIMIT[i] = m.P_NETWORK_HVDC_REVERSE_LIMIT[i] / m.P_NETWORK_BASE_POWER

    # Generator max output
    for i in m.P_GENERATOR_MAX_OUTPUT.keys():
        m.P_GENERATOR_MAX_OUTPUT[i] = m.P_GENERATOR_MAX_OUTPUT[i] / m.P_NETWORK_BASE_POWER

    # Generator short run marginal costs
    for i in m.P_GENERATOR_SRMC.keys():
        m.P_GENERATOR_SRMC[i] = m.P_GENERATOR_SRMC[i] / m.P_NETWORK_BASE_POWER

    # Interconnector flow limits
    for i in m.P_NETWORK_INTERCONNECTOR_LIMIT.keys():
        m.P_NETWORK_INTERCONNECTOR_LIMIT[i] = m.P_NETWORK_INTERCONNECTOR_LIMIT[i] / m.P_NETWORK_BASE_POWER

    # Fixed injections
    for i in m.P_NETWORK_FIXED_INJECTION.keys():
        m.P_NETWORK_FIXED_INJECTION[i] = m.P_NETWORK_FIXED_INJECTION[i] / m.P_NETWORK_BASE_POWER

    # Demand
    for i in m.P_NETWORK_DEMAND.keys():
        m.P_NETWORK_DEMAND[i] = m.P_NETWORK_DEMAND[i] / m.P_NETWORK_BASE_POWER

    # Complementarity constraints
    big_m_parameters = [f'P_M_{i}{j}' for i in range(1, 8) for j in range(1, 3)]
    ignore_scaling = ['P_M_31']
    for i in big_m_parameters:
        if i in ignore_scaling:
            continue
        else:
            for j in m.__getattribute__(i).keys():
                m.__getattribute__(i)[j] = m.__getattribute__(i)[j] / m.P_NETWORK_BASE_POWER

    # Scale price targets
    m.P_POLICY_PERMIT_PRICE_TARGET = m.P_POLICY_PERMIT_PRICE_TARGET.value / m.P_NETWORK_BASE_POWER.value
    m.P_POLICY_WEIGHTED_RRN_PRICE_TARGET = m.P_POLICY_WEIGHTED_RRN_PRICE_TARGET.value / m.P_NETWORK_BASE_POWER.value

    return m

def construct_model(data, use_pu):
    """Construct model"""

    # Initialise model
    m = pyo.ConcreteModel()

    # Define sets and parameters
    m = define_sets(m, data)
    m = define_parameters(m, data)

    # Optionally apply per-unit scaling - attempt to improve numerical stability
    if use_pu:
        m = apply_pu_scaling(m)

    # Define variables, expressions, and constraints
    m = define_variables(m)
    m = define_expressions(m)
    m = define_constraints(m)

    # Define objective functions
    m = define_objective_functions(m)

    return m

def configure_feasibility_model(m):
    """Configure model to accept a fixed emissions intensity baseline"""

    # Deactivate price targeting objective functions
    m.O_PERMIT_PRICE_TARGET.deactivate()
    m.O_WEIGHTED_RRN_PRICE_TARGET.deactivate()

    # Deactivate linearised constraints - those with discretised baseline
    m.C_FOC_1_LINEARISED.deactivate()
    m.C_PERMIT_MARKET_1_LINEARISED.deactivate()
    m.C_PERMIT_MARKET_3_LINEARISED.deactivate()

    # Deactivate constraints used for binary expansion linearisation
    m.C_Z_1_CONSTRAINT_1.deactivate()
    m.C_Z_1_CONSTRAINT_2.deactivate()
    m.C_Z_1_CONSTRAINT_3.deactivate()
    m.C_Z_1_CONSTRAINT_4.deactivate()
    m.C_Z_2_CONSTRAINT_1.deactivate()
    m.C_Z_2_CONSTRAINT_2.deactivate()
    m.C_Z_2_CONSTRAINT_3.deactivate()
    m.C_Z_2_CONSTRAINT_4.deactivate()

    return m

def configure_weighted_rrn_price_targeting_model(m):
    """Configure mode to target weighted RRN prices"""

    # Ensure weighted RRN price targeting objective is the only one active
    m.O_FEASIBILITY.deactivate()
    m.O_PERMIT_PRICE_TARGET.deactivate()

    # Deactivate first order condition and permit market constraints that have not been linearised
    m.C_FOC_1.deactivate()
    m.C_PERMIT_MARKET_1.deactivate()
    m.C_PERMIT_MARKET_3.deactivate()

    return m

def configure_permit_price_targeting_model(m):
    """Configure permit price targeting model"""

    # Ensure permit price targeting objective is the only one active
    m.O_FEASIBILITY.deactivate()
    m.O_WEIGHTED_RRN_PRICE_TARGET.deactivate()

    # Deactivate first order condition and permit market constraints that have not been linearised
    m.C_FOC_1.deactivate()
    m.C_PERMIT_MARKET_1.deactivate()
    m.C_PERMIT_MARKET_3.deactivate()

    return m

def configure_model(m, options):
    """Activate / deactivate constraints and objectives depending on the case to be analysed"""

    if options['mode'] == 'feasibility':
        m = configure_feasibility_model(m)

    elif options['mode'] == 'weighted_rrn_price_target':
        m = configure_weighted_rrn_price_targeting_model(m)

    elif options['mode'] == 'permit_price_target':
        m = configure_permit_price_targeting_model(m)

    else:
        raise Exception(f"Unexpected mode: {options['mode']}")

    return m

def solve_model(m):
    """Solve model"""

    opt = pyo.SolverFactory('cplex', solver_io='mps')

    # Solver options
    options = {
        'mip tolerances absmipgap': 1e-6,
        'emphasis mip': 1,  # Emphasise feasibility
        # 'timelimit': 5000
    }

    # Solve model
    opt.solve(m, keepfiles=False, tee=True, options=options)

    return m

def extract_value(v):
    """Extract model value"""

    if type(v) in [int, float]:
        return v
    else:
        return v.value

def get_solution(m, params):
    """Return model solution"""

    # Extract selected model parameters - used to check case file was correctly specified
    model_parameters = {
        'P_POLICY_PERMIT_PRICE_TARGET': m.P_POLICY_PERMIT_PRICE_TARGET.value,
        'P_POLICY_WEIGHTED_RRN_PRICE_TARGET': m.P_POLICY_PERMIT_PRICE_TARGET.value,
        'P_SCENARIO_DURATION': {k: extract_value(v) for k, v in m.P_SCENARIO_DURATION.items()},
        'P_GENERATOR_SRMC': {k: extract_value(v) for k, v in m.P_GENERATOR_SRMC.items()},
        'P_GENERATOR_EMISSIONS_INTENSITY': {k: extract_value(v) for k, v in m.P_GENERATOR_EMISSIONS_INTENSITY.items()},
    }

    # Extract selected variables and expressions
    try:
        variables = {
            'V_PRIMAL_GENERATOR_POWER': {k: extract_value(v) for k, v in m.V_PRIMAL_GENERATOR_POWER.items()},
            'V_DUAL_PERMIT_MARKET': m.V_DUAL_PERMIT_MARKET.value,
        }
    except ValueError:
        variables = {}

    try:
        expressions = {
            'E_WEIGHTED_RRN_PRICE': m.E_WEIGHTED_RRN_PRICE.expr(),
            'E_AVERAGE_ELECTRICITY_PRICE': m.E_AVERAGE_ELECTRICITY_PRICE.expr(),
        }
    except ValueError:
        expressions = {}

    # Extract discretised baseline - can only be extracted when targeting prices
    try:
        price_targeting_expressions = {
            'E_BIN_EXP_DISCRETISED_BASELINE': m.E_BIN_EXP_DISCRETISED_BASELINE.expr(),
        }
    except ValueError:
        price_targeting_expressions = {}

    # Combine into single dictionary
    solution = {**model_parameters, **variables, **expressions, **price_targeting_expressions}

    # Combine into single dictionary
    output = {
        'options': params,
        'solution': solution
    }

    return output

if __name__ == '__main__':
    # Data and output directories
    data_directory = os.path.join(os.path.dirname(__file__), os.path.pardir, os.path.pardir, 'data')
    scenario_directory = os.path.join(os.path.dirname(__file__), os.path.pardir, '1_create_scenarios', 'output')
    tmp_directory = os.path.join(os.path.dirname(__file__), 'utils', 'tmp')

    model_options = {
        'parameters': {
            'P_BINARY_EXPANSION_LARGEST_INTEGER': 10,
            'P_POLICY_FIXED_BASELINE': 1.2,
            'P_POLICY_PERMIT_PRICE_TARGET': 30,
            'P_POLICY_WEIGHTED_RRN_PRICE_TARGET': 20,
        },
        'mode': 'feasibility',
    }

    # Get case data
    case_data = get_case_data(data_directory, scenario_directory, tmp_directory, model_options, use_cache=True)

    # Construct model
    model = construct_model(case_data, use_pu=True)
    model = configure_model(model, model_options)
    model = solve_model(model)


import subprocess

class LocalCallableManager:
    def __init__(self, config):
        self.config = config
        self.module_to_container_id = {}

    def start_containers(self):
        for module_name in self.config:
            if self.config[module_name]['url'] != 'none':
                self.start_container(module_name)
        return

    def start_container(self, module_name):
        port = self.config[module_name]['port']
        docker_file_dir = self.config[module_name]['docker_file_dir']

        # check if container is already running
        running = subprocess.run(['docker', 'container', 'ls', '-q', '-f', 'name={}'.format(module_name)],
                                 stdout=subprocess.PIPE)
        if running.stdout: return

        # build docker image
        print(f"Building {module_name} using the docker file at {docker_file_dir}.")
        building = subprocess.run(['docker', 'build', '-t', module_name, docker_file_dir], check=True)
        print(f"Finished building {module_name}.")
        print(building)

        print(f"Running the container {module_name}.")
        # run the docker container
        container_process = subprocess.run(['docker', 'run', '-d', '--rm', '-p',
                                            '{}:80'.format(port),
                                            '--name',
                                            '{}'.format(module_name),
                                            '{}:latest'.format(module_name)],
                                           check=True, stdout=subprocess.PIPE)
        print(f"Finished running {module_name}.")
        print(container_process)

        container_id = container_process.stdout.decode('utf-8').strip()
        self.module_to_container_id[module_name] = container_id

    def stop_containers(self):
        for container_id in self.module_to_container_id.values():
            subprocess.run(['docker', 'stop', container_id])


from datetime import datetime, timedelta
import time

def check_request(request):
    code = request.status_code
    if (code == 200):
        return request
    elif (code == 202):
        return request
    elif (code == 401):
        raise AccessTokenError("Bad access token.")
    elif (code == 400):
        raise BadRequestError(request)
    elif (code == 404):
        raise NotFoundError(request)
    elif (code == 413):
        raise LimitExceededError("Request too large.")
    elif (code == 429):
        delta = (datetime.utcfromtimestamp(int(request.headers["X-RateLimit-Reset"])) - datetime.utcnow()).total_seconds()
        print("Too many requests. Reset in: " + str(delta) + "secs")
        if int(delta) > 0:
            time.sleep(int(delta) + 1)
        else:
            time.sleep(1)
        print("Retrying the call...")
        raise RetryCall("Failed to retry the call.")
    elif (code in [500, 502, 503]):
        raise APIError("Questrade API failed.")
    else:
        print("UNKNOWN ERROR: " + str(code))
        print(request.text)
        raise Exception

class AccessTokenError(Exception):

    def __init__(self, value):
        self.value = value

    def __str__(self):
        return repr(self.value)

class APIError(Exception):

    def __init__(self, value):
        self.value = value

    def __str__(self):
        return repr(self.value)

class BadRequestError(Exception):

    def __init__(self, response):
        try:
            code = response.json()["code"]
            if (code == 1002):
                self.value = "Invalid argument."
            elif (code == 1003):
                self.value = "Argument length exceeds limit."
            elif (code == 1004):
                self.value = "Missing required argument."
            elif (code == 1013):
                self.value = "Requesting anything other than 'application/json'."
            elif (code == 1015):
                self.value = "Invalid argument."
        except ValueError:
            self.value = "Bad Request: " + str(response.content) + str(response.text) + str(response.json)

    def __str__(self):
        return repr(self.value)

class LimitExceededError(Exception):

    def __init__(self, value):
        self.value = value

    def __str__(self):
        return repr(self.value)

class NotFoundError(Exception):

    def __init__(self, value):
        try:
            code = value.json()["code"]
            if (code == 1001):
                self.value = "Invalid endpoint."
            elif (code == 1018):
                self.value = "Account number not found."
            elif (code == 1019):
                self.value = "Symbol not found."
            elif (code == 1020):
                self.value = "Order not found."
        except ValueError:
            self.value = "Not Found Error."

    def __str__(self):
        return repr(self.value)

class RetryCall(Exception):

    def __init__(self, value):
        self.value = value

    def __str__(self):
        return repr(self.value)


import numpy as np
import pytest
import tensorflow as tf

from tensorflow_addons.metrics import GeometricMean

def get_test_data():
    return [
        ([0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 0),
        ([0, 0, 0, 0, 0, 0, 0, 1, 2, 6], 0),
        ([0.2, 0.5, 0.3, 0.6, 0.1, 0.7], 0.32864603),
        ([8, 4, 1, 7, 2, 11, 9, 22, 52], 7.1804023),
        ([8.2, 9.7, 9.1, 2.7, 1.1, 2.0], 4.0324492),
        ([0.6666666, 0.215213, 0.15167], 0.27918512),
    ]

def assert_result(expected, result):
    np.testing.assert_allclose(expected, result, atol=1e-6)

def check_result(obj, expected_result, expected_count):
    result = obj.result().numpy()
    count = obj.count.numpy()
    assert_result(expected_result, result)
    np.testing.assert_equal(expected_count, count)

def test_config_gmean():
    def _check_config(obj, name):
        assert obj.name == name
        assert obj.dtype == tf.float32
        assert obj.stateful
        assert len(obj.variables) == 2

    name = "my_gmean"
    obj1 = GeometricMean(name=name)
    _check_config(obj1, name)

    obj2 = GeometricMean.from_config(obj1.get_config())
    _check_config(obj2, name)

def test_init_states_gmean():
    obj = GeometricMean()
    assert obj.total.numpy() == 0.0
    assert obj.count.numpy() == 0.0
    assert obj.total.dtype == tf.float32
    assert obj.count.dtype == tf.float32

@pytest.mark.parametrize("values, expected", get_test_data())
def test_scalar_update_state_gmean(values, expected):
    obj = GeometricMean()
    values = tf.constant(values, tf.float32)
    for v in values:
        obj.update_state(v)
    check_result(obj, expected, len(values))

@pytest.mark.parametrize("values, expected", get_test_data())
def test_vector_update_state_gmean(values, expected):
    obj = GeometricMean()
    values = tf.constant(values, tf.float32)
    obj.update_state(values)
    check_result(obj, expected, len(values))

@pytest.mark.parametrize("values, expected", get_test_data())
def test_call_gmean(values, expected):
    obj = GeometricMean()
    result = obj(tf.constant(values, tf.float32))
    count = obj.count.numpy()
    assert_result(expected, result)
    np.testing.assert_equal(len(values), count)

def test_reset_state():
    obj = GeometricMean()
    obj.update_state([1, 2, 3, 4, 5])
    obj.reset_state()
    assert obj.total.numpy() == 0.0
    assert obj.count.numpy() == 0.0

@pytest.mark.parametrize(
    "values, sample_weight, expected",
    [
        ([1, 2, 3, 4, 5], 1, 2.6051712),
        ([2.1, 4.6, 7.1], [1, 2, 3], 5.014777),
        ([9.6, 1.8, 8.2], [0.2, 0.5, 0.3], 3.9649222),
    ],
)
def test_sample_weight_gmean(values, sample_weight, expected):
    obj = GeometricMean()
    obj.update_state(values, sample_weight=sample_weight)
    assert_result(expected, obj.result().numpy())


##########################################################################
####			Meniscus processing tool
####			Made by Ruslan Baynazarov in 2017
####			hocop@yandex.ru, vk.com/ruslanbain
##########################################################################

import numpy as np
import cv2
from math import *
import time
from os import listdir
from os.path import isfile, join
from appJar import gui

path = 'input/'

onlyfiles = [f for f in listdir(path) if isfile(join(path, f))]
onlyfiles.sort()

# get info
f0 = onlyfiles[0]
time0 = int(f0[6:8])*3600 + int(f0[8:10])*60 + int(f0[10:12])
img = cv2.imread(path+f0)
imgHeight, imgWidth, c = img.shape

# init arrays
times = []
heights = []

# apriori values
top = 0
bottom = imgHeight
left = 0
right = imgWidth
maxBlack = 50
rot = 0

def process(f):
	# get time from filename
	time = 0
	try:
		time = int(f[6:8])*3600 + int(f[8:10])*60 + int(f[10:12]) - time0
	except:
		global curFileNum
		time = curFileNum

	# read image
	img = cv2.imread(path+f)
	img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

	# rotate
	rows,cols = img.shape
	ROTM = cv2.getRotationMatrix2D((cols/2,rows/2),rot,1)
	img = cv2.warpAffine(img,ROTM,(cols,rows))

	# remove not interesting domains
	img[:top,:] = maxBlack + 1 + img[:top,:] * 0
	img[bottom:,:] = maxBlack + 1 + img[bottom:,:] * 0
	img[:,:left] = maxBlack + 1 + img[:,:left] * 0
	img[:,right:] = maxBlack + 1 + img[:,right:] * 0

	# make mask
	mask = cv2.inRange(img, 0, maxBlack)
	mask = cv2.erode(mask,None,iterations=4)
	mask = cv2.dilate(mask,None,iterations=8)
	mask = cv2.erode(mask,None,iterations=4)

	# find contours
	v2,cont,h=cv2.findContours(mask,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)

	# extract coordinate
	height = -1
	if len(cont) == 1:
		M = cv2.moments(cont[0])
		height = M['m10'] / M['m00']

	# draw
	img = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
		# green if ok, else red
	cv2.drawContours(img, cont, -1, (0,255,0)if len(cont)==1 else (0,0,255), 2)
	return img, time, height

# variables
curFileNum = 0
t, h = time0, -1

# button functions
def compAndShowLast():
	global t
	global h
	global curFileNum
	global top
	global bottom
	global left
	global right
	global maxBlack
	global rot
	top = app.getScale('Top')
	bottom = app.getScale('Bottom')
	left = app.getScale('Left')
	right = app.getScale('Right')
	maxBlack = app.getScale('Thresh')
	rot = app.getScale('Rot')

	img, t, h = process(onlyfiles[curFileNum])

	cv2.imshow('image', img)
	cv2.waitKey(30)

def press(button):
	global t
	global h
	global curFileNum
	global outfile
	if button == 'Submit':
		if h > 0:
			outfile.write('%f\t%f\n' % (t, h))
		else:
			outfile.write('%f\tnan\n' % t)
		curFileNum += 1
		if curFileNum == len(onlyfiles):
			exit()
	if button == 'Submit all':
		while True:
			press('Submit')
	if button == 'Skip':
		curFileNum += 1
	compAndShowLast()

# create window
app = gui('Meniscus processing', '400x400')

app.addLabel('title1','Set brightness threshold:')
app.addLabelScale("Thresh")
app.setScaleRange('Thresh', 0, 254, curr=None)
app.setScale('Thresh', maxBlack, callFunction=True)
app.setScaleChangeFunction('Thresh', press)
app.showScaleValue('Thresh',show=True)

app.addLabel('title2','Set rotation:')
app.addLabelScale("Rot")
app.setScaleRange('Rot', -90, 90, curr=None)
app.setScale('Rot', rot, callFunction=True)
app.setScaleChangeFunction('Rot', press)
app.showScaleValue('Rot',show=True)

app.addLabel('title3','Set margins:')

app.addLabelScale("Top")
app.setScaleRange('Top', 0, imgHeight, curr=None)
app.setScale('Top', top, callFunction=True)
app.setScaleChangeFunction('Top', press)

app.addLabelScale("Bottom")
app.setScaleRange('Bottom', 0, imgHeight, curr=None)
app.setScale('Bottom', bottom, callFunction=True)
app.setScaleChangeFunction('Bottom', press)

app.addLabelScale("Left")
app.setScaleRange('Left', 0, imgWidth, curr=None)
app.setScale('Left', left, callFunction=True)
app.setScaleChangeFunction('Left', press)

app.addLabelScale("Right")
app.setScaleRange('Right', 0, imgWidth, curr=None)
app.setScale('Right', right, callFunction=True)
app.setScaleChangeFunction('Right', press)

app.addButtons(['Skip','Submit','Submit all'], press)

# run
compAndShowLast()
outfile = open('output.txt','w')
outfile.write('time(sec)\theight(pixel)\n')
app.go()


nome = str(input('Nome Inteiro: ')).strip()
max = nome.upper()
min = nome.lower()
div = nome.split()
consolida = ''.join(div)
cont = len(consolida)
pnome = len(div[0])

print('Nome Maisculo: {}'.format(max))
print('Nome Minusculo: {}'.format(min))
print('Nº de Letras: {}'.format(cont))
print('Nº de Letras no 1º Nome: {}'.format(pnome))


from frame import *

f = open("gen/c_code/output.c",'w')
dic_typ = {"integer":"int","real":"float","char":"char","boolean":"int"}
dic_type_c = {"int":"%d","float":"%f","char":"%c"}
dic_trans = {"mod":"%","div":"/","=":"==","and":"&&","<>":"!=","or":"||","not":"!"}
global_vars = {} #{'y': 'g0', 'a': 'g2', 'c': 'g4', 'z': 'g1', 'b': 'g3'}
var_type = {} #{'g4': 'integer', 'g3': 'boolean', 'g2': 'char', 'g1': 'real', 'g0': 'real'}
frames = {}

return_counter = 0
var_counter = 0
stat_counter = 0
block_flag = False
MAIN_BLOCK = ""
ACT_BLOCK = ""

def generate(node):
	global block_flag,main_flag,MAIN_BLOCK,ACT_BLOCK,stat_counter
	if node == None:
		return None

	elif type(node) == type(""):
		if node.upper() in ["FALSE","TRUE"]:
			return node.upper()
		else:
			return node

	elif type(node) == type(1) or type(node) == type(1.4):
		return node

	elif node.type in ["program"]:
		translate_header()
		for child in node.children:
			generate(child)
		translate_footer()
		f.close()

	elif node.type in ["block_name"]:
		b = node.children[0]
		if not block_flag:
			MAIN_BLOCK = b.lower()
			block_flag = True
		ACT_BLOCK = b.lower()
		return ACT_BLOCK

	elif node.type in ["procedure_and_function_declaration_part"]:
		for child in node.children:
			generate(child)
		ACT_BLOCK = MAIN_BLOCK

	elif node.type in ["function_declaration"]:
		name = generate(node.children[0].children[0])

		if len(node.children[0].children) ==3:
			retur = generate(node.children[0].children[2]) # return value
		else:
			retur = generate(node.children[0].children[1]) # return value

		frames[name] = Frame(retur.lower())
		translate_proc_1st(name)

		if len(node.children[0].children) ==3:
			par = generate(node.children[0].children[1]) #gerar parametros

		generate(node.children[1]) # corpo da func
		translate_proc_2nd(name)

	elif node.type in ["procedure_declaration"]:
		if len(node.children[0].children)==1:
			name = generate(node.children[0])
		else:
			name = generate(node.children[0].children[0])

		frames[name] = Frame()
		translate_proc_1st(name)

		if len(node.children[0].children)!=1:
			generate(node.children[0].children[1]) #gerar parametros

		generate(node.children[1]) #corpo do proc
		translate_proc_2nd(name)

	elif node.type in  ["block","variable_declaration_part","variable_declation_list","compound_statement",
					"statement_sequence","statement","open_statement","closed_statement",
					"program_heading","proc_or_func_declaration_list","proc_or_func_declaration",
					"formal_parameter_list","formal_parameter_section_list"]:
		for child in node.children:
			generate(child)

	elif node.type in [ "unsigned_constant","actual_parameter","direction",
					"params","boolean","procedure_heading","function_returning"]:
		for child in node.children:
			return generate(child)

	elif node.type in ["closed_if_statement","open_if_statement"]:
		stat_counter += 1
		a = stat_counter
		l = get_list(generate(node.children[0]))
		f.write("if %s goto then%d;\n" % (l,a) )
		if len(node.children) == 3:
			generate(node.children[2])
		f.write("goto endif%d;\n" % (a) )
		f.write("then%d:\n" % (a) )
		generate(node.children[1])
		f.write("endif%d:\n" % (a) )

	elif node.type in ["closed_while_statement","open_while_statement"]:
		stat_counter += 1
		a = stat_counter
		l = get_list(generate(node.children[0]))
		f.write("while%d:\n" % (a) )
		f.write("if (!(%s)) goto endwhile%d;\n" % (l,a) )
		generate(node.children[1])
		f.write("goto while%d;\n" % (a) )
		f.write("endwhile%d:\n" % (a) )

	elif node.type in ["closed_for_statement","open_for_statement"]:
		stat_counter += 1
		a = stat_counter
		v = generate(node.children[0]) #gera assigment
		direction = generate(node.children[1]).lower()
		if direction == 'to':
			signal = '<'
			op = '+'
		else:
			signal = '>'
			op = '-'
		limit = generate(node.children[2])
		f.write("for%d:\n" % (a) )
		f.write("if (!(%s %s= %s)) goto endfor%d;\n" % (v,signal,str(limit[0][0]),a) )
		generate(node.children[3])
		f.write("%s = %s %s 1;\n" % (v,v,op) )
		f.write("goto for%d;\n" % (a) )
		f.write("endfor%d:\n" % (a) )

	elif node.type in ["repeat_statement"]:
		stat_counter += 1
		a = stat_counter
		exp = get_list(generate(node.children[1]))
		f.write("repeat%d:\n" % (a) )
		generate(node.children[0])
		f.write("if %s goto endrepeat%d;\n" % (exp,a) )
		generate(node.children[1])
		f.write("goto repeat%d;\n" % (a) )
		f.write("endrepeat%d:\n" % (a) )

	elif node.type in ["mulop","relop","addop"]:
		st = generate(node.children[0])
		st = st.lower()
		if st in dic_trans:
			st = dic_trans[st]
		return st

	elif node.type in ["primary"]:
		if len(node.children) == 2:
			return [dic_trans[generate(node.children[0])],generate(node.children[1])]
		for child in node.children:
			if type(child) == type(""):
				if child.lower() in frames:
					return (child.lower(),[])
				if ACT_BLOCK == MAIN_BLOCK:
					return global_vars[child]
				else:
					if child in frames[ACT_BLOCK].global_vars:
						return frames[ACT_BLOCK].global_vars[child]
					else:
						return global_vars[child]
			else:
				return generate(child)

	elif node.type in [ "identifier_list","type_denoter","actual_parameter_list","expression"]:
		l = []
		for child in node.children:
			r = generate(child)
			if type(r) == type(""):
				l.append(r)
			else:
				l = l + r
		return l

	elif node.type in ["assignment_statement"]:
		var = generate(node.children[0])
		assg = generate(node.children[1])

		if type(assg[0][0]) == type(()):
			translate_call_stat(assg[0][0][0].lower(),assg[0][0][1],var)

		else:
			st = get_list(assg)

			if var.lower() == ACT_BLOCK:
				rt = dic_typ[frames[ACT_BLOCK].return_typ]
				f.write("sp->parent->return_val[0] = (%s*)malloc(sizeof(%s));\n" % (rt,rt) )
				f.write("*((%s*)sp->parent->return_val[0]) = %s;\n" % (rt,st) )
			elif ACT_BLOCK == MAIN_BLOCK:
				f.write("%s = %s;\n" % (global_vars[var],st) )
				return global_vars[var]
			else:
				if var in frames[ACT_BLOCK].global_vars:
					f.write("%s = %s;\n" % (frames[ACT_BLOCK].global_vars[var],st) )
					return frames[ACT_BLOCK].global_vars[var]
				else:
					f.write("%s = %s;\n" % (global_vars[var],st) )
					return global_vars[var]

	elif node.type in ["procedure_statement","function_designator"]:
		name = generate(node.children[0]).lower()

		if len(node.children)!=1:
			params = generate(node.children[1])
		else:
			params = None

		if node.type == "function_designator":
			return (name,params)
		if name == "writeln" or name == "write":
			par = params[0][0]
			if par in var_type:
				translate_printf_var(name,dic_type_c[dic_typ[var_type[par]]],par)

			elif ACT_BLOCK != MAIN_BLOCK and par in frames[ACT_BLOCK].var_type:
				translate_printf_var(name,dic_type_c[dic_typ[frames[ACT_BLOCK].var_type[par]]],par)

			else:
				translate_printf(name,par)

		else:
			translate_call_stat(name,params)

	elif node.type in ["simple_expression","term"]:
		if len(node.children) == 1:
			return [generate(node.children[0])]
		else:
			return [generate(node.children[0]), generate(node.children[1]), generate(node.children[2])]

	elif node.type in ["variable_declaration","formal_parameter_section"]:
		var = generate(node.children[0])
		typ = generate(node.children[1])
		if len(var) == len(typ):
			for i in range(len(var)):
				if ACT_BLOCK == MAIN_BLOCK:
					do_main_set_var(var[i],typ[i].lower())
				else:
					do_frame_set_var(var[i],typ[i].lower(),dic_typ[typ[i].lower()],node.type)
		else:
			t = typ[0].lower()
			for v in var:
				if ACT_BLOCK == MAIN_BLOCK:
					do_main_set_var(v,t)
				else:
					do_frame_set_var(v,t,dic_typ[t],node.type)

def do_main_set_var(v,t):
	w = set_var(v,t)
	f.write("%s %s;\n" % (w[0],w[1]))

def do_frame_set_var(v,t,dt,node):
	w = frames[ACT_BLOCK].set_var(v,t,dt)
	if node == "variable_declaration":
		nt = dic_typ[w[0]]
		f.write( "sp->locals[%s]=(%s*)malloc(sizeof(%s));\n" % (w[1],nt,nt) )
	else:
		f.write( "sp->locals[%s]=sp->parent->outgoing[%s];\n" % (w[1],w[1]) )

def translate_printf_var(name,typ_par,par):
	if name == "writeln":
		typ_par = "\"" + typ_par + "\\n\""
	else:
		typ_par = "\"" + typ_par + "\""
	f.write("printf(%s, %s);\n" % (typ_par,par) )

def translate_printf(name,par):
	par = par.replace("\'","\"")
	if name == "writeln":
		par = par[:-1]
		par = par + "\\n\""
	f.write("printf(%s);\n" % (par))

def set_var(v,t):
	global var_counter
	next = "g"+str(var_counter)
	global_vars[v] = next
	var_type[next] = t
	var_counter += 1
	return (dic_typ[var_type[next]],next)

def get_list(lis):
	if type(lis) == type([]):
		return "(%s)" % " ".join([ get_list(i) for i in lis ])
	else:
		return str(lis)

def translate_header():
	f.write(  "#include \"frame.h\"\n"
			"#include <stdlib.h>\n"
			"#include <stdio.h>\n"
			"#define FALSE 0\n"
			"#define TRUE 1\n\n"
			"int main()\n{\n"
			"int _ra;\n"
			"frame* fp=NULL;\n"
			"frame* sp=NULL;\n"
			"sp=(frame*)malloc(sizeof(frame));\n"
		)

def translate_footer():
	translate_redirector()
	f.write(  "return 0;\n"
			"}\n\n"
		)

def translate_proc_1st(name):
	f.write(  "goto %sskip;\n" % (name) )
	f.write(  "%s:\n" % (name) )
	f.write(  "fp=sp;\n"
			"sp=(frame*)malloc(sizeof(frame));\n"
			"sp->parent=fp;\n"
			"sp->return_address=_ra;\n"
		)

def translate_proc_2nd(name):
	f.write(  "_ra=sp->return_address;\n"
			"sp=sp->parent;\n"
			"fp=sp->parent;\n"
			"goto redirector;\n"
		)
	f.write(  "%sskip:\n" % (name) )

def translate_redirector():
	global return_counter
	f.write(  "goto exit;\n"
			"redirector:\n"
		)

	for i in range(return_counter):
		f.write("if(_ra==%d) goto return%d;\n" % (i,i))

	f.write("exit:\n")

def translate_call_stat(name,par,var=None):
	global return_counter
	if par != None:
		for i in range(len(par)):
			t = None
			act = par[i][0]
			if ACT_BLOCK == MAIN_BLOCK:
				if act in var_type:
					t = dic_typ[var_type[act]]
			else:
				if act in frames[ACT_BLOCK].var_type:
					t = dic_typ[frames[ACT_BLOCK].var_type[act]]
			if t==None:
				t = get_type(act)
			f.write(  "sp->outgoing[%s] = (%s*)malloc(sizeof(%s));\n" % (str(i),t,t) )
			f.write(  "*((%s*)sp->outgoing[%s]) = %s;\n" % (t,str(i),str(act) ) )

	f.write(  "_ra=%d;\n" % (return_counter) )
	f.write(  "goto %s;\n" % (name.lower()) )
	f.write(  "return%d:\n" % (return_counter) )
	if var !=None:
		t = dic_typ[frames[name].return_typ]
		if ACT_BLOCK == MAIN_BLOCK:
			f.write("%s = *((%s*)sp->return_val[0]);\n" % (global_vars[var],t) )
		else:
			if var in frames[ACT_BLOCK].global_vars:
				f.write("%s = *((%s*)sp->return_val[0]);\n" % (frames[ACT_BLOCK].global_vars[var],t) )
			else:
				f.write("%s = *((%s*)sp->return_val[0]);\n" % (global_vars[var],t) )
	return_counter += 1

def get_type(v):
	if type(v) == type(1):
		return "int"
	elif type(v) == type(1.2):
		return "float"
	elif len(v) == 3:
		return "char"
	else:
		return "int"


# -*- coding: utf-8 -*-
"""
Spyder Editor

This is a temporary script file.
"""
import torch as T
from torch import nn
import torch.nn.functional as F
from torch import optim
from tqdm import tqdm
import os
from torch.utils.data import Dataset
import torchvision
import numpy as np
from PIL import Image
from tensorboardX import SummaryWriter
import datetime

if os.path.exists('/Users/taurine511/Desktop/abc32/.DS_Store'):
    os.remove('/Users/taurine511/Desktop/abc32/.DS_Store')

def Writer(nb_name):
    dt_now = datetime.datetime.now()
    exp_time = dt_now.strftime('%Y%m%d_%H:%M:%S')
    return SummaryWriter("runs/"+nb_name+'___'+exp_time)

def initialize_weights(m):
    if isinstance(m, nn.Linear) or isinstance(m, nn.ConvTranspose2d) or isinstance(m, nn.Conv2d):
        nn.init.xavier_uniform_(m.weight.data)

def upload(writer,loss,epoch,mode):
    for i in loss.keys():
        writer.add_scalar(f'{mode}_{i}',loss[i],epoch)

def get_path(ind,ds,root,y_dim):
    return f'{root}/{ds[ind//y_dim]}/{ind%y_dim}.png'

class NormalDataset(Dataset):
    def __init__(self, root, y_dim,transform=torchvision.transforms.ToTensor()):
        super().__init__()

        self.y_dim = y_dim
        self.root = root
        self.ds = os.listdir(root)
        self.len = len(self.ds)*y_dim
        self.transform = transform

    def __len__(self):
        return self.len

    def __getitem__(self, index):

        path = get_path(index,self.ds,self.root,self.y_dim)
        image = np.array(Image.open(path)).astype(np.float32).transpose((2,0,1))[0]
        image /= 255

        char = F.one_hot(T.tensor(index%self.y_dim),self.y_dim)
        image = self.transform(image)

        return image, char

class MyDataset(Dataset):
    def __init__(self, root, y_dim,category,transform=None):
        super().__init__()

        self.y_dim = y_dim
        self.root = root
        self.ds = os.listdir(root)
        self.len = len(self.ds)
        self.transform = transform
        self.category = category

    def __len__(self):
        return self.len

    def __getitem__(self, index):

        path = get_path(26*index+self.category,self.ds,self.root,self.y_dim)
        image = np.array(Image.open(path)).astype(np.float32).transpose((2,0,1))[0]
        image /= 255

        char = F.one_hot(T.tensor(self.category),self.y_dim)

        if self.transform:
            image = self.transform(image)
        return image, char

def get_colab_path(ind,ds,root,y_dim):
    font = ind//(y_dim*y_dim)
    rest = ind%(y_dim*y_dim)
    st = f'{root}/{ds[font]}/{rest%y_dim}.png'
    en = f'{root}/{ds[font]}/{rest//y_dim}.png'
    return [st,en]

class ColabDataset(Dataset):
    def __init__(self, root, y_dim,transform=None):
        super().__init__()

        self.y_dim = y_dim
        self.root = root
        self.ds = os.listdir(root)
        self.len = len(self.ds)*(y_dim**2)
        self.transform = transform

    def __len__(self):
        return self.len

    def __getitem__(self, index):

        label = [index%self.y_dim,index%(self.y_dim**2)//self.y_dim]
        path = get_colab_path(index,self.ds,self.root,self.y_dim)
        image_1 = self.trans(path[0])
        image_2 = self.trans(path[1])
        char_1 = F.one_hot(T.tensor(label[0]),self.y_dim)
        char_2 = F.one_hot(T.tensor(label[1]),self.y_dim)

        if self.transform:
            image_1 = self.transform(image_1)
            image_2 = self.transform(image_2)
        return image_1,image_2, char_1, char_2

    def trans(self,path):
        image = np.array(Image.open(path)).astype(np.float32).transpose((2,0,1))[0]
        image /= 255
        return image

def get_rand_loader(root,y_dim,batch_size):
    dataset = ColabDataset(root,y_dim,torchvision.transforms.ToTensor())
    t = int(len(dataset)*0.9)

    train_dataset, test_dataset = T.utils.data.random_split(
        dataset,
        [t, len(dataset)-t]
    )

    train_loader = T.utils.data.DataLoader(
        train_dataset,
        batch_size=batch_size,
        shuffle=True,
    )

    test_loader = T.utils.data.DataLoader(
        test_dataset,
        batch_size=batch_size,
        shuffle=False,
    )
    return train_loader, test_loader

def get_loaders(root,y_dim,batch_size,Dataset=MyDataset):
    train_loaders,test_loaders = [], []
    for i in range(y_dim):
        dataset = Dataset(root,y_dim,i,torchvision.transforms.ToTensor())
        t = int(len(dataset)*0.9)

        train_dataset, test_dataset = T.utils.data.random_split(
            dataset,
            [t, len(dataset)-t]
        )

        train_loader = T.utils.data.DataLoader(
            train_dataset,
            batch_size=batch_size,
            shuffle=True,
        )

        test_loader = T.utils.data.DataLoader(
            test_dataset,
            batch_size=batch_size,
            shuffle=False,
        )
        train_loaders.append(train_loader)
        test_loaders.append(test_loader)
    return train_loaders, test_loaders

class Residual(nn.Module):
    def __init__(self,inc,h_dim,n_res_h):
        super(Residual,self).__init__()

        self.layer = nn.Sequential(
            nn.ReLU(),
            nn.Conv2d(inc,n_res_h,3,1,1),
            nn.ReLU(),
            nn.Conv2d(n_res_h,h_dim,1,1),
        )

    def forward(self,x):
        h = self.layer(x)
        return x+h

class Res_stack(nn.Module):
    def __init__(self,inc,h_dim,n_res_h,n_layer):
        super(Res_stack,self).__init__()
        self.n_layer = n_layer
        self.layer = nn.Sequential(
            *[Residual(inc,h_dim,n_res_h) for _ in range(n_layer)],
            nn.ReLU()
        )

    def forward(self,x):
        return self.layer(x)

def block(in_dim,out_dim,activate=nn.ReLU(),norm=False):
    layer = [nn.Conv2d(in_dim,out_dim,4,2,1)]
    layer.append(activate)
    if norm:
        layer.append(nn.BatchNorm2d(out_dim))
    return layer

def block_t(in_dim,out_dim,activate=nn.ReLU(),norm=False):
    layer = [nn.ConvTranspose2d(in_dim,out_dim,4,2,1)]
    if norm:
        layer.append(nn.BatchNorm2d(out_dim))
    layer.append(activate)
    return layer

class Flatten(nn.Module):
    def forward(self, x):
        N, _, _, _ = x.size() # read in N, C, H, W
        return x.view(N, -1)  # "flatten" the C * H * W values into a single vector per image

class Unflatten(nn.Module):
    """
    An Unflatten module receives an input of shape (N, C*H*W) and reshapes it
    to produce an output of shape (N, C, H, W).
    """
    def __init__(self, N=-1, C=128, H=7, W=7):
        super(Unflatten, self).__init__()
        self.N = N
        self.C = C
        self.H = H
        self.W = W

    def forward(self, x):
        return x.view(self.N, self.C, self.H, self.W)


from django.core.management import call_command
from django.test import TestCase
from django.utils import timezone

from ais.models import Waternet, WaternetSnapshot

class TestWaternetImporter(TestCase):
    fixtures = ['waternet_test.json']

    def test_ok(self):
        call_command('import_waternet')
        self.assertEqual(Waternet.objects.count(), 18)

    def test_extra_field_ignored(self):
        WaternetSnapshot.objects.all().delete()
        WaternetSnapshot.objects.create(data=[{
            'Id': '120',
            'ExtraField': 12,
            "Sensor": 'test',
            "Speed": 1,
            'Position': {
                "x": 4.919753551483154,
                "y": 52.3687858581543
            },
            'Direction': 2658,
            'Status': 15,
            'Lastupdate': "2019-07-24T14:18:06.000Z"
        }])
        call_command('import_waternet')
        self.assertEqual(Waternet.objects.count(), 1)

    def test_iterate_raw_model(self):
        iterator = WaternetSnapshot.objects.query_iterator(2)

        self.assertEqual(len(next(iterator)), 2)
        self.assertEqual(len(next(iterator)), 2)
        self.assertEqual(len(next(iterator)), 1)

        with self.assertRaises(StopIteration):
            next(iterator)

    def test_only_latest(self):
        call_command('import_waternet')
        self.assertEqual(Waternet.objects.count(), 18)

        hour_later = timezone.now() + timezone.timedelta(hours=1)
        WaternetSnapshot.objects.filter(pk=1).update(scraped_at=hour_later)

        call_command('import_waternet')
        self.assertEqual(Waternet.objects.count(), 21)

    def test_correct_timezone(self):
        call_command('import_waternet')

        waternet = Waternet.objects.order_by('id').first()
        correct_pub_date = timezone.datetime(2019, 7, 24, 14, 18)

        self.assertEqual(waternet.lastupdate.date(), correct_pub_date.date())
        self.assertEqual(waternet.lastupdate.hour, correct_pub_date.hour)
        self.assertEqual(waternet.lastupdate.minute, correct_pub_date.minute)

        correct_scraped_at = timezone.datetime(2019, 7, 24, 14, 26)

        self.assertEqual(waternet.scraped_at.date(), correct_scraped_at.date())
        self.assertEqual(waternet.scraped_at.hour, correct_scraped_at.hour)
        self.assertEqual(waternet.scraped_at.minute, correct_scraped_at.minute)


#!/usr/bin/env python3

import os
import sys
import copy
import shutil
import argparse
import subprocess

class Command(object):
    def __init__(self, executable, *args, verbose=False):
        self.executable = executable
        self.args = args
        self.verbose = verbose

    def __str__(self):
        return self.executable + ' ' + ' '.join(self.args)

    def execute(self):
        if self.verbose: print(' > ' + str(self))
        out = None if self.verbose else subprocess.PIPE
        # Awful hack because echo command has no effect with subprocess.run, and I don't know why.
        if self.executable == 'echo':
            with open(self.args[-1], 'a') as f:
                f.write(self.args[0].replace('"', '')+'\n\n')
        else:
            subprocess.run([self.executable, *self.args], check=True, shell=False, stdout=out, stderr=out)

class GitCommand(Command):
    def __init__(self, git_command, *args, verbose=False):
        super(GitCommand, self).__init__('git', git_command, *args, verbose=verbose)

class GitProject(object):
    def __init__(self, folder_name, always_proceed=False, verbose=False):
        self.folder_name = folder_name
        self.always_proceed = always_proceed
        self.verbose = verbose
        self.commands = [GitCommand('init', verbose=verbose)]

    def _append_command(self, executable, *args):
        self.commands.append(Command(executable, *args, verbose=self.verbose))

    def _append_echo_command(self, filename, content):
        self._append_command('echo', '\"' + content + '\"', '>>', filename)

    def git(self, command, *args):
        self.commands.append(GitCommand(command, *args, verbose=self.verbose))

    def append_to_readme(self, content):
        self._append_command('touch', 'README.md')
        self._append_echo_command('README.md', content)
        self.git('add', '.')
        self.git('commit', '-m', 'README')

    def create_new_file(self, filename, content=None, message=None):
        self._append_command('touch', filename)
        if content is not None:
            self._append_echo_command(filename, content)
        self.git('add', '.')
        if message is None:
            message = filename
        self.git('commit', '-m', message)

    def append_content_to_file(self, filename, content, message=None):
        self._append_echo_command(filename, content)
        self.git('add', '.')
        if message is None:
            message = filename
        self.git('commit', '-m', message)

    def override_file_content(self, filename, new_content, message=None):
        self._append_command('rm', '-f', filename)
        self._append_command('touch', filename)
        self._append_echo_command(filename, new_content)
        self.git('add', '.')
        if message is None:
            message = filename
        self.git('commit', '-m', message)

    def reset(self):
        if not self.always_proceed:
            answer = input(' ** WARNING : I am about to erase folder : {0}. Proceed ? [yN]'.format(self.folder_name))
        else:
            answer = 'y'
        if answer == 'y':
            shutil.rmtree(self.folder_name, ignore_errors=True)
        else:
            print(' Ok, fine. Not touching anything.')
        return (answer == 'y')

    def initialize(self):
        os.mkdir(self.folder_name)
        os.chdir(self.folder_name)

    def create(self):
        if self.reset():
            current_dir = os.getcwd()
            self.initialize()
            for command in self.commands:
                command.execute()
            os.chdir(current_dir)

    def duplicate(self, new_folder_name):
        new_self = copy.deepcopy(self)
        new_self.folder_name = new_folder_name
        return new_self

if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument("-v", "--verbose", help="display the commands being executed", action="store_true")
    parser.add_argument("-p", "--always_proceed", help="display the commands being executed", action="store_true")
    args = parser.parse_args()

    gp = GitProject('git-book-v2-chapter-3.1-branches-in-a-nutshell', always_proceed=args.always_proceed, verbose=args.verbose)
    gp.create_new_file('98ca9.txt')
    gp.create_new_file('34ac2.txt')
    gp.create_new_file('f30ab.txt')
    gp.git('branch', 'testing')
    gp.git('checkout', 'testing')
    gp.create_new_file('87ab2.txt')
    gp.git('checkout', 'master')
    gp.create_new_file('c2b9e.txt')
    gp.create()

    gp = GitProject('git-book-v2-chapter-3.2-basic-branching-and-merging-1-figure-21', always_proceed=args.always_proceed, verbose=args.verbose)
    gp.append_to_readme('### Git Book v2 Chapter 3.2 : Figure 21')
    gp.append_to_readme('**Purpose** : do the merge and the delete of hotfix branch yourself.')
    gp.append_to_readme('![Figure 21](https://git-scm.com/book/en/v2/images/basic-branching-4.png)')
    gp.create_new_file('index.html', 'line master c0', message='c0')
    gp.append_content_to_file('index.html', 'line master c1', message='c1')
    gp.append_content_to_file('index.html', 'line master c2', message='c2')
    gp.git('branch', 'iss53')
    gp.git('checkout', 'iss53')
    gp.append_content_to_file('index.html', 'line iss53 c3', message='c3')
    gp.git('checkout', 'master')
    gp.git('branch', 'hotfix')
    gp.git('checkout', 'hotfix')
    gp.append_content_to_file('index.html', 'line hotfix c4', message='c4')
    gp.create()

    gp = GitProject('git-book-v2-chapter-3.2-basic-branching-and-merging-2-figure-24-no-conflict', always_proceed=args.always_proceed, verbose=args.verbose)
    gp.append_to_readme('### Git Book v2 Chapter 3.2 : Figure 24')
    gp.append_to_readme('**Purpose** : do the merge and the delete of iss53 branch yourself.')
    gp.append_to_readme('![Figure 24](https://git-scm.com/book/en/v2/images/basic-merging-1.png)')
    gp.create_new_file('index.html', 'line master c0', message='c0')
    gp.append_content_to_file('index.html', 'line master c1', message='c1')
    gp.append_content_to_file('index.html', 'line master c2', message='c2')
    gp.git('branch', 'iss53')
    gp.git('checkout', 'iss53')
    gp.append_content_to_file('index.html', 'line iss53 c3', message='c3')
    gp.git('checkout', 'master')
    gp.append_content_to_file('index.html', 'line master c4', message='c4')
    gp.git('checkout', 'iss53')
    gp.append_content_to_file('index.html', 'line iss53 c5', message='c5')
    gp.create()

    gp = GitProject('git-book-v2-chapter-3.2-basic-branching-and-merging-3-figure-24-with-conflict', always_proceed=args.always_proceed, verbose=args.verbose)
    gp.append_to_readme('### Git Book v2 Chapter 3.2 : Figure 24')
    gp.append_to_readme('**Purpose** : do the merge by resolving the conflict.')
    gp.append_to_readme('![Figure 24](https://git-scm.com/book/en/v2/images/basic-merging-1.png)')
    gp.create_new_file('index.html', 'line master c0', message='c0')
    gp.append_content_to_file('index.html', 'line master c1', message='c1')
    gp.append_content_to_file('index.html', 'line master c2', message='c2')
    gp.git('branch', 'iss53')
    gp.git('checkout', 'iss53')
    gp.append_content_to_file('index.html', 'line iss53 c3', message='c3')
    gp.git('checkout', 'master')
    gp.append_content_to_file('index.html', 'line master c4', message='c4')
    gp.git('checkout', 'iss53')
    gp.override_file_content('index.html', 'line master c0\n\nline master c1\n\nline master c2\n\nline master \nc4\nhere is a conflicting line...', message='c5')
    gp.create()

    gp = GitProject('git-book-v2-chapter-3.6-git-branching-rebasing-1-figure-35', always_proceed=args.always_proceed, verbose=args.verbose)
    gp.append_to_readme('### Git Book v2 Chapter 3.6 : Figure 35')
    gp.append_to_readme('**Purpose** : do the rebase yourself.')
    gp.append_to_readme('![Figure 35](https://git-scm.com/book/en/v2/images/basic-rebase-1.png)')
    gp.create_new_file('index.html', 'line master c0', message='c0')
    gp.append_content_to_file('index.html', 'line master c1', message='c1')
    gp.append_content_to_file('index.html', 'line master c2', message='c2')
    gp.git('branch', 'experiment')
    gp.append_content_to_file('index.html', 'line master c3', message='c3')
    gp.git('checkout', 'experiment')
    gp.append_content_to_file('index.html', 'line experiment c4', message='c4')
    gp.create()

    gp = GitProject('git-book-v2-chapter-3.6-git-branching-rebasing-2-figure-39', always_proceed=args.always_proceed, verbose=args.verbose)
    gp.append_to_readme('### Git Book v2 Chapter 3.6 : Figure 39')
    gp.append_to_readme('**Purpose** : do the rebase yourself up to Figure 43.')
    gp.append_to_readme('![Figure 39](https://git-scm.com/book/en/v2/images/interesting-rebase-1.png)')
    gp.create_new_file('index.html', 'line master c1', message='c1')
    gp.append_content_to_file('index.html', 'line master c2', message='c2')
    gp.git('branch', 'server')
    gp.git('checkout', 'server')
    gp.append_content_to_file('index.html', 'line server c3', message='c3')
    gp.git('branch', 'client')
    gp.append_content_to_file('index.html', 'line server c4', message='c4')
    gp.git('checkout', 'master')
    gp.append_content_to_file('index.html', 'line master c5', message='c5')
    gp.append_content_to_file('index.html', 'line master c6', message='c6')
    gp.git('checkout', 'client')
    gp.append_content_to_file('index.html', 'line master c8', message='c8')
    gp.append_content_to_file('index.html', 'line master c9', message='c9')
    gp.git('checkout', 'server')
    gp.append_content_to_file('index.html', 'line master c10', message='c10')
    gp.create()


from __future__ import division, print_function
import numpy as np

from openmdao.api import ExplicitComponent

class BreguetRange(ExplicitComponent):
    """
    Computes the fuel burn using the Breguet range equation using
    the computed CL, CD, weight, and provided specific fuel consumption, speed of sound,
    Mach number, initial weight, and range.

    Note that we add information from each lifting surface.

    Parameters
    ----------
    CL : float
        Total coefficient of lift (CL) for the lifting surface.
    CD : float
        Total coefficient of drag (CD) for the lifting surface.
    weight : float
        Total weight of the structural spar.

    Returns
    -------
    fuelburn : float
        Computed fuel burn in kg based on the Breguet range equation.

    """

    def initialize(self):
        self.options.declare('surfaces', types=list)

    def setup(self):
        for surface in self.options['surfaces']:
            name = surface['name']
            self.add_input(name + '_structural_weight', val=1., units='N')

        self.add_input('CT', val=0.25, units='1/s')
        self.add_input('CL', val=0.7)
        self.add_input('CD', val=0.02)
        self.add_input('speed_of_sound', val=100., units='m/s')
        self.add_input('R', val=3000., units='m')
        self.add_input('Mach_number', val=1.2)
        self.add_input('W0', val=200., units='kg')
        self.add_input('load_factor', val=1.05)

        self.add_output('fuelburn', val=1., units='kg')

        self.declare_partials('*', '*')
        self.set_check_partial_options(wrt='*', method='cs', step=1e-30)

    def compute(self, inputs, outputs):

        g = 9.80665 * inputs['load_factor']
        CT = inputs['CT']
        a = inputs['speed_of_sound']
        R = inputs['R']
        M = inputs['Mach_number']
        W0 = inputs['W0'] * g

        # Loop through the surfaces and add up the structural weights
        # to get the total structural weight.
        Ws = 0.
        for surface in self.options['surfaces']:
            name = surface['name']
            Ws += inputs[name + '_structural_weight']

        CL = inputs['CL']
        CD = inputs['CD']

        fuelburn = (W0 + Ws * inputs['load_factor']) * (np.exp(R * CT / a / M * CD / CL) - 1)

        # Convert fuelburn from N to kg
        outputs['fuelburn'] = fuelburn / 9.80665

    def compute_partials(self, inputs, partials):

        g = 9.80665 * inputs['load_factor']
        CT = inputs['CT']
        a = inputs['speed_of_sound']
        R = inputs['R']
        M = inputs['Mach_number']
        W0 = inputs['W0'] * g

        Ws = 0.
        for surface in self.options['surfaces']:
            name = surface['name']
            Ws += inputs[name + '_structural_weight']

        CL = inputs['CL']
        CD = inputs['CD']

        dfb_dCL = -(W0 + Ws * inputs['load_factor']) * np.exp(R * CT / a / M * CD / CL) \
            * R * CT / a / M * CD / CL ** 2
        dfb_dCD = (W0 + Ws * inputs['load_factor']) * np.exp(R * CT / a / M * CD / CL) \
            * R * CT / a / M / CL
        dfb_dCT = (W0 + Ws * inputs['load_factor']) * np.exp(R * CT / a / M * CD / CL) \
            * R / a / M / CL * CD
        dfb_dR = (W0 + Ws * inputs['load_factor']) * np.exp(R * CT / a / M * CD / CL) \
            / a / M / CL * CD * CT
        dfb_da = -(W0 + Ws * inputs['load_factor']) * np.exp(R * CT / a / M * CD / CL) \
            * R * CT / a**2 / M * CD / CL
        dfb_dM = -(W0 + Ws * inputs['load_factor']) * np.exp(R * CT / a / M * CD / CL) \
            * R * CT / a / M**2 * CD / CL

        dfb_dW = np.exp(R * CT / a / M * CD / CL) - 1

        partials['fuelburn', 'CL'] = dfb_dCL / 9.80665
        partials['fuelburn', 'CD'] = dfb_dCD / 9.80665
        partials['fuelburn', 'CT'] = dfb_dCT / 9.80665
        partials['fuelburn', 'speed_of_sound'] = dfb_da / 9.80665
        partials['fuelburn', 'R'] = dfb_dR / 9.80665
        partials['fuelburn', 'Mach_number'] = dfb_dM / 9.80665
        partials['fuelburn', 'W0'] = dfb_dW * inputs['load_factor']
        partials['fuelburn', 'load_factor'] = (W0 / inputs['load_factor'] + Ws) * dfb_dW / 9.80665

        for surface in self.options['surfaces']:
            name = surface['name']
            inp_name = name + '_structural_weight'
            partials['fuelburn', inp_name] = dfb_dW / 9.80665 * inputs['load_factor']


#User function Template for python3

class Solution:
    def CountPS(self, S, N):
        count = 0

        # Helper function to expand around the center
        def expand_around_center(left, right):
            nonlocal count
            while left >= 0 and right < N and S[left] == S[right]:
                # Found a palindromic substring
                count += 1
                left -= 1
                right += 1

        # Iterate through each character as the potential center
        for i in range(N):
            # Expand around the center for odd-length palindromes
            expand_around_center(i, i)

            # Expand around the center for even-length palindromes
            expand_around_center(i, i + 1)

        return count - N  # Subtract N to exclude single-character palindromes

#{
 # Driver Code Starts
#Initial Template for Python 3

if __name__ == '__main__':

    t = int(input())

    for _ in range(t):
        N = int(input())
        S = input()

        solObj = Solution()

        print(solObj.CountPS(S,N))
# } Driver Code Ends

Count Palindrome Sub-Strings of a String - GFG/count-palindrome-sub-strings-of-a-string.py


import cantools
from can.message import Message
db = cantools.db.load_file('/home/wi/Downloads/honda.dbc')

speed = db.get_message_by_name('WHEEL_SPEEDS')
speed_data = speed.encode({'WHEEL_SPEED_FL':100, 'WHEEL_SPEED_FR': 100, 'WHEEL_SPEED_RL': 100, 'WHEEL_SPEED_RR': 100},'utf-8')

speed_d_data = speed_data.hex()

import can
bus = can.interface.Bus(bustype = 'socketcan', channel = 'vcan0', bitrate = 250000)
speed_CAN = can.Message(arbitration_id = speed.frame_id, data = speed_data, is_extended_id = False)

try:
    bus.send(speed_CAN)
    print("Message sent on {}".format(bus.channel_info))
except can.CanError:
    print("Message NOT sent")


import logging.handlers
import os
from config import base_path

class GetLog:
    # 新建日志器变量
    __logger = None
    # 新建获取日志器方法

    @classmethod
    def get_logger(cls):
        # 判断日志器为空：
        if cls.__logger is None:
            # 获取日志器
            cls.__logger = logging.getLogger()
            # 设置日志等级
            cls.__logger.setLevel(logging.INFO)
            # 获取日志处理器对象
            # sh = logging.StreamHandler()
            th = logging.FileHandler(filename=os.path.join(base_path, "log", "api.log"), encoding="utf-8")
            # 设置处理器获取日志级别

            # 添加格式器
            fmt = "%(asctime)s %(levelname)s [%(filename)s (%(funcName)s：%(lineno)d)] - %(message)s"
            fm = logging.Formatter(fmt)
            # 将格式器添加到处理器对象中
            th.setFormatter(fm)
            # 添加处理器添加到日志器中
            cls.__logger.addHandler(th)
        # 返回日志器
        return cls.__logger

if __name__ == '__main__':
    log = GetLog.get_logger()
    log.info("测试：info\n")
    log.warning("测试：warning")
    log.error("测试：error")


#!/usr/bin/python
import json, re, sys, csv
from time import time
import spacy
import en_core_web_sm
# Spacy model setup (NOTE - change to lg to include vectors)
nlp = en_core_web_sm.load()

with open('train_data.json', 'r') as train_data:
    data = json.load(train_data)

##################################################################
def getLemmatizer():
    from spacy.lemmatizer import Lemmatizer
    from spacy.lang.en import LEMMA_INDEX, LEMMA_EXC, LEMMA_RULES
    lemmatizer = Lemmatizer(LEMMA_INDEX, LEMMA_EXC, LEMMA_RULES)
    return lemmatizer

def getTokens(doc):
    tokens = []
    for tok in doc:
        if not tok.is_stop:
            tokens.append({ 'word':tok.lemma_, 'pos':tok.pos_ })
    return tokens

def getEntities(doc):
    ents = {}
    for ent in doc.ents:
        if not ent.text.isspace():
            ents[ent.text] = ent.label_
    return ents

def clean(text):
    # spacing out special characters in preparation for abbreviations
    clean = re.sub('[\*\#\@]', ' ', text).lower().strip().lstrip()
    clean = re.sub(r'([\;\,\.\%\"\-\(\)\:\$\!\?])', r' \1', clean)
    # putting special characters back in place
    clean = re.sub(r' ([\;\,\.\%\"\-\(\)\:\$\!\?])', r'\1', clean)
    clean = re.sub(r'(\w+)/(\w+)', r'\1 \2', clean).capitalize()
    clean = re.sub('[\*\;\&\#\,\$\@\.\%\"\'\-\(\)\:\$\!\?\+\[\]\s+]',' ', clean)
    return clean

def preprocessing(data):
    for tweet in data:
        tweet['clean'] = clean(tweet['text'])
        doc = nlp(tweet['text'])
        tweet['entities'] = getEntities(doc) #marks target entity
        tweet['tokens'] = getTokens(doc)   #adds POS, removes stopwords, and lemmatizes
    return data
##################################################################

processedComments = preprocessing(data)

# writes new parameters into input file
with open("spacy_output.json", 'w') as outfile:
    json.dump(processedComments, outfile, sort_keys=True, indent=2, separators=(',', ': '))


import matplotlib.pyplot as plt
import seaborn as sns
from pathlib import Path
import pandas as pd
import numpy as np
from collections import Counter, defaultdict

def get_summary_table(all_df: pd.DataFrame, start_week: int, end_week: int):
    df = all_df.loc[(start_week <= all_df.week) & (all_df.week <= end_week)]
    players = df.team.unique()

    column_counters = defaultdict(lambda: Counter({p: 0 for p in players}))

    for _, group in df.groupby("week"):
        for player in players:
            team_row = group.loc[group.team == player, "score"]
            if team_row.empty:
                continue

            score: float = team_row.values[0].item()
            all_scores: list[tuple[str, float]] = group.loc[:, ["team", "score"]].values.tolist()
            for opp, opp_score in all_scores:
                if player != opp:
                    column_counters["W"][player] += score > opp_score
                    column_counters["T"][player] += score == opp_score
                    column_counters["L"][player] += score < opp_score

    summary = pd.DataFrame(column_counters)
    team_grouped = df.groupby("team")
    week_grouped = df.groupby("week")

    summary["Pct"] = (summary["W"] + 0.5 * summary["T"]) / (
        summary["W"] + summary["T"] + summary["L"]
    )

    summary["Actual"] = team_grouped.apply(
        lambda tm: ((tm.score > tm.opp_score) + 0.5 * (tm.score == tm.opp_score)).sum()
    )

    has_ties = (df["score"] == df["opp_score"]).any()
    if not has_ties:
        summary["Actual"] = summary["Actual"].astype(int)

    games_played = team_grouped.week.nunique()
    summary["Exp"] = summary["Pct"] * games_played
    summary["Luck"] = summary["Actual"] - summary["Exp"]

    season = df["season"].unique().item()
    num_weeks = 14 if season > 2020 else 13
    weeks_left = np.maximum(num_weeks - games_played, 0)
    summary["Proj"] = summary["Actual"] + (summary["Pct"] * weeks_left)

    # TODO: remaining SOS (and then incorporate that into projected)

    summary["PF"] = team_grouped.score.sum()
    summary["PA"] = team_grouped.opp_score.sum()

    summary["Max"] = team_grouped.score.max()
    summary["Min"] = team_grouped.score.min()

    weekly_max = week_grouped.score.max()
    weekly_min = week_grouped.score.min()
    weekly_top3 = week_grouped.score.nth(2)
    weekly_bot3 = week_grouped.score.nth(-3)

    summary["Top1"] = team_grouped.apply(
        lambda tm: sum(
            score >= weekly_max[wk] for wk, score in tm.set_index("week").score.to_dict().items()
        )
    )
    summary["Bot1"] = team_grouped.apply(
        lambda tm: sum(
            score <= weekly_min[wk] for wk, score in tm.set_index("week").score.to_dict().items()
        )
    )
    summary["Top3"] = team_grouped.apply(
        lambda tm: sum(
            score >= weekly_top3[wk] for wk, score in tm.set_index("week").score.to_dict().items()
        )
    )
    summary["Bot3"] = team_grouped.apply(
        lambda tm: sum(
            score <= weekly_bot3[wk] for wk, score in tm.set_index("week").score.to_dict().items()
        )
    )

    summary["Carpe"] = summary["Actual"] / ((summary["W"] + 0.5 * summary["T"]) / games_played)

    summary = summary.sort_values("Pct", ascending=False).round(3)
    return summary

def plot_season_graphs(df: pd.DataFrame, start_week: int, end_week: int, out_dir: Path):
    summaries = [get_summary_table(df, start_week, end) for end in range(start_week, end_week + 1)]
    plot_configs = [
        (
            "Expected Wins",
            pd.concat(
                [summ["Exp"].rename(f"{i+1}") for i, summ in enumerate(summaries)],
                axis=1,
            ).T,
        ),
        (
            "Wins",
            pd.concat(
                [summ["Actual"].rename(f"{i+1}") for i, summ in enumerate(summaries)],
                axis=1,
            ).T,
        ),
        (
            "Expected Win%",
            pd.concat(
                [summ["Pct"].rename(f"{i+1}") for i, summ in enumerate(summaries)],
                axis=1,
            ).T,
        ),
        (
            "Points Per Game",
            pd.concat(
                [(summ["PF"] / (i + 1)).rename(f"{i+1}") for i, summ in enumerate(summaries)],
                axis=1,
            ).T,
        ),
        (
            "PF",
            pd.concat(
                [summ["PF"].rename(f"{i+1}") for i, summ in enumerate(summaries)],
                axis=1,
            ).T,
        ),
    ]

    plt.style.use("fivethirtyeight")
    for name, series in plot_configs:
        ordered_labels = series.tail(1).squeeze().sort_values(ascending=False).index.values.tolist()
        series = series.loc[:, ordered_labels]
        fig, ax = plt.subplots(sharex=True, figsize=(16 * 2, 9 * 2))
        fig.set_tight_layout(True)
        sns.lineplot(series, ax=ax)
        plt.legend(
            handles=ax.legend_.legendHandles,
            labels=ordered_labels,
        )
        ax.set_xlabel("Week")
        ax.set_ylabel(name)
        season = df.season.unique().item()
        ax.set_title(f"{name} Over {season} Season")
        fig.savefig(out_dir / f"plot_{name}.png", bbox_inches="tight")
        plt.close(fig)