PuLP Showing UpperBound values of LpVariable with minimalization - python-3.x
I'm trying to minimized the following problem:
for the production of laptops, phones and tablets, there are costs for inventory (1$ per item per month) and for overtime hours (10$ per hour). There is a demand scheme to be met, which functions as a constraint for the minimum number of gadgets in a specific month. Besides this there is a maximum of 20000 hours of production, plus 3000 overtime hours per month.
The problem is that the results python/pulp give me are (with one exception) all the upperbound values that are inserted in the LpVariables: not the minimized costs!
from pulp import *
# Define the LP problem: minimize costs
prob = LpProblem("Minimize costs of production and inventory", LpMinimize)
# Demand schemes
demand_laptops = [75, 125, 1000, 1500, 1000, 500, 1250, 1500, 1000, 500, 500, 400, 300] # Demand laptops
demand_phones = [120, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000] # Demand phones
demand_tablets = [50, 2000, 3000, 2000, 3000, 4000, 5000, 2000, 3000, 4000, 5000, 4000, 5000] # Demand tablets
# Defining variables: normal production hours and overtime production hours.
production_laptop = {x: LpVariable("Production hours for laptop in month {}".format(x), 0, 20000)
for x in range(1, 13)}
production_phone = {x: LpVariable("Production hours for phone in month {}".format(x), 0, 20000)
for x in range(1, 13)}
production_tablet = {x: LpVariable("Production hours for tablet in month {}".format(x), 0, 20000)
for x in range(1, 13)}
overtime_laptop = {x: LpVariable("Overtime hours for laptop in month {}".format(x), 0, 3000)
for x in range(1, 13)}
overtime_phone = {x: LpVariable("Overtime hours for phone in month {}".format(x), 0, 3000)
for x in range(1, 13)}
overtime_tablet = {x: LpVariable("Overtime hours for tablet in month {}".format(x), 0, 3000)
for x in range(1, 13)}
# defining a list of names for the inventory of products
inventory_laptops = {x: "inventory of laptops in month {}".format(x)
for x in range(1, 13)}
inventory_phones = {x: "inventory of phones in month {}".format(x)
for x in range(1, 13)}
inventory_tables = {x: "inventory of tablets in month {}".format(x)
for x in range(1, 13)}
# Inventory (to be minimized)
inventory_laptops[1] = demand_laptops[0] + (1 / 5) * production_laptop[1] + (1 / 5) * overtime_laptop[1] - demand_laptops[1]
inventory_laptops[2] = inventory_laptops[1] + (1 / 5) * production_laptop[2] + (1 / 5) * overtime_laptop[2] - demand_laptops[2]
inventory_laptops[3] = inventory_laptops[2] + (1 / 5) * production_laptop[3] + (1 / 5) * overtime_laptop[3] - demand_laptops[3]
inventory_laptops[4] = inventory_laptops[3] + (1 / 5) * production_laptop[4] + (1 / 5) * overtime_laptop[4] - demand_laptops[4]
inventory_laptops[5] = inventory_laptops[4] + (1 / 5) * production_laptop[5] + (1 / 5) * overtime_laptop[5] - demand_laptops[5]
inventory_laptops[6] = inventory_laptops[5] + (1 / 5) * production_laptop[6] + (1 / 5) * overtime_laptop[6] - demand_laptops[6]
inventory_laptops[7] = inventory_laptops[6] + (1 / 5) * production_laptop[7] + (1 / 5) * overtime_laptop[7] - demand_laptops[7]
inventory_laptops[8] = inventory_laptops[7] + (1 / 5) * production_laptop[8] + (1 / 5) * overtime_laptop[8] - demand_laptops[8]
inventory_laptops[9] = inventory_laptops[8] + (1 / 5) * production_laptop[9] + (1 / 5) * overtime_laptop[9] - demand_laptops[9]
inventory_laptops[10] = inventory_laptops[9] + (1 / 5) * production_laptop[10] + (1 / 5) * overtime_laptop[10] - demand_laptops[10]
inventory_laptops[11] = inventory_laptops[10] + (1 / 5) * production_laptop[11] + (1 / 5) * overtime_laptop[11] - demand_laptops[11]
inventory_laptops[12] = inventory_laptops[11] + (1 / 5) * production_laptop[12] + (1 / 5) * overtime_laptop[12] - demand_laptops[12]
inventory_phones[1] = demand_phones[0] + (1 / 2) * production_phone[1] + (1 / 2) * overtime_phone[1] - demand_phones[1]
inventory_phones[2] = inventory_phones[1] + (1 / 2) * production_phone[2] + (1 / 2) * overtime_phone[2] - demand_phones[2]
inventory_phones[3] = inventory_phones[2] + (1 / 2) * production_phone[3] + (1 / 2) * overtime_phone[3] - demand_phones[3]
inventory_phones[4] = inventory_phones[3] + (1 / 2) * production_phone[4] + (1 / 2) * overtime_phone[4] - demand_phones[4]
inventory_phones[5] = inventory_phones[4] + (1 / 2) * production_phone[5] + (1 / 2) * overtime_phone[5] - demand_phones[5]
inventory_phones[6] = inventory_phones[5] + (1 / 2) * production_phone[6] + (1 / 2) * overtime_phone[6] - demand_phones[6]
inventory_phones[7] = inventory_phones[6] + (1 / 2) * production_phone[7] + (1 / 2) * overtime_phone[7] - demand_phones[7]
inventory_phones[8] = inventory_phones[7] + (1 / 2) * production_phone[8] + (1 / 2) * overtime_phone[8] - demand_phones[8]
inventory_phones[9] = inventory_phones[8] + (1 / 2) * production_phone[9] + (1 / 2) * overtime_phone[9] - demand_phones[9]
inventory_phones[10] = inventory_phones[9] + (1 / 2) * production_phone[10] + (1 / 2) * overtime_phone[10] - demand_phones[10]
inventory_phones[11] = inventory_phones[10] + (1 / 2) * production_phone[11] + (1 / 2) * overtime_phone[11] - demand_phones[11]
inventory_phones[12] = inventory_phones[11] + (1 / 2) * production_phone[12] + (1 / 2) * overtime_phone[12] - demand_phones[12]
inventory_tables[1] = demand_tablets[0] + (1 / 4) * production_tablet[1] + (1 / 4) * overtime_tablet[1] - demand_tablets[1]
inventory_tables[2] = inventory_tables[1] + (1 / 4) * production_tablet[2] + (1 / 4) * overtime_tablet[2] - demand_tablets[2]
inventory_tables[3] = inventory_tables[2] + (1 / 4) * production_tablet[3] + (1 / 4) * overtime_tablet[3] - demand_tablets[3]
inventory_tables[4] = inventory_tables[3] + (1 / 4) * production_tablet[4] + (1 / 4) * overtime_tablet[4] - demand_tablets[4]
inventory_tables[5] = inventory_tables[4] + (1 / 4) * production_tablet[5] + (1 / 4) * overtime_tablet[5] - demand_tablets[5]
inventory_tables[6] = inventory_tables[5] + (1 / 4) * production_tablet[6] + (1 / 4) * overtime_tablet[6] - demand_tablets[6]
inventory_tables[7] = inventory_tables[6] + (1 / 4) * production_tablet[7] + (1 / 4) * overtime_tablet[7] - demand_tablets[7]
inventory_tables[8] = inventory_tables[7] + (1 / 4) * production_tablet[8] + (1 / 4) * overtime_tablet[8] - demand_tablets[8]
inventory_tables[9] = inventory_tables[8] + (1 / 4) * production_tablet[9] + (1 / 4) * overtime_tablet[9] - demand_tablets[9]
inventory_tables[10] = inventory_tables[9] + (1 / 4) * production_tablet[10] + (1 / 4) * overtime_tablet[10] - demand_tablets[10]
inventory_tables[11] = inventory_tables[10] + (1 / 4) * production_tablet[11] + (1 / 4) * overtime_tablet[11] - demand_tablets[11]
inventory_tables[12] = inventory_tables[11] + (1 / 4) * production_tablet[12] + (1 / 4) * overtime_tablet[12] - demand_tablets[12]
# Constraints to meet demand scheme
prob += demand_laptops[0] + (1 / 5) * production_laptop[1] + (1 / 5) * overtime_laptop[1] >= demand_laptops[1]
prob += inventory_laptops[1] + (1 / 5) * production_laptop[2] + (1 / 5) * overtime_laptop[2] >= demand_laptops[2]
prob += inventory_laptops[2] + (1 / 5) * production_laptop[3] + (1 / 5) * overtime_laptop[3] >= demand_laptops[3]
prob += inventory_laptops[3] + (1 / 5) * production_laptop[4] + (1 / 5) * overtime_laptop[4] >= demand_laptops[4]
prob += inventory_laptops[4] + (1 / 5) * production_laptop[5] + (1 / 5) * overtime_laptop[5] >= demand_laptops[5]
prob += inventory_laptops[5] + (1 / 5) * production_laptop[6] + (1 / 5) * overtime_laptop[6] >= demand_laptops[6]
prob += inventory_laptops[6] + (1 / 5) * production_laptop[7] + (1 / 5) * overtime_laptop[7] >= demand_laptops[7]
prob += inventory_laptops[7] + (1 / 5) * production_laptop[8] + (1 / 5) * overtime_laptop[8] >= demand_laptops[8]
prob += inventory_laptops[8] + (1 / 5) * production_laptop[9] + (1 / 5) * overtime_laptop[9] >= demand_laptops[9]
prob += inventory_laptops[9] + (1 / 5) * production_laptop[10] + (1 / 5) * overtime_laptop[10] >= demand_laptops[10]
prob += inventory_laptops[10] + (1 / 5) * production_laptop[11] + (1 / 5) * overtime_laptop[11] >= demand_laptops[11]
prob += inventory_laptops[11] + (1 / 5) * production_laptop[12] + (1 / 5) * overtime_laptop[12] >= demand_laptops[12]
prob += demand_phones[0] + (1 / 2) * production_phone[1] + (1 / 2) * overtime_phone[1] >= demand_phones[1]
prob += inventory_phones[1] + (1 / 2) * production_phone[2] + (1 / 2) * overtime_phone[2] >= demand_phones[2]
prob += inventory_phones[2] + (1 / 2) * production_phone[3] + (1 / 2) * overtime_phone[3] >= demand_phones[3]
prob += inventory_phones[3] + (1 / 2) * production_phone[4] + (1 / 2) * overtime_phone[4] >= demand_phones[4]
prob += inventory_phones[4] + (1 / 2) * production_phone[5] + (1 / 2) * overtime_phone[5] >= demand_phones[5]
prob += inventory_phones[5] + (1 / 2) * production_phone[6] + (1 / 2) * overtime_phone[6] >= demand_phones[6]
prob += inventory_phones[6] + (1 / 2) * production_phone[7] + (1 / 2) * overtime_phone[7] >= demand_phones[7]
prob += inventory_phones[7] + (1 / 2) * production_phone[8] + (1 / 2) * overtime_phone[8] >= demand_phones[8]
prob += inventory_phones[8] + (1 / 2) * production_phone[9] + (1 / 2) * overtime_phone[9] >= demand_phones[9]
prob += inventory_phones[9] + (1 / 2) * production_phone[10] + (1 / 2) * overtime_phone[10] >= demand_phones[10]
prob += inventory_phones[10] + (1 / 2) * production_phone[11] + (1 / 2) * overtime_phone[11] >= demand_phones[11]
prob += inventory_phones[11] + (1 / 2) * production_phone[12] + (1 / 2) * overtime_phone[12] >= demand_phones[12]
prob += demand_tablets[0] + (1 / 4) * production_tablet[1] + (1 / 4) * overtime_tablet[1] >= demand_tablets[1]
prob += inventory_phones[1] + (1 / 4) * production_tablet[2] + (1 / 4) * overtime_tablet[2] >= demand_tablets[2]
prob += inventory_phones[2] + (1 / 4) * production_tablet[3] + (1 / 4) * overtime_tablet[3] >= demand_tablets[3]
prob += inventory_phones[3] + (1 / 4) * production_tablet[4] + (1 / 4) * overtime_tablet[4] >= demand_tablets[4]
prob += inventory_phones[4] + (1 / 4) * production_tablet[5] + (1 / 4) * overtime_tablet[5] >= demand_tablets[5]
prob += inventory_phones[5] + (1 / 4) * production_tablet[6] + (1 / 4) * overtime_tablet[6] >= demand_tablets[6]
prob += inventory_phones[6] + (1 / 4) * production_tablet[7] + (1 / 4) * overtime_tablet[7] >= demand_tablets[7]
prob += inventory_phones[7] + (1 / 4) * production_tablet[8] + (1 / 4) * overtime_tablet[8] >= demand_tablets[8]
prob += inventory_phones[8] + (1 / 4) * production_tablet[9] + (1 / 4) * overtime_tablet[9] >= demand_tablets[9]
prob += inventory_phones[9] + (1 / 4) * production_tablet[10] + (1 / 4) * overtime_tablet[10] >= demand_tablets[10]
prob += inventory_phones[10] + (1 / 4) * production_tablet[11] + (1 / 4) * overtime_tablet[11] >= demand_tablets[11]
prob += inventory_phones[11] + (1 / 4) * production_tablet[12] + (1 / 4) * overtime_tablet[12] >= demand_tablets[12]
# Objective function: inventory costs and overtime costs (10 per hour)
prob += sum(inventory_laptops) + sum(inventory_phones) + sum(inventory_tables) + (10 * (sum(overtime_laptop) + sum(overtime_phone) + sum(overtime_tablet)))
# Solve the problem
prob.solve()
print("Status:", LpStatus[prob.status])
for v in prob.variables():
print(v.name, "=", v.varValue)
print("total costs:", value(prob.objective))
This gives me the following results:
Status: Optimal
Overtime_hours_for_laptop_in_month_1 = 3000.0
Overtime_hours_for_laptop_in_month_10 = 3000.0
Overtime_hours_for_laptop_in_month_11 = 3000.0
Overtime_hours_for_laptop_in_month_12 = 3000.0
Overtime_hours_for_laptop_in_month_2 = 3000.0
Overtime_hours_for_laptop_in_month_3 = 3000.0
Overtime_hours_for_laptop_in_month_4 = 3000.0
Overtime_hours_for_laptop_in_month_5 = 3000.0
Overtime_hours_for_laptop_in_month_6 = 3000.0
Overtime_hours_for_laptop_in_month_7 = 3000.0
Overtime_hours_for_laptop_in_month_8 = 3000.0
Overtime_hours_for_laptop_in_month_9 = 3000.0
Overtime_hours_for_phone_in_month_1 = 3000.0
Overtime_hours_for_phone_in_month_10 = 3000.0
Overtime_hours_for_phone_in_month_11 = 3000.0
Overtime_hours_for_phone_in_month_12 = 3000.0
Overtime_hours_for_phone_in_month_2 = 3000.0
Overtime_hours_for_phone_in_month_3 = 3000.0
Overtime_hours_for_phone_in_month_4 = 3000.0
Overtime_hours_for_phone_in_month_5 = 3000.0
Overtime_hours_for_phone_in_month_6 = 3000.0
Overtime_hours_for_phone_in_month_7 = 3000.0
Overtime_hours_for_phone_in_month_8 = 3000.0
Overtime_hours_for_phone_in_month_9 = 3000.0
Overtime_hours_for_tablet_in_month_1 = 0.0
Overtime_hours_for_tablet_in_month_10 = 3000.0
Overtime_hours_for_tablet_in_month_11 = 3000.0
Overtime_hours_for_tablet_in_month_12 = 3000.0
Overtime_hours_for_tablet_in_month_2 = 3000.0
Overtime_hours_for_tablet_in_month_3 = 3000.0
Overtime_hours_for_tablet_in_month_4 = 3000.0
Overtime_hours_for_tablet_in_month_5 = 3000.0
Overtime_hours_for_tablet_in_month_6 = 3000.0
Overtime_hours_for_tablet_in_month_7 = 3000.0
Overtime_hours_for_tablet_in_month_8 = 3000.0
Overtime_hours_for_tablet_in_month_9 = 3000.0
Production_hours_for_laptop_in_month_1 = 20000.0
Production_hours_for_laptop_in_month_10 = 20000.0
Production_hours_for_laptop_in_month_11 = 20000.0
Production_hours_for_laptop_in_month_12 = 20000.0
Production_hours_for_laptop_in_month_2 = 20000.0
Production_hours_for_laptop_in_month_3 = 20000.0
Production_hours_for_laptop_in_month_4 = 20000.0
Production_hours_for_laptop_in_month_5 = 20000.0
Production_hours_for_laptop_in_month_6 = 20000.0
Production_hours_for_laptop_in_month_7 = 20000.0
Production_hours_for_laptop_in_month_8 = 20000.0
Production_hours_for_laptop_in_month_9 = 20000.0
Production_hours_for_phone_in_month_1 = 20000.0
Production_hours_for_phone_in_month_10 = 20000.0
Production_hours_for_phone_in_month_11 = 20000.0
Production_hours_for_phone_in_month_12 = 20000.0
Production_hours_for_phone_in_month_2 = 20000.0
Production_hours_for_phone_in_month_3 = 20000.0
Production_hours_for_phone_in_month_4 = 20000.0
Production_hours_for_phone_in_month_5 = 20000.0
Production_hours_for_phone_in_month_6 = 20000.0
Production_hours_for_phone_in_month_7 = 20000.0
Production_hours_for_phone_in_month_8 = 20000.0
Production_hours_for_phone_in_month_9 = 20000.0
Production_hours_for_tablet_in_month_1 = 7800.0
Production_hours_for_tablet_in_month_10 = 20000.0
Production_hours_for_tablet_in_month_11 = 20000.0
Production_hours_for_tablet_in_month_12 = 20000.0
Production_hours_for_tablet_in_month_2 = 20000.0
Production_hours_for_tablet_in_month_3 = 20000.0
Production_hours_for_tablet_in_month_4 = 20000.0
Production_hours_for_tablet_in_month_5 = 20000.0
Production_hours_for_tablet_in_month_6 = 20000.0
Production_hours_for_tablet_in_month_7 = 20000.0
Production_hours_for_tablet_in_month_8 = 20000.0
Production_hours_for_tablet_in_month_9 = 20000.0
__dummy = None
total costs: None
Can somebody tell me what I am doing wrong?
There are a few syntactic glitches that result in the solver getting a different model than what you would expect. In addition, I would like to point some syntactic suggestions as well.
What is wrong?
First, the production variables are defined as dictionaries, whose values are LpVariables. I would suggest that you use the pulp data structure designed for this job, LpVariable.dicts. The definition would then be like this:
production_laptop = LpVariable.dicts(
"Production hours for laptop in month ", range(1, 13),
lowBound = 0, upBound = 20000)
Note that I explicitly denote lower and upper bounds: this is a good habit, which helps a lot if you have to reuse the code after a few months (or even weeks).
Later on, you define dictionaries that represent variable names: the inventory_ variables. Then, you redefine the values of these dictionaries to point to a combination of variables and constraints. I would define these variables as the previous ones:
inventory_laptops = LpVariable.dicts(
"inventory of laptops in month ", range(1,13), lowBound = 0)
If there exist relationships among the variables, you can represent them in the constraints, so we do not need to worry about this during the variable definition stage.
Note that after the variable are defined, the objective function should be defined. Its definition is not correct, because instead of sum(inventory_laptops) one has to sum(inventory_laptops[i] for i in range(1,13)), otherwise we try to sum over a dictionary, and in particular over the keys of the dictionary.
Syntax
DRY: You write a lot of repetitive code, which could easily fit into loops. Try to not repeat yourself, because the code is unnecessarily lengthy and complex and prone to errors. In fact, there is an error in your code which might be because of copy-pasting code you already had: the last block of constraints mixes phones and tablets, like this:
prob += inventory_phones[1] + (1 / 4) * production_tablet[2] + (1 / 4) * overtime_tablet[2] >= demand_tablets[2]
probably because you were copy pasting and replacing phones with tablets. You can easily write these lines as
for i in range(1,13):
prob += (demand_tablets[i - 1] if i == 1 else inventory_tables[i - 1]) + \
(1 / 4) * production_tablet[i] + (1 / 4) * overtime_tablet[i] >= \
demand_tablets[i], "demand tablets {}".format(i)
which also has the added benefit that you give your constraint a name, so that you can trace it later if you want to.
Comments: Try to use helpful comments. These are the comments that describe what you intent, not what you actually do. Why comment # Demand laptops when your variable is called demand_laptops?
Consistency: This is a big one. It takes a bit of time to work with your code, mostly because variable names are not consistent: demand_tablets, inventory_tables, overtime_tablet and production_tablet are all very similar and easy to confuse. Try to stick to a more consistent notation.
Line length: Although not necessary, Python developers do not use arbitrary line lengths. Try to use a good IDE (I use Pycharm, sometimes Sublime Text), which is going to steer you to use the regular Python conventions (also in naming variables, functions, etc). This makes the code looking more like Python.
Debugging Math Optimization Models: A very useful habit for small problems, is to print out the formulation you are passing to the solver. This can help you catch many bugs and issues. It would be apparent for example, that you have defined a variable called _dummy, which was done accidentally. This is done with prob.writeLP("DebugThis.lp"). I would also use shorter length variables, so that I can understand what is going on in the constraints and objective function. As a final word, try to avoid hard numbers in your models. The inventory cost might be 10 for the instance you have now, but in the future this might change (it will change in a non-assignment environment). Thus, it is better to define a list of inventory costs (one for each product, and/or period) and update that list only. This is helpful in case you want to add more products, as the constraints and variables will be generated automatically.
Revised Code
I implemented a working version of your code hereby. To keep it close to the original, so that it is easier to understand (for yourself) I did not implement everything I suggest. As a further improvement on my lines below, try to have a list of products and generate the product-month pairs automatically. There are a few ways to do this, and perhaps this example will help.
from pulp import * # I would not import the entire workspace - you might end up shadowing variables names that you need
# Problem formulation starts here
prob = LpProblem("Minimize costs of production and inventory", LpMinimize)
# Problem data: Product Demands
demand_laptops = [75, 125, 1000, 1500, 1000, 500, 1250, 1500, 1000, 500, 500, 400, 300]
demand_phones = [120, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000]
demand_tablets = [50, 2000, 3000, 2000, 3000, 4000, 5000, 2000, 3000, 4000, 5000, 4000, 5000]
# Defining variables: normal production, overtime, and inventories
production_laptop = LpVariable.dicts(
"Production hours for laptop in month ", range(1, 13),
lowBound = 0, upBound = 20000)
production_phone = LpVariable.dicts(
"Production hours for phone in month ", range(1, 13),
lowBound = 0, upBound = 20000)
production_tablet = LpVariable.dicts(
"Production hours for tablet in month ", range(1, 13),
lowBound = 0, upBound = 20000)
overtime_laptop = LpVariable.dicts(
"Overtime hours for laptop in month ", range(1, 13),
lowBound = 0, upBound = 3000)
overtime_phone = LpVariable.dicts(
"Overtime hours for phone in month ", range(1, 13),
lowBound = 0, upBound = 3000)
overtime_tablet = LpVariable.dicts(
"Overtime hours for tablet in month ", range(1, 13),
lowBound = 0, upBound = 3000)
inventory_laptops = LpVariable.dicts(
"inventory of laptops in month ", range(1,13), lowBound = 0)
inventory_phones = LpVariable.dicts(
"inventory of phones in month ", range(1,13), lowBound = 0)
inventory_tables = LpVariable.dicts(
"inventory of tables in month ", range(1,13), lowBound = 0)
# Objective function: inventory costs and overtime costs
prob += (sum(
inventory_laptops[i] + inventory_phones[i] + inventory_tables[i]
for i in range(1,13)) + \
10 * sum(overtime_laptop[i] + overtime_phone[i] + overtime_tablet[i]
for i in range(1,13)))
# Constraint definition part
for i in range(1,13):
# Inventory definition for laptops, phones and tablets
prob += inventory_laptops[i] == (demand_laptops[i - 1] if i == 1 else \
inventory_laptops[i - 1]) + \
(1 / 5) * production_laptop[i] + (1 / 5) * overtime_laptop[i] - \
demand_laptops[i], "inventory_laptops definition {}".format(i)
prob += inventory_phones[i] == (demand_phones[i - 1] if i == 1 else \
inventory_phones[i - 1]) + \
(1 / 2) * production_phone[i] + (1 / 2) * overtime_phone[i] - \
demand_phones[i], "inventory_phones definition {}".format(i)
prob += inventory_tables[i] == (demand_tablets[i - 1] if i == 1 else \
inventory_tables[i - 1]) + \
(1 / 4) * production_tablet[i] + (1 / 4) * overtime_tablet[i] - \
demand_tablets[i], "inventory_tables definition {}".format(i)
# Demand-covering constraints for laptops, phones, tablets
prob += (demand_laptops[i - 1] if i == 1 else inventory_laptops[i - 1]) + \
(1 / 5) * production_laptop[i] + (1 / 5) * overtime_laptop[i] >= \
demand_laptops[i], "demand laptops {}".format(i)
prob += (demand_phones[i - 1] if i == 1 else inventory_phones[i - 1]) + \
(1 / 2) * production_phone[i] + (1 / 2) * overtime_phone[i] >= \
demand_phones[i], "demand phones {}".format(i)
prob += (demand_tablets[i - 1] if i == 1 else inventory_tables[i - 1]) + \
(1 / 4) * production_tablet[i] + (1 / 4) * overtime_tablet[i] >= \
demand_tablets[i], "demand tablets {}".format(i)
# Solve the problem
prob.solve()
# Take a look at what was solved
prob.writeLP("SO40113557.lp")
print("Status:", LpStatus[prob.status])
for v in prob.variables():
print(v.name, "=", v.varValue)
print("total costs:", value(prob.objective))
Output (without printing out the variable names/values):
('Status:', 'Optimal')
('total costs:', 0.0)
I hope this helps!
Related
AttributeError: 'IAPWS97' object has no attribute 'rho'
I am trying to run this loop; however, I am getting a no attribute error in the second portion of my code. Below is the entire code (sorry for the length). When I run the first case (PWR) the code executes normally as expected. However, when I run the second case (BWR) I receive the error even though it is the same exact statement from case one. Is there any fix or explanation for this? Thank you. import numpy as np import math from iapws import IAPWS97 import matplotlib.pyplot as plt case = int(input('Which case [1 (PWR) or 2 (BWR)]? ')) if case == 1: # PWR H = 3.8 # m He = 3.8 # m Pitch = 1.25 * 10 ** (-2) # m Gap_t = 0.00006 # m D_fuel = 0.0082 # m k_gap = 0.25 # W/m-K k_c = 21.5 # W/m-K k_fuel = 3.6 # W/m-K T0 = float(278 + 273.15) # K q0_prime = float(330 * 10 ** (2)) # W/m P0 = 15 # MPa MF = float(3460) # kg/m^2-s D_rod = .0095 # m R_rod = D_rod / 2 R_fuel = D_fuel / 2 R_gap = R_fuel + Gap_t R_clad = R_rod Clad_t = D_rod - D_fuel - Gap_t # m h0_enthalpy = (IAPWS97(T=T0, P=P0).h) * 10 ** (3) T_sat0 = IAPWS97(P=P0, x=0).T g = 9.81 # m/s # geometry properties heated_p = math.pi * D_rod wetted_p = math.pi * D_rod A_f = (Pitch ** 2) - ((1 / 4) * math.pi * (D_rod ** 2)) D_H = (4 * A_f) / heated_p # grid setup grid_points = 100 dz = H / grid_points z_array = np.arange(0, H, dz) z_arrayplots = np.arange(0, H, dz) q_HeatFluxList = [] # defining array of q'' values in list for z in z_array: heat_fluxA = (q0_prime / (math.pi * D_rod)) * math.sin(math.pi * (z / He)) q_HeatFluxList.append(heat_fluxA) q_heat_flux = np.array(q_HeatFluxList) q_prime = np.zeros(len(z_array)) for i in range(0, len(z_array)): q_prime[i] = q0_prime * math.sin((np.pi * z_array[i]) / He) # defining array of h values h_enthalpy_list = [] h_enthalpy_prefactor = ((heated_p * q0_prime * H) / (A_f * MF * (math.pi ** 2) * D_rod)) for z in z_array: h_enthalpy = (-h_enthalpy_prefactor * math.cos(math.pi * (z / He))) + h_enthalpy_prefactor + h0_enthalpy h_enthalpy_list.append(h_enthalpy) h_enthalpy_array_J = np.array(h_enthalpy_list) h_enthalpy_array = h_enthalpy_array_J * 10 ** (-3) P_array = np.zeros(len(z_array)) P_array[0] = P0 T_sat = np.zeros(len(z_array)) T_sat[0] = T_sat0 T_f_array = np.zeros(len(z_array)) T_f_array[0] = T0 Re = np.zeros(len(z_array)) Re_f = np.zeros(len(z_array)) Pr = np.zeros(len(z_array)) k_fluid = np.zeros(len(z_array)) x_array = np.zeros(len(z_array)) xe_array = np.zeros(len(z_array)) frictional = np.zeros(len(z_array)) gravitational = np.zeros(len(z_array)) compressibility = np.zeros(len(z_array)) # Pressure Loop PWR dp = 0.001 for i in range(0, len(z_array) - 1): rho_f = IAPWS97(P=P_array[i], x=0).rho vf = IAPWS97(P=P_array[i], x=0).v vg = IAPWS97(P=P_array[i], x=1).v hf_enthalpy = IAPWS97(P=P_array[i], x=0).h hg_enthalpy = IAPWS97(P=P_array[i], x=1).h muf = (IAPWS97(P=P_array[i], x=0).mu) * 10 ** (-6) mug = (IAPWS97(P=P_array[i], x=1).mu) * 10 ** (-6) k_fluid[i] = IAPWS97(P=P_array[i], T=T_f_array[i]).k Pr[i] = IAPWS97(P=P_array[i], h=h_enthalpy_array[i]).Liquid.Prandt x_array[i] = 0 xe_array[i] = (h_enthalpy_array[i] - hf_enthalpy) / (hg_enthalpy - hf_enthalpy) rho_m = 1 / ((x_array[i] * vg) + ((1 - x_array[i]) * vf)) mu_m = 1 / ((x_array[i] / mug) + ((1 - x_array[i]) / muf)) Re[i] = (MF * D_H) / (mu_m * 10 ** 6) # convert mu to Pa/s f = 0.079 * (Re[i] ** -0.25) * (mu_m / muf) Tau = (1 / 2) * f * ((MF ** 2) / rho_m) Re_f[i] = Re[i] vf_plus_dP = IAPWS97(P=P_array[i] + dp, x=0).v vf_minus_dP = IAPWS97(P=P_array[i] - dp, x=0).v ddP_vf = (vf_plus_dP - vf_minus_dP) / (2 * (dp * 10 ** 6)) frictional[i] = (Tau * wetted_p) / A_f gravitational[i] = g * rho_f compressibility[i] = (MF ** 2) * (ddP_vf) dPdz_num = (frictional[i] + gravitational[i]) # Pa/m dPdz_denom = 1 + compressibility[i] # Pa/m dPdz = -dPdz_num / dPdz_denom # Pa/m P_array[i + 1] = P_array[i] + ((dPdz * dz) * 10 ** (-6)) T_f_array[i + 1] = IAPWS97(P=P_array[i + 1], h=h_enthalpy_array[i + 1]).T T_sat[i + 1] = IAPWS97(P=P_array[i + 1], x=0).T # final calc for final value of quality and void fraction because loop stops before these hf_final = IAPWS97(P=P_array[-1], x=0).h hg_final = IAPWS97(P=P_array[-1], x=1).h muf_final = (IAPWS97(P=P_array[-1], x=0).mu) * 10 ** (-6) mug_final = (IAPWS97(P=P_array[-1], x=1).mu) * 10 ** (-6) k_fluid[-1] = IAPWS97(P=P_array[-1], T=T_f_array[-1]).k xe_array[-1] = (h_enthalpy_array[-1] - hf_final) / (hg_final - hf_final) # fuel and clad temps T_C_Outer = np.zeros(len(z_array)) mu_m_final = 1 / ((x_array[-1] / mug_final) + ((1 - x_array[-1]) / muf_final)) Re_f[-1] = (MF * D_H) / (muf_final * 10 ** 6) Pr[-1] = IAPWS97(P=P_array[i], h=h_enthalpy_array[i]).Liquid.Prandt h_HT = 0.023 * (Re_f[0] ** 0.8) * (Pr[0] ** 0.4) * (k_fluid[0] / D_H) T_C_Outer[0] = (q_heat_flux[0] + (h_HT * T_f_array[0])) / h_HT for i in range(0, len(z_array) - 1): h_HT = 0.023 * (Re_f[i + 1] ** 0.8) * (Pr[i + 1] ** 0.4) * (k_fluid[i + 1] / D_H) T_C_Outer[i + 1] = (q_heat_flux[i + 1] + (h_HT * T_f_array[i + 1])) / h_HT q_triple_prime = (q_prime * 4) / (np.pi * (D_fuel ** 2)) T_C_Inner = np.zeros(len(z_array)) T_F_Outer = np.zeros(len(z_array)) T_F_Center = np.zeros(len(z_array)) for i in range(0, len(z_array)): C1 = -((q0_prime * R_clad) / (k_c * heated_p)) * np.sin(np.pi * (z_array[i] / H)) C2 = T_C_Outer[i] - (C1 * np.log(R_clad)) T_C_Inner[i] = (C1 * np.log(R_gap)) + C2 C3 = (k_c / k_gap) * C1 C4 = T_C_Inner[i] - (C3 * np.log(R_gap)) T_F_Outer[i] = (C3 * np.log(R_fuel)) + C4 C6 = T_F_Outer[i] + ((q_triple_prime[i] * (R_fuel ** 2)) / (4 * k_fuel)) T_F_Center[i] = C6 CL_max = np.amax(T_F_Center) index = np.where(T_F_Center == CL_max) z_CL_max = z_array[index] Clad_max = np.amax(T_C_Inner) index = np.where(T_C_Inner == Clad_max) z_Clad_max = z_array[index] plt.figure(1) plt.plot(T_C_Outer, z_arrayplots, label='Clad Outer Surface Temp') plt.plot(T_C_Inner, z_arrayplots, label='Clad Inner Surface Temp') plt.legend(loc='upper left') plt.xlabel("Temperature [K]") plt.ylabel("Height z [m]") plt.savefig("TempClad.png", dpi=600) plt.figure(2) plt.plot(T_C_Outer, z_arrayplots, label='Clad Outer Surface Temp') plt.plot(T_C_Inner, z_arrayplots, label='Clad Inner Surface Temp') plt.plot(T_F_Outer, z_arrayplots, label='Fuel Outer Surface Temp') plt.plot(T_F_Center, z_arrayplots, label='Fuel Centerline Temp') plt.legend(loc='upper left') plt.xlabel("Temperature [K]") plt.ylabel("Height z [m]") plt.savefig("TempFuelAndClad.png", dpi=600) # radial calcs T_array_A = [T_F_Center[25], T_F_Outer[25], T_C_Inner[25], T_C_Outer[25]] T_array_B = [T_F_Center[49], T_F_Outer[49], T_C_Inner[49], T_C_Outer[49]] T_array_C = [T_F_Center[53], T_F_Outer[53], T_C_Inner[53], T_C_Outer[53]] r_array = [0, R_fuel, R_gap, R_clad] plt.figure(3) plt.plot(r_array, T_array_A, label='z = -H/4 = -0.9 m') plt.plot(r_array, T_array_B, label='z = 0 m') plt.plot(r_array, T_array_C, '--', label='z = zmax = 0.108 m') plt.legend(loc='upper left') plt.ylabel("Temperature [K]") plt.xlabel("Radius r [m]") plt.savefig("TempRadial.png", dpi=600) # critical heat flux and DNBR P_array_DNBR = np.delete(P_array, 0) q_heat_flux_DNBR = np.delete(q_heat_flux, 0) z_arrayplots_DNBR = np.delete(z_arrayplots, 0) G_Mlbs = MF * (((2.20462 * 10 ** (-6)) * 3600) / 10.7639) q_heat_flux_MBtu = q_heat_flux[1:] * 3.41 * (1 / 1000000) * (1 / 10.7639) P_c = 22.064 # https://nuclearstreet.com/nuclear-power-plants/w/nuclear_power_plants/features-of-pressurized-water-reactors P_crit = P_array_DNBR / P_c P1 = 0.5328 P2 = 0.1212 P3 = 1.6151 P4 = 1.4066 P5 = -0.3040 P6 = 0.4843 P7 = -0.3285 P8 = -2.0749 A = P1 * (P_crit ** P2) * (G_Mlbs ** (P5 + (P7 * P_crit))) C = P3 * (P_crit ** P4) * (G_Mlbs ** (P6 + (P8 * P_crit))) q_crit_heat_flux_MBtu = (A - xe_array[0]) / (C + ((xe_array[1:] - xe_array[0]) / q_heat_flux_MBtu)) q_crit_heat_flux = q_crit_heat_flux_MBtu * (1 / 3.41) * 1000000 * 10.7639 DNBR = q_crit_heat_flux / q_heat_flux_DNBR plt.figure(4) plt.plot(DNBR, z_arrayplots_DNBR) plt.xlabel("Departure from Nucleate Boiling Ratio") plt.ylabel("Height z [m]") plt.savefig("DNBR.png", dpi=600) plt.figure(5) plt.plot(P_array, z_arrayplots) plt.xlabel('Pressure [MPa]') plt.ylabel('Height z [m]') plt.savefig("Pressure.png", dpi=600) plt.figure(6) plt.plot(T_f_array, z_arrayplots) plt.xlabel('Temperature [K]') plt.ylabel('Height z [m]') plt.savefig("TempBulk.png", dpi=600) plt.figure(7) plt.plot(T_F_Outer, z_arrayplots, label='Fuel Outer Surface Temp') plt.plot(T_F_Center, z_arrayplots, label='Fuel Centerline Temp') plt.legend(loc='upper left') plt.xlabel("Temperature [K]") plt.ylabel("Height z [m]") plt.savefig("TempFuel.png", dpi=600) tempdifference = T_C_Outer - T_f_array print("Max clad vs bulk difference is " + str(np.amax(tempdifference)) + " K") print("Max coolant temp is " + str(np.amax(T_f_array)) + " K") print("Min coolant temp is " + str(np.amin(T_f_array)) + " K") print("Max clad inner temp is " + str(np.amax(T_C_Inner)) + " K") print("Max clad outer temp is " + str(np.amax(T_C_Outer)) + " K") print("min clad outer temp is " + str(np.amin(T_C_Outer)) + " K") print("Max fuel temp is " + str(np.amax(T_F_Center)) + " K") print("Max fuel outer temp is " + str(np.amax(T_F_Outer)) + " K") print("Min fuel outer temp is " + str(np.amin(T_F_Outer)) + " K") print("Max centerline temp occurs at z = " + str(z_CL_max) + "m") print("Max clad temp occurs at z = " + str(z_Clad_max) + "m") MDNBR = np.amin(DNBR) print("MDNBR is " + str(MDNBR)) plt.show() if case == 2: # BWR H = 3.8 # m He = 3.8 # m Pitch = 1.63 * 10 ** (-2) # m Gap_t = 0.0001 # m D_fuel = 0.0104 # m k_gap = 0.25 # W/m-K k_c = 21.5 # W/m-K k_fuel = 3.6 # W/m-K T0 = float(274 + 273.15) # K q0_prime = float(410 * 10 ** (2)) # W/m P0 = 7.5 # MPa MF = float(2290) # kg/m^2-s D_rod = .0123 # m R_rod = D_rod / 2 R_fuel = D_fuel / 2 R_gap = R_fuel + Gap_t R_clad = R_rod Clad_t = D_rod - D_fuel - Gap_t # m h0_enthalpy = (IAPWS97(T=T0, P=P0).h) * 10 ** (3) T_sat0 = IAPWS97(P=P0, x=0).T g = 9.81 # m/s # geometry properties heated_p = math.pi * D_rod wetted_p = math.pi * D_rod A_f = (Pitch ** 2) - ((1 / 4) * math.pi * (D_rod ** 2)) D_H = (4 * A_f) / heated_p # grid setup grid_points = 100 dz = H / grid_points z_array = np.arange(0, H, dz) z_arrayplots = np.arange(-H / 2, H / 2, dz) q_HeatFluxList = [] # defining array of q'' values in list for z in z_array: heat_fluxA = (q0_prime / (math.pi * D_rod)) * math.sin(math.pi * (z / He)) q_HeatFluxList.append(heat_fluxA) q_heat_flux = np.array(q_HeatFluxList) q_prime = np.zeros(len(z_array)) for i in range(0, len(z_array)): q_prime[i] = q0_prime * math.sin((np.pi * z_array[i]) / He) # defining array of h values h_enthalpy_list = [] h_enthalpy_prefactor = ((heated_p * q0_prime * H) / (A_f * MF * (math.pi ** 2) * D_rod)) for z in z_array: h_enthalpy = (-h_enthalpy_prefactor * math.cos(math.pi * (z / He))) + h_enthalpy_prefactor + h0_enthalpy h_enthalpy_list.append(h_enthalpy) h_enthalpy_array_J = np.array(h_enthalpy_list) h_enthalpy_array = h_enthalpy_array_J * 10 ** (-3) P_array = np.zeros(len(z_array)) P_array[0] = P0 T_sat = np.zeros(len(z_array)) T_sat[0] = T_sat0 T_f_array = np.zeros(len(z_array)) T_f_array[0] = T0 Re = np.zeros(len(z_array)) Re_f = np.zeros(len(z_array)) Pr = np.zeros(len(z_array)) k_fluid = np.zeros(len(z_array)) x_array = np.zeros(len(z_array)) xe_array = np.zeros(len(z_array)) dxe_array = np.zeros(len(z_array)) frictional = np.zeros(len(z_array)) gravitational = np.zeros(len(z_array)) compressibility = np.zeros(len(z_array)) alpha_array = np.zeros(len(z_array)) # Pressure Loop BWR dp = 0.001 for i in range(0, len(z_array) - 1): rho_f = IAPWS97(P=P_array[i], x=0).rho rho_m = IAPWS97(P=P_array[i], x=xe_array[i]).rho vf = IAPWS97(P=P_array[i], x=0).v vg = IAPWS97(P=P_array[i], x=1).v vfg = vg - vf hf_enthalpy = IAPWS97(P=P_array[i], x=0).h hg_enthalpy = IAPWS97(P=P_array[i], x=1).h hfg = hg_enthalpy - hf_enthalpy hfg_sat = IAPWS97(P=P0, x=1).h - IAPWS97(P=P0, x=0).h # vf = IAPWS97(P=P_array[i], x=0).v # vg_sat = IAPWS97(P=P_array[i], x=1).v hf_in = IAPWS97(P=P0, T=T0).h muf = (IAPWS97(P=P_array[i], x=0).mu) * 10 ** (-6) mum = (IAPWS97(P=P_array[i], x=xe_array[i]).mu) * 10 ** (-6) mug = (IAPWS97(P=P_array[i], x=1).mu) * 10 ** (-6) k_fluid[i] = IAPWS97(P=P_array[i], T=T_f_array[i]).k Pr[i] = IAPWS97(P=P_array[i], h=h_enthalpy_array[i]).Liquid.Prandt xe_in = (hf_in - hf_enthalpy) / (hfg) vf_sat = IAPWS97(P=P_array[i], x=xe_array[i]) # vapor quality if xe_array[i] <= 0: # single phase Re1p = MF * D_rod / muf f1p = 0.316 * Re1p ** (-.25) dp = -(.5 * f1p * MF * 2 * heated_p / (rho_f * A_f) + g / rho_f) * dz x_array[i] = 0 dxe_array[i] = q0_prime * np.sin(np.pi * z_array[i] / H) / (MF * A_f * hfg_sat) * dz xe_array = xe_array[i - 1] + dxe_array[i] # P_array[i]=P[i-1]+dp1p elif xe_array[i] > 0 and xe_array[i] < 1: # 2 phase Re2p = MF * D_rod / mum f2p = 0.046 * Re2p ** (-.2) * (muf / mum ** (-.2)) dp2p = (-MF ** 2 * vfg * dxe_array[i] + .5 * f2p * MF ** 2 * heated_p / (rho_m * A_f) + g * rho_m) * dz xe_array[i] = (h_enthalpy_array[i] - hf_enthalpy) / (hg_enthalpy - hf_enthalpy) # Void Fraction if xe_array[i] <= 0: alpha_array[0] elif xe_array[i] > 0 and xe_array[i] < 1: x_array[i] = xe_array[i] vfg_sat = vg - vf rho_m = (vf_sat + vfg_sat * x_array) ** (-1) rhof = 1 / vf rhog = 1 / vg void = (rho_m - rhof) / (rhog - rhof) alpha_array[void] print("Void fraction is " + str(np.amax(alpha_array))) if xe_array[i] <= 0: alpha_array[0] elif xe_array[i] > 0 and xe_array[i] < 1: x_array[i] = xe_array[i] vfg_sat = vg - vf rho_m = (vf_sat + vfg_sat * x_array) ** (-1) rhof = 1 / vf rhog = 1 / vg void = (rho_m - rhof) / (rhog - rhof) alpha_array[void] print("Void fraction is " + str(np.amax(alpha_array))) rho_m = 1 / ((x_array[i] * vg) + ((1 - x_array[i]) * vf)) mu_m = 1 / ((x_array[i] / mug) + ((1 - x_array[i]) / muf)) Re[i] = (MF * D_H) / (mu_m * 10 ** 6) # convert mu to Pa/s f = 0.079 * (Re[i] ** -0.25) * (mu_m / muf) Tau = (1 / 2) * f * ((MF ** 2) / rho_m) Re_f[i] = Re[i] vf_plus_dP = IAPWS97(P=P_array[i] + dp, x=xe_array[i]).v vf_minus_dP = IAPWS97(P=P_array[i] - dp, x=xe_array[i]).v ddP_vf = (vf_plus_dP - vf_minus_dP) / (2 * (dp * 10 ** 6)) frictional[i] = (Tau * wetted_p) / A_f gravitational[i] = g * rho_f compressibility[i] = (MF ** 2) * (ddP_vf) dPdz_num = (frictional[i] + gravitational[i]) # Pa/m dPdz_denom = 1 + compressibility[i] # Pa/m dPdz = -dPdz_num / dPdz_denom # Pa/m P_array[i + 1] = P_array[i] + ((dPdz * dz) * 10 ** (-6)) T_f_array[i + 1] = IAPWS97(P=P_array[i + 1], h=h_enthalpy_array[i + 1]).T T_sat[i + 1] = IAPWS97(P=P_array[i + 1], x=0).T # final calc for final value of quality and void fraction because loop stops before these hf_final = IAPWS97(P=P_array[-1], x=0).h hg_final = IAPWS97(P=P_array[-1], x=1).h muf_final = (IAPWS97(P=P_array[-1], x=0).mu) * 10 ** (-6) mug_final = (IAPWS97(P=P_array[-1], x=1).mu) * 10 ** (-6) k_fluid[-1] = IAPWS97(P=P_array[-1], T=T_f_array[-1]).k xe_array[-1] = (h_enthalpy_array[-1] - hf_final) / (hg_final - hf_final) # fuel and clad temps T_C_Outer = np.zeros(len(z_array)) mu_m_final = 1 / ((x_array[-1] / mug_final) + ((1 - x_array[-1]) / muf_final)) Re_f[-1] = (MF * D_H) / (muf_final * 10 ** 6) Pr[-1] = IAPWS97(P=P_array[i], h=h_enthalpy_array[i]).Liquid.Prandt h_HT = 0.023 * (Re_f[0] ** 0.8) * (Pr[0] ** 0.4) * (k_fluid[0] / D_H) T_C_Outer[0] = (q_heat_flux[0] + (h_HT * T_f_array[0])) / h_HT for i in range(0, len(z_array) - 1): h_HT = 0.023 * (Re_f[i + 1] ** 0.8) * (Pr[i + 1] ** 0.4) * (k_fluid[i + 1] / D_H) T_C_Outer[i + 1] = (q_heat_flux[i + 1] + (h_HT * T_f_array[i + 1])) / h_HT q_triple_prime = (q_prime * 4) / (np.pi * (D_fuel ** 2)) T_C_Inner = np.zeros(len(z_array)) T_F_Outer = np.zeros(len(z_array)) T_F_Center = np.zeros(len(z_array)) for i in range(0, len(z_array)): C1 = -((q0_prime * R_clad) / (k_c * heated_p)) * np.sin(np.pi * (z_array[i] / H)) C2 = T_C_Outer[i] - (C1 * np.log(R_clad)) T_C_Inner[i] = (C1 * np.log(R_gap)) + C2 C3 = (k_c / k_gap) * C1 C4 = T_C_Inner[i] - (C3 * np.log(R_gap)) T_F_Outer[i] = (C3 * np.log(R_fuel)) + C4 C6 = T_F_Outer[i] + ((q_triple_prime[i] * (R_fuel ** 2)) / (4 * k_fuel)) T_F_Center[i] = C6 CL_max = np.amax(T_F_Center) index = np.where(T_F_Center == CL_max) z_CL_max = z_array[index] plt.figure(1) plt.plot(T_C_Outer, z_arrayplots, label='Clad Outer Surface Temp') plt.plot(T_C_Inner, z_arrayplots, label='Clad Inner Surface Temp') plt.legend(loc='upper left') plt.xlabel("Temperature [K]") plt.ylabel("Height z [m]") plt.savefig("TempCladBWR.png", dpi=600) plt.figure(2) plt.plot(T_C_Outer, z_arrayplots, label='Clad Outer Surface Temp') plt.plot(T_C_Inner, z_arrayplots, label='Clad Inner Surface Temp') plt.plot(T_F_Outer, z_arrayplots, label='Fuel Outer Surface Temp') plt.plot(T_F_Center, z_arrayplots, label='Fuel Centerline Temp') plt.legend(loc='upper left') plt.xlabel("Temperature [K]") plt.ylabel("Height z [m]") plt.savefig("TempFuelAndCladBWR.png", dpi=600) # radial calcs T_array_A = [T_F_Center[25], T_F_Outer[25], T_C_Inner[25], T_C_Outer[25]] T_array_B = [T_F_Center[49], T_F_Outer[49], T_C_Inner[49], T_C_Outer[49]] T_array_C = [T_F_Center[53], T_F_Outer[53], T_C_Inner[53], T_C_Outer[53]] r_array = [0, R_fuel, R_gap, R_clad] plt.figure(3) plt.plot(r_array, T_array_A, label='z = -H/4 = -0.9 m') plt.plot(r_array, T_array_B, label='z = 0 m') plt.plot(r_array, T_array_C, '--', label='z = zmax = 0.108 m') plt.legend(loc='upper left') plt.ylabel("Temperature [K]") plt.xlabel("Radius r [m]") plt.savefig("TempRadialBWR.png", dpi=600) # critical heat flux and DNBR P_array_DNBR = np.delete(P_array, 0) q_heat_flux_DNBR = np.delete(q_heat_flux, 0) z_arrayplots_DNBR = np.delete(z_arrayplots, 0) G_Mlbs = MF * (((2.20462 * 10 ** (-6)) * 3600) / 10.7639) q_heat_flux_MBtu = q_heat_flux[1:] * 3.41 * (1 / 1000000) * (1 / 10.7639) P_c = 22.064 # https://nuclearstreet.com/nuclear-power-plants/w/nuclear_power_plants/features-of-pressurized-water-reactors P_crit = P_array_DNBR / P_c P1 = 0.5328 P2 = 0.1212 P3 = 1.6151 P4 = 1.4066 P5 = -0.3040 P6 = 0.4843 P7 = -0.3285 P8 = -2.0749 A = P1 * (P_crit ** P2) * (G_Mlbs ** (P5 + (P7 * P_crit))) C = P3 * (P_crit ** P4) * (G_Mlbs ** (P6 + (P8 * P_crit))) q_crit_heat_flux_MBtu = (A - xe_array[0]) / (C + ((xe_array[1:] - xe_array[0]) / q_heat_flux_MBtu)) q_crit_heat_flux = q_crit_heat_flux_MBtu * (1 / 3.41) * 1000000 * 10.7639 DNBR = q_crit_heat_flux / q_heat_flux_DNBR plt.figure(4) plt.plot(DNBR, z_arrayplots_DNBR) plt.xlabel("Onset of Nucleate Boiling Ratio") plt.ylabel("Height z [m]") plt.title("Onset of Nucleate Boiling Ratio versus Height") plt.savefig("ONBR.png", dpi=600) plt.figure(5) plt.plot(P_array, z_arrayplots) plt.xlabel('Pressure [MPa]') plt.ylabel('Height z [m]') plt.title('Pressure versus Height') plt.savefig("PressureBWR.png", dpi=600) plt.figure(6) plt.plot(T_f_array, z_arrayplots) plt.xlabel('Temperature [K]') plt.ylabel('Height z [m]') plt.title('Coolant Temperature vs Height') plt.savefig("TempBulkBWR.png", dpi=600) plt.figure(7) plt.plot(T_F_Outer, z_arrayplots, label='Fuel Outer Surface Temp') plt.plot(T_F_Center, z_arrayplots, label='Fuel Centerline Temp') plt.legend(loc='upper left') plt.xlabel("Temperature [K]") plt.ylabel("Height z [m]") plt.savefig("TempFuelBWR.png", dpi=600) # density plt.figure(8) plt.plot(Density, z_arrayplots, label='Density') plt.legend(loc='upper left') plt.xlabel("Pressure [mPa]") plt.ylabel("Height z [m]") plt.savefig("Density", dpi=600) # quality plt.figure(9) plt.plot(x, z_arrayplots, label='Quality') plt.plot(xe, z_arrayplots, label='Quality') plt.legend(loc='upper left') plt.xlabel("Quality") plt.ylabel("Height z [m]") plt.savefig("Quality", dpi=600) # void plt.figure(10) plt.plot(alpha, z_arrayplots, label='Void Fraction') plt.legend(loc='upper left') plt.xlabel("Void Fraction") plt.ylabel("Height z [m]") plt.savefig("Void Fraction", dpi=600) tempdifference = T_C_Outer - T_f_array print("Max clad vs bulk difference is " + str(np.amax(tempdifference)) + " C") print("Max coolant temp is " + str(np.amax(T_f_array) - 273.15) + " C") print("Max coolant temp is " + str(np.amax(T_f_array)) + " K") print("Max clad temp is " + str(np.amax(T_C_Inner) - 273.15) + " C") print("Max clad temp is " + str(np.amax(T_C_Inner)) + " K") print("Max fuel temp is " + str(np.amax(T_F_Center) - 273.15) + " C") print("Max fuel temp is " + str(np.amax(T_F_Center)) + " K") print("Max fuel temp is " + str(np.amax(T_F_Outer) - 273.15) + " C") print("Max fuel temp is " + str(np.amax(T_F_Outer)) + " K") print("Max centerline temp occurs at z = " + str(z_CL_max) + "m") MDNBR = np.amin(DNBR) print("MDNBR is " + str(MDNBR))
Python - Create a new field in Pandas df with result of a scipy function
I have a pandas df that contains fields A, B, and C. I have a scipy minimization function that uses A, B, and C, and returns x. I want to add the value of x as new field for each row in the same df. I have tested the scipy function separately on single values of A, B, and C entered directly as values instead of as df['name'] and it works, returning the value of x. The code does not work when I try to operate on the entire df. Any ideas? Each of A, B, and C are Float64 in the df. Here is the error message: Here is the code: from scipy.optimize import minimize_scalar import math # set parameters current_price_per_share = df['share_price'] shares_outstanding_in_millions = df['shares_(diluted)'] / 1000000 owners_income = df['owners_income'] / 1000000 def growth_needed(x, current_price_per_share, shares_outstanding_in_millions, owners_income): # set growth rates and cost of capital fcf_growth_1_to_5 = x / 100 fcf_growth_6_to_10 = fcf_growth_1_to_5 / 2 # half the rate of year 1-5 terminal_growth_rate = .03 # constant cost_of_capital = .1 #constant # calculate ten years of Free Cash Flow and the Terminal Value FCF_01 = owners_income * (1 + fcf_growth_1_to_5) FCF_02 = FCF_01 * (1 + fcf_growth_1_to_5) FCF_03 = FCF_02 * (1 + fcf_growth_1_to_5) FCF_04 = FCF_03 * (1 + fcf_growth_1_to_5) FCF_05 = FCF_04 * (1 + fcf_growth_1_to_5) FCF_06 = FCF_05 * (1 + fcf_growth_6_to_10) FCF_07 = FCF_06 * (1 + fcf_growth_6_to_10) FCF_08 = FCF_07 * (1 + fcf_growth_6_to_10) FCF_09 = FCF_08 * (1 + fcf_growth_6_to_10) FCF_10 = FCF_09 * (1 + fcf_growth_6_to_10) term_value = (FCF_10 * (1 + terminal_growth_rate)) / (cost_of_capital - terminal_growth_rate) # calcuate the Present Value for each period PV_01 = FCF_01 * (1 /(( 1 + cost_of_capital) ** 1)) PV_02 = FCF_02 * (1 /(( 1 + cost_of_capital) ** 2)) PV_03 = FCF_03 * (1 /(( 1 + cost_of_capital) ** 3)) PV_04 = FCF_04 * (1 /(( 1 + cost_of_capital) ** 4)) PV_05 = FCF_05 * (1 /(( 1 + cost_of_capital) ** 5)) PV_06 = FCF_06 * (1 /(( 1 + cost_of_capital) ** 6)) PV_07 = FCF_07 * (1 /(( 1 + cost_of_capital) ** 7)) PV_08 = FCF_08 * (1 /(( 1 + cost_of_capital) ** 8)) PV_09 = FCF_09 * (1 /(( 1 + cost_of_capital) ** 9)) PV_10 = FCF_10 * (1 /(( 1 + cost_of_capital) ** 10)) PV_TV = term_value * (1 /(( 1 + cost_of_capital) ** 11)) #sum the Present Values and calculate the value per share intrinsic_value = PV_01 + PV_02 + PV_03 + PV_04 + PV_05 + PV_06 + PV_07 + PV_08 + PV_09 + PV_10 + PV_TV intrinsic_value_per_share = intrinsic_value / shares_outstanding_in_millions # calculate the growth rate in year 1-5 needed to match the current share price # the square and square root are to force to zero before adding back the growth rate return ((math.sqrt((intrinsic_value_per_share - current_price_per_share) ** 2)) + x ) res = minimize_scalar(growth_needed, method='bounded', bounds=(-50, 100), args=(current_price_per_share, shares_outstanding_in_millions, owners_income,)) # notice the trailing comma in the Args function to make it a tuple df['implied_growth'] = res.x / 100
How do I use multithreading on this function for a np.meshgrid of values?
The following code generates numpy 2D lists of r and E values for the specified intervals. r = np.linspace(3, 14, 10) E = np.linspace(0.05, 0.75, 10) r, E = np.meshgrid(r, E) I am then using the following nested loop to generate output from the function ionisationGamma for each r and E interval value. for ridx in trange(len(r)): z = [] for cidx in range(len(r[ridx])): z.append(ionisationGamma(r[ridx][cidx], E[ridx][cidx])) Z.append(z) Z = np.array(Z) This loop gives me a 2D numpy array Z, which is my output and I am using it for a 3D graph. The problem with it is: it is taking ~6 hours to generate the output for all these intervals as there are so many values due to np.meshgrid. I have just discovered multi-threading in Python and wanted to know how I can implement this by using it. Any help is appreciated. See below code for ionisationGamma def ionisationGamma(r, E): I = complex(0.1, 1.0) a_soft = 1.0 omega = 0.057 beta = 0.0 dt = 0.1 steps = 10000 Nintervals = 60 N = 3000 xmin = float(-300) xmax = -xmin x = [0.0]*N dx = (xmax - xmin) / (N - 1) L = dx * N dk = 2 * M_PI / L propagator = None in_, out_, psi0 = None, None, None in_ = [complex(0.,0.)] * N psi0 = [complex(0.,0.)] * N out_ = [[complex(0.,0.)]*N for i in range(steps+1)] overlap = exp(-r) * (1 + r + (1 / 3) * pow(r, 2)) normC = 1 / (sqrt(2 * (1 + overlap))) gammai = 0.5 qi = 0.0 + (r / 2) pi = 0.0 gammai1 = 0.5 gammai2 = 0.5 qi1 = 0.0 - (r / 2) qi2 = 0.0 + (r / 2) pi1 = 0.0 pi2 = 0.0 # split initial wavepacket for i in range(N): x[i] = xmin + i * dx out_[0][i] = (normC) * ((pow(gammai1 / M_PI, 1. / 4.) * exp(complex(-(gammai1 / 2.) * pow(x[i] - qi1, 2.), pi1 * (x[i] - qi1)))) + (pow(gammai2 / M_PI, 1. / 4.) * exp(complex(-(gammai2 / 2.) * pow(x[i] - qi2, 2.), pi2 * (x[i] - qi2))))) in_[i] = (normC) * ((pow(gammai1 / M_PI, 1. / 4.) * exp(complex(-(gammai1 / 2.) * pow(x[i] - qi1, 2.), pi1 * (x[i] - qi1)))) + (pow(gammai2 / M_PI, 1. / 4.) * exp(complex(-(gammai2 / 2.) * pow(x[i] - qi2, 2.), pi2 * (x[i] - qi2))))) psi0[i] = in_[i] for l in range(1, steps+1): for i in range(N): propagator = exp(complex(0, -potential(x[i], omega, beta, a_soft, r, E, dt, l) * dt / 2.)) in_[i] = propagator * in_[i]; in_ = np.fft.fft(in_, N) for i in range(N): k = dk * float(i if i < N / 2 else i - N) propagator = exp(complex(0, -dt * pow(k, 2) / (2.))) in_[i] = propagator * in_[i] in_ = np.fft.ifft(in_, N) for i in range(N): propagator = exp(complex(0, -potential(x[i], omega, beta, a_soft, r, E, dt, l) * dt / 2.)) in_[i] = propagator * in_[i] out_[l][i] = in_[i] initialGammaCentre = 0.0 finalGammaCentre = 0.0 for i in range(500, 2500 +1): initialGammaCentre += pow(abs(out_[0][i]), 2) * dx finalGammaCentre += pow(abs(out_[steps][i]), 2) * dx ionisationGamma = finalGammaCentre / initialGammaCentre return ionisationGamma def potential(x, omega, beta, a_soft, r, E, dt, l): V = (-1. / sqrt((x - (r / 2)) * (x - (r / 2)) + a_soft * a_soft)) + ((-1. / sqrt((x + (r / 2)) * (x + (r / 2)) + a_soft * a_soft))) + E * x return V
Since the question is about how to use multiprocessing, the following code will work: import multiprocessing as mp if __name__ == '__main__': with mp.Pool(processes=16) as pool: Z = pool.starmap(ionisationGamma, arguments) Z = np.array(Z) Where the arguments are: arguments = list() for ridx in range(len(r)): for cidx in range(len(r[ridx])): arguments.append((r[ridx][cidx], E[ridx][cidx])) I am using starmap instead of map, since you have multiple arguments that you want to unpack. This will divide the arguments iterable over multiple cores, using the ionisationGamma function and the final result will be ordered. However, I do feel the need to say that the main solution is not really the multiprocessing but the original function code. In ionisationGamma you are using several times the slow python for loops. And it would benefit your code a lot if you could vectorize those operations. A second observation is that you are using many of those loops separately and it would be nice if you could separate that one big function into multiple smaller functions. Then you can time every function individually and speed up those that are too slow.
Optimize 2D numpy array creation loop
I have the following code, which I'd like to optimize. Unfortunately, I can't find a way to gain speed or vectorize anything. from scipy.sparse import diags import numpy as np def _compute_matrix_a(points, dw, dl, coefficient): """ """ coefficient = coefficient.reshape(points, order='F') extradl = coefficient[:,0] * 3 extradw = coefficient[0] * 3 #Build diagonals diagonal_a = [] diagonal_b = [] diagonal_c = [] diagonal_d = [] diagonal_e = [] for idx, (k, i) in enumerate(product(range(points[1]), range(points[0]))): if k == 0: continue if k <= 1: pass elif k < points[1] - 1: a = 1 / (4 * dl**2) * (coefficient[i][k-1] - coefficient[i][k+1])\ + coefficient[i][k] / dl**2 diagonal_a.append(a) else: a = coefficient[i][k-1] / (dl + extradl[i])**2\ + coefficient[i][k] / (dl**2 / 2 + extradl[i]**2 / 2) diagonal_a.append(a) if k == 0 or (k == 1 and i == 0): pass elif i == 0: b = 0 diagonal_b.append(b) elif i < points[0] - 1: b = 1 / (4 * dw**2) * (coefficient[i-1][k] - coefficient[i+1][k]) \ + coefficient[i][k] * (1 / dw**2 - 1 / (2 * i * dw**2)) diagonal_b.append(b) else: b = coefficient[i-1][k] / (dw + extradw[k]) ** 2 \ + coefficient[i][k] / (dw**2 / 2 + extradw[k]**2 / 2) \ - coefficient[i][k] / (i * dw * (dw + extradw[k])) diagonal_b.append(b) if k == 0: pass elif i == 0: if k < points[1] - 1: c = - 4 * coefficient[i][k] / dw**2\ - 2 * coefficient[i][k] / dl**2 else: c = - 4 * coefficient[i][k] / dw**2\ - 2 * coefficient[i][k] / (dl**2 / 2 + extradl[i]**2 / 2) diagonal_c.append(c) elif i < points[0] - 1: if k < points[1] - 1: c = - 2 * coefficient[i][k] / dl**2 \ - 2 * coefficient[i][k] / dw**2 else: c = - 2 * coefficient[i][k] / dw**2 \ - 2 * coefficient[i][k] / (dl**2 / 2 + extradl[i]**2 / 2) diagonal_c.append(c) else: if k < points[1] - 1: c = - 2 * coefficient[i][k] / (dw**2 / 2 + extradw[k]**2 / 2) \ - 2 * coefficient[i][k] / dl**2 else: c = - 2 * coefficient[i][k] / (dw**2 / 2 + extradw[k]**2 / 2) \ - 2 * coefficient[i][k] / (dl**2 / 2 + extradl[i]**2 / 2) diagonal_c.append(c) if k == 0 or (k == points[1] - 1 and i == points[0] - 1): pass elif i == 0: d = 4 * coefficient[i][k] / dw**2 diagonal_d.append(d) elif i == points[0] - 1: d = 0 diagonal_d.append(d) else: d = 1 / (4 * dw ** 2) * (coefficient[i+1][k] - coefficient[i-1][k]) \ + coefficient[i][k] * (1 / dw**2 + 1 / (2 * i * dw**2)) diagonal_d.append(d) if k == 0 or k == points[1] - 1: pass else: e = 1 / (4 * dl**2) * (coefficient[i][k+1] - coefficient[i][k-1])\ + coefficient[i][k] / dl**2 diagonal_e.append(e) diagonals = [diagonal_a, diagonal_b, diagonal_c, diagonal_d, diagonal_e] mat_a = diags(diagonals, [-points[0], -1, 0, 1, points[0]]).toarray() return mat_a mesh_points = (20, 50) coefficients = np.random.rand(mesh_points[0], mesh_points[1]) dwidth = 100. dlength = 100. mymatrix = _compute_matrix_a(mesh_points, dwidth, dlength, coefficients) I can't seem to find a way around my two loops (itertool product) to create the matrix. I tried using np.roll: # This gets the k-1 coefficients_km1 = np.roll(coefficients, 1, axis=0) # This gets the i-1 coefficients_im1 = np.roll(coefficients, 1, axis=1) # This gets the k+1 coefficients_kp1 = np.roll(coefficients, -1, axis=0) # This gets the i+1 coefficients_ip1 = np.roll(coefficients, -1, axis=1) Unfortunately, I couldn't convert the idea fully and got stuck in creating the array. I'm open to any suggestion to optimize this function.
Z factor iteration using VBA
I created a form button with two subroutines. 1.Pressure Depth Calculations 2. Z factor calculation Both are iterations. (1) is running properly while (2) does not execute. Following are the codes: Sub PressureDepthCalculation() 'Declaring Variables Dim i, t, row As Integer t = Range("B5").Value row = 11 'For Loop For i = t To 0 Step -100 'Depth caclculation Range("A" & row).Value = i 'Pressure calculation Range("B" & row).Value = Range("F5").Value + 0.052 * Range("F6") * i row = row + 1 Next i End Sub Sub ZFactorCalculation() 'Z factor calculation Dim r1, r2, r3, r4, r5, ppc, tpc, ppr, tpr, fr, dfr, ddfr, rhor As Double Dim i, row,t As Integer t = 1 row = 11 Range("D6").Value = 10.731 a1 = 0.3265 a2 = 1.07 * -1 a3 = 0.5339 * -1 a4 = 0.01569 a5 = 0.05165 * -1 a6 = 0.5475 a7 = 0.7361 * -1 a8 = 0.1844 a9 = 0.1056 a10 = 0.6134 a11 = 0.721 For i = t To 100 ppc = (4.6 + (0.1 * Range("H6").Value) - (0.258 * Range("H6").Value ^ 2) * 10.1325 * 14.7) tpc = (99.3 + (180 * Range("H6").Value) - (6.94 * Range("H6").Value ^ 2) * 1.8) ppr = 6760 / ppc tpr = Range("B6").Value / tpc rhor = 0.27 * ppr / tpr r1 = (a1 + (a2 / tpr) + (a3 / tpr ^ 3) + (a4 / tpr ^ 4) + (a5 / tpr ^ 5)) r2 = ((0.27 * ppr) / tpr) r3 = (a6 + (a7 / tpr) + (a8 / tpr ^ 2)) r4 = a9 * ((a7 / tpr) + (a8 / tpr ^ 2)) r5 = (a10 / tpr ^ 3) fr = (r1 * rhor) - (r2 / rhor) + (r3 * rhor ^ 2) - (r4 * rhor ^ 5) + (r5 * (1 + (a11 * rhor ^ 2))) * (Exp(-a11 * rhor ^ 2)) + 1 dfr = (r1) + (r2 / rhor ^ 2) + (2 * r3 * rhor) - (5 * r4 * rhor ^ 4) + (2 * r5 * rhor * (Exp(-a11 * rhor ^ 2)) * ((1 + (2 * a11 * rhor ^ 3)) - (a11 * rhor ^ 2 * (1 + (a11 * rhor ^ 2))))) ddfr = rhor - (fr / dfr) If Abs(rhor - ddfr) <= 0.000000000001 Then Range("I" & r).Value = (0.27 * ppr) / (rhor * tpr) Else rhor = ddfr End If Also when in (1) I calculate Range("B"&row).value, I want to use it to calculate ppc in place of 6760 in (2).
It appears that your second loop has no directive to continue the loop. You can either do: For i = t To 100 **Step someNumber** 'The -Step- argument was used in loop 1, but was omitted in loop 2 Or this: For i = t To 100 'the rest of your code here **Next i** 'will increment i by 1 Welcome to StackOverflow :)