Wednesday, 8 October 2025

Graphene Sheet Demand Forecast Using Normal Distribution

Assume Graphene Sheet Demand for last 100 days as Table 1 below.

Demand analysis and forecast for the graphene sheet based on the last 100 days of data:

🔹 Given:

  • Mean daily demand, μ=100.01\mu = 100.01

  • Standard deviation, σ=20.01\sigma = 20.01

  • Desired service level = 95%
    → which means the warehouse wants only a 5% risk of shortage.


🔹 Formula:

For a normal demand distribution, the required stock (safety stock included) for a given service level is:

                                                        Q μ × σ

Where:

  • zz = z-score corresponding to the desired service level

  • For 95% service level → z=1.645z = 1.645 (one-sided)


🔹 Calculation:


Q = 100.01 + 32.82 = 132.83

Answer:

The warehouse should prepare ≈ 133 graphene sheets to achieve a 95% service level (only 5% chance of shortage).



                                        Table 1: Graphene Sheet Demand for last 100 days


Code from ChatGPT


import numpy as np

import matplotlib.pyplot as plt

from scipy.stats import norm


# Given parameters

mean_demand = 100.01

std_demand = 20.01

service_level = 0.95

z_value = 1.645  # z-score for 95% service level


# Calculate the stock level for 95% service level

Q = mean_demand + z_value * std_demand


# Create range of possible demand values

x = np.linspace(mean_demand - 4*std_demand, mean_demand + 4*std_demand, 500)

y = norm.pdf(x, mean_demand, std_demand)


# Plot the normal distribution

plt.figure(figsize=(8, 5))

plt.plot(x, y, label='Demand Distribution', linewidth=2)

plt.fill_between(x, y, 0, where=(x <= Q), color='skyblue', alpha=0.4, label='95% Service Area')

plt.axvline(Q, color='red', linestyle='--', linewidth=2, label=f'95% Service Level = {Q:.1f} sheets')


# Labels and title

plt.title("Graphene Sheet Demand Forecast (95% Service Level)")

plt.xlabel("Daily Demand (Sheets)")

plt.ylabel("Probability Density")

plt.legend()

plt.grid(alpha=0.3)


# Show plot

plt.show()








Tuesday, 7 October 2025

Inventory Power of Two Policy For A Serial System

Serial System: Manufacturer → Warehouse → Retail Store

A warehouse supplies a retail store with Graphene. The store faces a steady annual demand of 2,400 units.
Each order placed by the store costs $30, and the holding cost rate is 25% of the item’s value ($20 per unit).

The warehouse replenishes the item from an external supplier.
Each order the warehouse places costs $200, and its holding cost rate is 15% of the item’s value ($15 per unit).

Assume a year has 52 weeks, and both locations operate under a Power-of-Two (PO2) policy with a 1-week base period.


Required

  1. (a) Determine the optimal EOQ and order interval for the retail store and warehouse (ignore PO2 restriction).

  2. (b) Round each order interval to the nearest Power-of-Two number of weeks.

  3. (c) Suggest a synchronized PO2 plan for the two levels.

(a) EOQ and Optimal Order Interval (no PO2 restriction)

Formula:

Formula:

Q=2Kdhc,T=Qd (in years)

✅ Final PO2 Serial System Summary

LocationEOQ (units)EOQ Interval (weeks)PO2 Interval (weeks)PO2 Q (units)
Retail Store1703.74185
Warehouse65414.216739

💬 Interpretation

  • The retail store orders 185 units every 4 weeks.

  • The warehouse orders 739 units every 16 weeks from the supplier.

  • The Power-of-Two synchronization ensures that every fourth store order triggers one warehouse order — simple and coordinated.




Code from ChatGPT

import numpy as np
import matplotlib.pyplot as plt

# ----------------------------
# Basic data for Graphene system
# ----------------------------
# Retail store parameters
d_store = 2400       # annual demand (units)
K_store = 30         # ordering cost ($)
h_store = 0.25       # holding cost rate
c_store = 20         # unit cost ($)
Q_star_store = 170   # EOQ
Q_po2_store = 185    # PO2

# Warehouse parameters
d_wh = 2400
K_wh = 200
h_wh = 0.15
c_wh = 15
Q_star_wh = 654
Q_po2_wh = 739

# ----------------------------
# Cost function
# ----------------------------
def total_cost(Q, K, d, h, c):
    return K * d / Q + h * c * Q / 2

# Range of Q values
Q_store = np.linspace(50, 400, 300)
Q_wh = np.linspace(200, 1200, 300)

# Compute total costs
cost_store = total_cost(Q_store, K_store, d_store, h_store, c_store)
cost_wh = total_cost(Q_wh, K_wh, d_wh, h_wh, c_wh)

# EOQ and PO2 total costs
cost_store_star = total_cost(Q_star_store, K_store, d_store, h_store, c_store)
cost_store_po2 = total_cost(Q_po2_store, K_store, d_store, h_store, c_store)
cost_wh_star = total_cost(Q_star_wh, K_wh, d_wh, h_wh, c_wh)
cost_wh_po2 = total_cost(Q_po2_wh, K_wh, d_wh, h_wh, c_wh)

