pythoncvxpyconvex-optimization

In CVXPY, how would you make a boolean variable to check if something has changed?


I have an issue when using CVXPY that I wish to calculate the input flow for a calculation for an additional constraint within my program, I have a selection boolean variable that I am using to determine the flow rate which in turn is used to reshape a vector to fit what I need.

In this sense I am calculating estimated reservoir flows over a 24 hour period, so the selected flows are set across 7 periods of varying time periods (split into 30 minute intervals), the problem I am trying to sort is that often, it could take maybe 4 30 minute periods to go from say 15 l/s to the desired 17 l/s flow rate which can ultimate have a large effect on my calculation for smaller surface areas which is what I wish to eliminate here.

Example output currently for 1 period out of 7 (00:00 - 08:00):
[120 120 120 120 120 120 120 120 120 120 120 120 120 120 120 120]

# Imagine our ramp rate is actually 0.5l/s per 30 minutes and currently at 118l/s
Expected output:
[118 118.5 119 119.5 120 120 120 120 120 120 120 120 120 120 120 120]

I hope above example makes sense to what I wish to achieve

See below my current solution that I have implemented without a ramp rate developed in to the current problem.

        FACTOR = 1/self.SURFACE_AREA
        input_flow_matrix=np.zeros((max(period_lengths),len(period_lengths)))
        for i,l in enumerate(period_lengths):
            input_flow_matrix[:l,i]=1
        selection = cp.Variable(shape=cost_.shape,boolean=True)
        assignment_constraint = cp.sum(selection,axis=1) == 1
        input_flow_= cp.sum(cp.multiply(flow_,selection),axis=1)
        input_flow_vector=cp.vec(cp.multiply(input_flow_matrix,np.ones((max(period_lengths), 1)) @ cp.reshape(input_flow_,(1,len(period_lengths)))))

        res_flow= (input_flow_vector-cp.vec(out_flow_))
        net_volume = res_flow * 1.8
        res_level=cp.cumsum(net_volume) * FACTOR + initial_level
        volume_= cp.sum(cp.multiply(volume_,selection))
        volume_constraint = volume_ >= v_min
        min_level_constraint = res_level >= min_level
        max_level_constraint = res_level <= max_level

        constraints = [assignment_constraint, max_level_constraint, min_level_constraint, volume_constraint]

        cost_ = cp.sum(cp.multiply(cost_,selection))
        assign_prob = cp.Problem(cp.Minimize(cost_),constraints)
        assign_prob.solve(solver=cp.CPLEX, verbose=False)

My assumption here would be to include a boolean variable that would indicate if the flow rate is changing across my 7 periods which is from the input_flow_ variable. However I am just unsure how to actually develop a good solution, would this be needed over a matrix or something similar? Any help would be much appreciated.

I can provide figures if it helps with reproducibility.


Solution

  • If I have understand your question correctly, you should re-implement the flow_ considering the ramp rate. I didn't model the general case, but the following should work for your situation.

    # delta flow, models the 1-hop influence of certain selection (next )
    delta_flow_ = [5, 5, 5, 5, 4.5, 5, 4.5]
    selection_of_previous_period = cp.hstack([selection[0:-1, :], np.zeros((1, num_of_pumps))])  # assume selection is flase at the beginning of the day
    existence_of_delta_flow = cp.multiply(1-selection_of_previous_period, selection)  # delta flow exist when previous period is close and now is open
    input_flow_ = input_flow_ - cp.sum(cp.multiply(delta_flow_, existence_of_delta_flow), axis=1)
    
    # delta delta flow, models the 2-hop influence of certain selection
    delta_delta_flow_ = [0, 0, 0, 0, 0, 0.5, 0]
    selection_of_previous_period2 = cp.hstack([selection[0:-2, :], np.zeros((2, num_of_pumps))])  # assume selection is flase at the beginning of the day
    # delta_delta_flow[i] exist if selection[i-2] is False, and selection[i-1] is True, and selection[i] is True
    # the delta_delta_flow_[6] is 0.5, which means if selection[4]=False (pump not selected in period[4], indexing from 0)
    # and selection[5]=True (pump selected in period[5]) and and selection[6]=True
    # delta_delta_flow[i] is non_zero when the length period[i-1]<4*30min
    existence_of_delta_delta_flow = existence_of_delta_flow = cp.multiply(cp.multiply(1-selection_of_previous_period2, selection_of_previous_period), selection)
    input_flow_ = input_flow_ - cp.sum(cp.multiply(delta_delta_flow_, existence_of_delta_delta_flow), axis=1)
    
    # For general case, you may need "delta_delta_delta_flow_", which model the 3-hop influence of certain selection
    

    In addition, I think volume_ may also need to be re-implemented considering the ramp rate. You can imitate my codes and do it yourself.