Skip to main content

Barycentric method Loss Calculation from delunary tringles

Answered

Comments

2 comments

  • Riley Clement
    • Gurobi Staff Gurobi Staff

    Hi Parshwa,

    It seems you forgot to add your question.

    - Riley

    0
  • parshwa Bhavsar
    • First Comment
    • First Question

    Triangular File Explanation:

    The triangular file consists of multiple triangles generated through Delaunay triangulation, partitioning the state-of-charge (SOC) and power space into smaller segments. Each triangle is defined by three vertices, each containing:

    • State-of-charge (SOC, in %)
    • Power (in kW)
    • Corresponding losses (in kW)

    These triangles allow efficient and accurate piecewise-linear interpolation for battery losses, essential for optimization accuracy.

    Barycentric Coordinates Function Explanation:

    Barycentric coordinates (abc) are used to interpolate within each triangle. They represent weights for each vertex, calculated as follows:

    def barycentric_coordinates(self, x1, y1, x2, y2, x3, y3, x, y):
        v0x, v0y = x2 - x1, y2 - y1
        v1x, v1y = x3 - x1, y3 - y1
        denom = v0x * v1y - v1x * v0y
        inv_denom = 1.0 / denom
    
        a = (v1y * (x - x1) + v0x * (y - y1)) * inv_denom
        b = (v0y * (x - x1) + v1x * (y - y1)) * inv_denom
        c = 1.0 - a - b
    
        return a, b, c
    

    Model Implementation for Charging and Discharging:

    The implementation ensures accurate loss calculations using barycentric coordinates within selected triangles.

    M = 100  # Big-M method constant for constraint relaxation
    
    for period in range(self.SimPeriods):
        soc_rfb = (e_rfb[period] / self.RFBCapacity) * 100  # SOC percentage
    
        # === Charging Mode ===
        charging_loss_expr = gp.LinExpr()
    
        # Iterate through charging triangles to calculate losses
        for i, tri in enumerate(self.charge_triangles):
            v1, v2, v3 = tri["vertices"]
            x1, y1, z1 = v1
            x2, y2, z2 = v2
            x3, y3, z3 = v3
    
            # Calculate barycentric coordinates
            a, b, c = self.barycentric_coordinates(x1, y1, x2, y2, x3, y3, soc_rfb, p_to_rfb[period])
    
            # Binary variables for checking validity of coordinates
            valid_a_ch = self.Problem.addVar(vtype=gp.GRB.BINARY, name=f"valid_a_ch_{period}_{i}")
            valid_b_ch = self.Problem.addVar(vtype=gp.GRB.BINARY, name=f"valid_b_ch_{period}_{i}")
            valid_c_ch = self.Problem.addVar(vtype=gp.GRB.BINARY, name=f"valid_c_ch_{period}_{i}")
    
            # Constraints to ensure coordinates are within valid range [0,1]
            self.Problem.addConstr(a >= 0 - M * (1 - valid_a_ch))
            self.Problem.addConstr(a <= 1 + M * valid_a_ch)
            self.Problem.addConstr(b >= 0 - M * (1 - valid_b_ch))
            self.Problem.addConstr(b <= 1 + M * valid_b_ch)
            self.Problem.addConstr(c >= 0 - M * (1 - valid_c_ch))
            self.Problem.addConstr(c <= 1 + M * valid_c_ch)
    
            # Activate delta_ch if triangle conditions are valid
            self.Problem.addConstr(delta_ch[period, i] <= valid_a_ch)
            self.Problem.addConstr(delta_ch[period, i] <= valid_b_ch)
            self.Problem.addConstr(delta_ch[period, i] <= valid_c_ch)
            self.Problem.addConstr(delta_ch[period, i] >= valid_a_ch + valid_b_ch + valid_c_ch - 2)
    
            # Compute loss expression if triangle is selected
            charging_loss_expr = delta_ch[period, i] * (a * z1 + b * z2 + c * z3)
    
        # Constraint ensuring exactly one triangle is selected per period for charging
        self.Problem.addConstr(p_aux_losscharging_rfb_ch[period] == charging_loss_expr)
    
        # === Discharging Mode ===
        discharging_loss_expr = gp.LinExpr()
    
        for i, tri in enumerate(self.discharge_triangles):
            v1, v2, v3 = tri["vertices"]
            x1, y1, z1 = v1
            x2, y2, z2 = v2
            x3, y3, z3 = v3
    
            # Calculate barycentric coordinates
            a, b, c = self.barycentric_coordinates(x1, y1, x2, y2, x3, y3, soc_rfb, p_from_rfb[period])
    
            valid_a_dch = self.Problem.addVar(vtype=gp.GRB.BINARY, name=f"valid_a_dch_{period}_{i}")
            valid_b_dch = self.Problem.addVar(vtype=gp.GRB.BINARY, name=f"valid_b_dch_{period}_{i}")
            valid_c_dch = self.Problem.addVar(vtype=gp.GRB.BINARY, name=f"valid_c_dch_{period}_{i}")
    
            self.Problem.addConstr(a >= 0 - M * (1 - valid_a_dch))
            self.Problem.addConstr(a <= 1 + M * valid_a_dch)
            self.Problem.addConstr(b >= 0 - M * (1 - valid_b_dch))
            self.Problem.addConstr(b <= 1 + M * valid_b_dch)
            self.Problem.addConstr(c >= 0 - M * (1 - valid_c_dch))
            self.Problem.addConstr(c <= 1 + M * valid_c_dch)
    
            self.Problem.addConstr(delta_dch[period, i] <= valid_a_dch)
            self.Problem.addConstr(delta_dch[period, i] <= valid_b_dch)
            self.Problem.addConstr(delta_dch[period, i] <= valid_c_dch)
            self.Problem.addConstr(delta_dch[period, i] >= valid_a_dch + valid_b_dch + valid_c_dch - 2)
    
            discharging_loss_expr = delta_dch[period, i] * (a * z1 + b * z2 + c * z3)
    
        self.Problem.addConstr(p_aux_lossdischarging_rfb_dch[period] == discharging_loss_expr)
    

    Ensuring Single Triangle Selection:

    To guarantee the selection of exactly one triangle, add:

    self.Problem.addConstr(gp.quicksum(delta_ch[period, i] for i in range(num_triangles)) == 1)
    self.Problem.addConstr(gp.quicksum(delta_dch[period, i] for i in range(num_triangles)) == 1)
    

    This ensures the solver selects only the optimal triangle, effectively ignoring others.

    "I'm solving an optimization problem to estimate auxiliary losses in a Redox Flow Battery (RFB) using measured SOC-Power data. The losses depend on SOC and Power, so I applied Delaunay triangulation to divide the SOC-Power space into triangles, where each vertex has a known loss value. Using barycentric interpolation, I estimate losses for a given SOC and Power and integrate this into a Mixed Integer Linear Programming (MILP) model.

    The key steps in my approach:

    Binary variables select the triangle containing the (SOC, Power) point. Barycentric weights (a, b, c) are computed. The loss is interpolated as: Loss = a * Z1 + b * Z2 + c * Z3 where Z1, Z2, Z3 are the loss values at triangle vertices. The MILP model minimizes total cost, including these losses. Issue:

    The optimizer sometimes fails to correctly assign (SOC, Power) to the right triangle, leading to incorrect loss calculations. The barycentric weight constraints (a, b, c) might not be enforced properly in MILP. Big-M constraints could be causing numerical instability. I need guidance on how to properly integrate Delaunay triangulation into MILP, ensuring correct triangle selection and loss calculation. i want to know that the way i have implented constrin for barycentric that is right or not as i am getting error and zero losses ?

    0

Please sign in to leave a comment.