# ----------------------------
# Plot
# ----------------------------
plt.figure(figsize=(9,6))

# Retail store curve
plt.plot(Q_store, cost_store, label='Retail Store', color='blue')
plt.scatter(Q_star_store, cost_store_star, color='blue', marker='o', s=80, label='EOQ (Store)')
plt.scatter(Q_po2_store, cost_store_po2, color='cyan', marker='s', s=80, label='PO2 (Store)')

# Warehouse curve
plt.plot(Q_wh, cost_wh, label='Warehouse', color='green')
plt.scatter(Q_star_wh, cost_wh_star, color='green', marker='o', s=80, label='EOQ (Warehouse)')
plt.scatter(Q_po2_wh, cost_wh_po2, color='lime', marker='s', s=80, label='PO2 (Warehouse)')

# ----------------------------
# Formatting
# ----------------------------
plt.title('Graphene Inventory Cost Curves')
plt.xlabel('Order Quantity (units)')
plt.ylabel('Total Annual Cost ($)')
plt.grid(True, linestyle='--', alpha=0.6)
plt.legend()
plt.tight_layout()

# Show graph
plt.show()





Sunday, 5 October 2025

Inventory Reorder Level

The inventory reorder level (also known as the reorder point, or ROP) is the specific inventory level at which a new order should be placed to replenish stock before it runs out, ensuring there are no stock-outs.

Reorder Level Formula

ROP Daily Usage × Lead Time


Question

A solar battery company stocks Graphene for which the following information is available:

Usage – 50 Graphene per day
Lead time – 20 days
Reorder quantity – 1500 Graphene

Based on the data above, at what level of inventory should a replenishment order be issued in order to ensure that there are no stock-outs?

ROP=50×20=1,000 Graphene

A replenishment order should be issued when the inventory level reaches 1,000 Graphene. This ensures the company has enough stock to cover the 20 days of lead time before new stock arrives.



Code by Chat GPT

import matplotlib.pyplot as plt


# Parameters

daily_usage = 50

lead_time = 20

reorder_quantity = 1500

reorder_point = daily_usage * lead_time  # 1000

initial_inventory = reorder_point + reorder_quantity  # Start with some buffer


# Simulation

days = 100

inventory = initial_inventory

inventory_levels = []

orders = []          # Days when reorders are placed

deliveries = []      # Days when stock arrives

on_order = []        # Pending orders (arrival_day, quantity)


for day in range(days):

    # Check for incoming deliveries

    for arrival_day, qty in on_order[:]:

        if day == arrival_day:

            inventory += qty

            deliveries.append(day)

            on_order.remove((arrival_day, qty))


    # Record current inventory

    inventory_levels.append(inventory)


    # Deplete inventory by daily usage

    inventory -= daily_usage


    # Place a reorder if below or at reorder point and no pending orders

    if inventory <= reorder_point and not any(arrival > day for arrival, _ in on_order):

        arrival_day = day + lead_time

        on_order.append((arrival_day, reorder_quantity))

        orders.append(day)


# Plotting

plt.figure(figsize=(12, 6))

plt.plot(range(days), inventory_levels, label='Inventory Level', color='blue', linewidth=2)

plt.axhline(reorder_point, color='red', linestyle='--', label='Reorder Point (1000)')

plt.scatter(orders, [inventory_levels[day] for day in orders], color='green', marker='o', label='Reorder Placed')

plt.scatter(deliveries, [inventory_levels[day] for day in deliveries], color='orange', marker='^', label='Inventory Replenished')


# Labels and formatting

plt.title('Graphene Inventory Level Over Time', fontsize=14)

plt.xlabel('Day', fontsize=12)

plt.ylabel('Inventory Level (Graphene)', fontsize=12)

plt.legend()

plt.grid(True)

plt.tight_layout()


# Show plot

plt.show()


Saturday, 4 October 2025

FIFO Methods of Valuing Cost Of Inventory

Angel Ltd deals in one item of inventory, Graphene with below details around Jan 2025. 

Inventory at 1 Jan, 40 units@$50 

Purchase at 6 Jan, 50 units@$52 

Sold on 11 Jan, 38 units 

Purchase on 16 January, 45units@$48 

Sold on 21 January, 58 units 

Sold on 26 January, 38 Units. 

Can you calculate the closing inventory at 31 January 2025 using the method FIFO?


Answer:

Closing Inventory at 31 January 2025 using FIFO = 1 unit @ $48 = $48


Graph by ChatGPT


Code by ChatGPT

import matplotlib.pyplot as plt

import matplotlib.ticker as mtick


# Dates of interest

dates = ["1 Jan", "11 Jan", "16 Jan", "21 Jan", "26 Jan", "31 Jan"]


# Total inventory value after each transaction

inventory_values = [2000, 2700, 4860, 1872, 48, 48]  # Value in dollars


# Total inventory units after each transaction

inventory_units = [40, 52, 97, 39, 1, 1]


# Per-unit cost (total value / total units)

unit_costs = [v/u for v, u in zip(inventory_values, inventory_units)]


# Plotting

fig, ax1 = plt.subplots(figsize=(10, 6))


# Bar chart for total inventory value

bars = ax1.bar(dates, inventory_values, color='skyblue', label='Total Inventory Value ($)')

ax1.set_ylabel('Total Inventory Value ($)', color='blue')

ax1.set_xlabel('Date')

ax1.tick_params(axis='y', labelcolor='blue')

ax1.set_title('Inventory Value and Per-Unit Cost Over Time (FIFO Method)')


# Annotate bars with unit cost

for bar, unit_cost in zip(bars, unit_costs):

    height = bar.get_height()

    ax1.text(bar.get_x() + bar.get_width()/2, height + 50, f"${unit_cost:.2f}", 

             ha='center', va='bottom', fontsize=10, color='black')


# Line chart on secondary y-axis for per-unit cost

ax2 = ax1.twinx()

ax2.plot(dates, unit_costs, color='orange', marker='o', label='Unit Cost ($)')

ax2.set_ylabel('Unit Cost ($)', color='orange')

ax2.tick_params(axis='y', labelcolor='orange')

ax2.yaxis.set_major_formatter(mtick.FormatStrFormatter('%.2f'))


# Add legends

fig.legend(loc='upper right', bbox_to_anchor=(1,1), bbox_transform=ax1.transAxes)


plt.tight_layout()

plt.show()



Wednesday, 1 October 2025

Economic Order Quantity (EOQ) For Inventory

Paste this question in Grok. 

Lisa is budgeting to use 12 000 units of material Graphene during the year. Production will be distributed evenly throughout the year. The company does not carry any safety (buffer) levels of inventory.

Additional information

Cost of material Graphene $60 per unit

Ordering costs $500 per order

Inventory holding costs 8% of the average inventory value per annum

Order sizes available 1 000, 1 500, 2 000 and 3 000 units

Calculate the optimum order size using the Economic Order Quantity (EOQ) formula. 

Economic order quantity = √(2DS/H)= 1 581 units (1 500 order size)Graph Plotted by Grok


EOQ: 1581.14 units

Total Costs for Available Order Sizes:
Order Size 1000 units: Total Cost = $8400.00
Order Size 1500 units: Total Cost = $7600.00
Order Size 2000 units: Total Cost = $7800.00
Order Size 3000 units: Total Cost = $9200.00

Optimal Order Size: 1,500 units with Total Cost = $7600.00

Python Code From Grok
import numpy as np
import matplotlib.pyplot as plt

# Given data
D = 12000  # Annual demand (units)
S = 500    # Ordering cost per order ($)
H = 4.80   # Holding cost per unit per year ($)

# Calculate EOQ
EOQ = np.sqrt((2 * D * S) / H)

# Available order sizes
order_sizes = [1000, 1500, 2000, 3000]

# Function to calculate total cost
def total_cost(Q, D, S, H):
    ordering_cost = (D / Q) * S
    holding_cost = (Q / 2) * H
    return ordering_cost + holding_cost

# Calculate total costs for available order sizes
total_costs = [total_cost(Q, D, S, H) for Q in order_sizes]

# Calculate total cost for EOQ (for reference)
eoq_cost = total_cost(EOQ, D, S, H)

# Generate data for plotting the total cost curve
Q_range = np.arange(500, 3500, 10)  # Range of order quantities for smooth curve
tc_values = [total_cost(Q, D, S, H) for Q in Q_range]

# Plotting
plt.figure(figsize=(10, 6))
plt.plot(Q_range, tc_values, label='Total Cost Curve', color='blue')
plt.scatter(order_sizes, total_costs, color='red', label='Available Order Sizes', zorder=5)
plt.scatter([EOQ], [eoq_cost], color='green', label=f'EOQ ({EOQ:.2f} units)', zorder=5)
plt.axvline(x=1500, color='purple', linestyle='--', label='Optimal Order Size (1,500 units)', alpha=0.5)

# Add labels and title
plt.xlabel('Order Quantity (Q)')
plt.ylabel('Total Annual Cost ($)')
plt.title('EOQ and Total Inventory Cost')
plt.legend()
plt.grid(True)

# Show plot
plt.show()

# Print results
print(f"EOQ: {EOQ:.2f} units")
print("\nTotal Costs for Available Order Sizes:")
for Q, cost in zip(order_sizes, total_costs):
    print(f"Order Size {Q} units: Total Cost = ${cost:.2f}")
print(f"\nOptimal Order Size: 1,500 units with Total Cost = ${total_costs[1]:.2f}")

Working Capital Cycle: A Key to Better Cash Flow

The working capital cycle (WCC) measures the time in days a company takes to convert its net working capital—current assets minus current li...