diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..26d3352 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..fed8c48 --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +OrderSystem.py \ No newline at end of file diff --git a/.idea/HTSim.iml b/.idea/HTSim.iml new file mode 100644 index 0000000..d870a4a --- /dev/null +++ b/.idea/HTSim.iml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 0000000..105ce2d --- /dev/null +++ b/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..ab530bf --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..6b96659 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/ABMfim流程00.txt b/ABMfim流程00.txt new file mode 100644 index 0000000..4aa49c2 --- /dev/null +++ b/ABMfim流程00.txt @@ -0,0 +1,42 @@ +!按子系统功能! + +Oss: +接收订单。 +计算到当期为止,未交付订单的各类产品与其库存之差,得到gap最大的产品,并将能获得该商品最大生产率的生产状态通知Iss和Pss。 + +交付当期到期和已经出现延期的订单,先进先出。 + +计算(env)延期平均时间:延期时间 * 延期产品数/10000 + +Iss: +按照Oss指定的生产状态,准备原材料并交付Pss(如果原材料不充足,就将能交付的先交付) + +每期末统计原材料使用情况,按照遗传算法提供的Sspolicy,选择是否订货(初始原材料备货为s),如果订货要随机生成该原材料的交货期。 + +每期末要更新原材料剩余情况(上一次余值+当期到货量-当期使用量) + +更新产成品期末库存。 + + +Pss: +根据Oss的指示,开始生产,如果原材料不充足,就按照gap大小进行生产;如果没有gap的产品了,就按照库存水平由少到多进行生产。 +(此处如果出现原材料余料,回交Iss) +生成最终生产结果,产成品交付Iss。 + + +!按流程 ! + +Oss:接收订单。计算到当期为止,未交付订单的各类产品与其库存之差,得到gap最大的产品,并将能获得该商品最大生产率的生产状态通知Iss和Pss。 + +Iss:按照Oss指定的生产状态,准备原材料并交付Pss(如果原材料不充足,就将能交付的先交付)。 + +Pss:根据Oss的指示,开始生产,如果原材料不充足,就按照gap大小进行生产;如果没有gap的产品了,就按照库存水平由少到多进行生产。 +(此处如果出现原材料余料,回交Iss) +生成最终生产结果,产成品交付Iss。 + +Iss:统计原材料使用情况,按照遗传算法提供的Sspolicy,选择是否订货(初始原材料备货为s),如果订货要随机生成该原材料的交货期。 +每期末要更新原材料剩余情况(上一次余值+当期到货量-当期使用量)。 +更新产成品期末库存。 + +Oss:交付当期到期和已经出现延期的订单,先进先出。计算(env)延期平均时间:延期时间 * 延期产品数/10000 + diff --git a/Environment.py b/Environment.py new file mode 100644 index 0000000..0ca7f73 --- /dev/null +++ b/Environment.py @@ -0,0 +1,165 @@ +import random +import numpy as np +import pandas as pd +import agentpy as ap +from datetime import datetime +from numpy import random +import json + +from Firm import Firm +# import passive agents +from Order import Order + +from fake_api import get_plan_by_pp_id, get_bom_by_prd_id + + +class FMSEnv(ap.Model): + # put all parameters here, not in any other places + # xv_int_max_order: int + # ev_n_order_created: int + + the_firm: Firm + + # record data, define below + # op_os_n_total_order: int + # op_os_n_total_order_delayed: int + op_os_all_delay_time: list + # op_os_delay_ratio: float + # op_is_flt_material_room_left: float + # op_is_flt_product_room_left: float + + op_ps_str_status: str + op_os_to_dlv: np.ndarray + op_is_current_product: np.ndarray + op_is_current_material: np.ndarray + op_is_trans_material: np.ndarray + op_ps_back_trans_material: np.ndarray + op_ps_produced_num: np.ndarray + op_is_ip_mat_id: np.ndarray + op_ip_prd_s: np.ndarray + op_ip_prd_big_s: np.ndarray + op_ip_prd_est_pfm: int + + def __init__(self, dct_all_para, _run_id=None): + super().__init__() + + # create agents here + self.the_firm = Firm(env=self, dct_all_para=dct_all_para) + + # get the input parameter values from the dictionary + self.int_stop_time = int(dct_all_para['time']) + # self.xv_int_max_order = int(dct_all_para['xv_int_max_order']) + self.xv_dlv_product_para = np.asarray(dct_all_para['xv_dlv_product_para']) + # self.xv_int_dlv_period_lam = int(dct_all_para['xv_int_dlv_period_lam']) + # self.ev_n_order_created = 0 + + self.running = True + self.t = 0 + + # Creation of orders should be done in the environment + def create_order(self): + # Check if maximum number of orders has been reached + xv_int_create_order_num = 1 + # xv_int_create_order_num = random.poisson(lam=xv_int_create_order_lam, size=None) + # if self.ev_n_order_created < xv_int_max_order: + for i in range(xv_int_create_order_num): + new_order = Order(model=self, time_created=self.t, xv_dlv_product_para=self.xv_dlv_product_para, + leadtime=max(self.the_firm.xv_ary_lead_time)) + return new_order + return None + + # Execute the interactions of each time step in the simulation. + def step(self): + # organize the interactions of agents in each time step here + new_order = self.create_order() + self.the_firm.the_os.accept_order(new_order) + + self.the_firm.operating() + self.update() + + if self.t >= self.int_stop_time: + self.running = False + self.stop() + else: + print(f"running the {self.t} step") + + # Record data after each simulation + def update(self): + self.op_os_n_total_order = len(self.the_firm.the_os.a_lst_order) + # self.op_os_n_total_order_delayed = len([e for e in self.the_firm.the_os.a_lst_order if e.xv_dlv_t < self.t]) + self.op_os_to_dlv = self.the_firm.the_os.ev_ary_to_dlv + # self.op_os_all_delay_time = self.the_firm.the_os.ev_lst_all_delay_time + + self.op_ps_produced_num = self.the_firm.the_ps.ev_ary_produced_num + self.op_ps_str_status = self.the_firm.the_ps.ev_str_status + + # self.op_is_current_product = self.model.the_firm.the_is.ev_ary_current_product + # + # self.op_is_current_material = self.model.the_firm.the_is.ev_ary_current_material + # + # self.op_is_trans_material= self.model.the_firm.the_is.ev_lst_trans_material + + self.op_ps_back_trans_material = self.model.the_firm.the_ps.ev_lst_backtrans_material + + self.record([att for att in self.__dict__.keys() if att.startswith('op_')]) + pass + + +if __name__ == '__main__': + dct_para = { + 'time': 60, + # 'xv_int_max_order': random.randint(30, 50), + # 'xv_dlv_product_para': tuple([(30, 100), (30, 50)]), + # 'xv_dlv_product_para': tuple([30,40,30,20]), # 读取生产率 np.read. + # 'xv_int_dlv_period_lam': 8.5, + # 'xv_int_create_order_lam': 2, + # 'xv_ary_price_product': tuple([0.3,0.2,0.5,1]), + # 'xv_ary_cost_material_per': tuple([0.1,0.1,0.2,0.4]), + # 'xv_ary_volume_material': tuple([1.0, 1.5]), + # 'xv_ary_volume_product': tuple([3.0, 5.0]), + 'xv_array_lead_time': 2, # 读取原材料表格 np.read.,暂时不读 + # 'xv_int_lead_time_c': 3, + # 'xv_int_lead_time_d': 1, + 'xv_ary_initial_product_num': pd.read_excel("initial_product.xlsx").to_numpy(), + 'xv_ary_initial_material_num': pd.read_excel("initial_material.xlsx").to_numpy(), # 应读取遗传算法中随机生成的s,暂写为'1' 创建两个excel分别存储产品和原材料的库存 每个excel中存系统代码和库存 + # 'xv_flt_initial_cash': 50000.0, + # 'dct_status_info': json.dumps({ #需要引入生产状态表 + # "0": {"xv_flt_produce_rate": tuple([0.0, 0.0]), + # "xv_ary_mat_material": tuple([0.0, 0.0]), + # "xv_flt_broken_rate": 0, + # "xv_flt_run_cost": 0.0, + # "name": "wait" + # }, + # "1": {"xv_flt_produce_rate": tuple([90.0, 0.0]), + # "xv_ary_mat_material": tuple([4.0, 1.0]), + # "xv_flt_broken_rate": 0.03, + # "xv_flt_run_cost": 40.0, + # "name": "produceA" + # }, + # "2": {"xv_flt_produce_rate": tuple([0.0, 60.0]), + # "xv_ary_mat_material": tuple([1.5, 5.0]), + # "xv_flt_broken_rate": 0.05, + # "xv_flt_run_cost": 50.0, + # "name": "produceB" + # }, + # "3": {"xv_flt_produce_rate": tuple([55.0, 30.0]), + # "xv_ary_mat_material": tuple([2.0, 1.5]), + # "xv_flt_broken_rate": 0.07, + # "xv_flt_run_cost": 60.0, + # "name": "produceAB" + # }, + # "-1": {"xv_flt_produce_rate": 0.0, + # "xv_ary_mat_material": tuple([0.0, 0.0]), + # "xv_flt_broken_rate": 0.1, + # "xv_flt_run_cost": 100.0, + # "name": "failed" + # } + # }) + + } + sample = ap.Sample(dct_para) + + exp = ap.Experiment(FMSEnv, sample, iterations=1, record=True) + results = exp.run() + # results['variables']['FMSEnv'].to_excel(f"simulation-results-{datetime.today().strftime('%Y-%m-%d-%H-%M-%S')}.xlsx", + # engine='openpyxl') diff --git a/Firm.py b/Firm.py new file mode 100644 index 0000000..22607b7 --- /dev/null +++ b/Firm.py @@ -0,0 +1,37 @@ +import numpy as np +import json + +from InventorySystem import InventorySystem +from OrderSystem import OrderSystem +from ProduceSystem import ProduceSystem + +# Create Company Instance +class Firm: + the_os: OrderSystem + the_is: InventorySystem + the_ps: ProduceSystem + + def __init__(self, env, dct_all_para): + self.env = env + + # get the parameters here + self.xv_ary_initial_product_num = np.asarray(dct_all_para['xv_ary_initial_product_num']) + self.xv_ary_initial_material_num = np.asarray(dct_all_para['xv_ary_initial_material_num']) + self.dct_status_info = json.loads(dct_all_para['dct_status_info']) + self.xv_ary_lead_time = np.array([dct_all_para['xv_int_lead_time_a'], dct_all_para['xv_int_lead_time_b']]) + + # create agents here + self.the_os = OrderSystem(env) + self.the_is = InventorySystem(env, xv_ary_initial_material_num=self.xv_ary_initial_material_num, + xv_ary_initial_product_num=self.xv_ary_initial_product_num, + xv_ary_lead_time=self.xv_ary_lead_time) + self.the_ps = ProduceSystem(env, dct_status_info=self.dct_status_info) + # self.the_fs = FinancialSystem(env, xv_flt_initial_cash=self.xv_flt_initial_cash) + + def operating(self): + self.the_os.rank_order() + self.the_ps.change_status() + self.the_ps.run_produce() + self.the_os.do_shipment() + # self.the_is.inventory_cost() + # self.the_fs.financial_calculating() diff --git a/InventorySystem.py b/InventorySystem.py new file mode 100644 index 0000000..a82daac --- /dev/null +++ b/InventorySystem.py @@ -0,0 +1,128 @@ +import agentpy as ap +import numpy as np +from collections import deque + + +class InventorySystem(ap.Agent): + + xv_ary_initial_material_num: np.ndarray + xv_ary_initial_product_num: np.ndarray + ev_ary_current_material: np.ndarray #期末库存 + ev_ary_current_product: np.ndarray #期末库存 + ev_lst_trans_quan_material: np.ndarray # Iss传递给Pss的原材料数量 + ev_lst_backtrans_quan_material: np.ndarray # Pss退回的原材料数量 + ev_ary_material_state_to_use: np.ndarray # 当期预期使用的原材料 + ev_ary_material_to_use: np.ndarray # 当期实际消耗的原材料 + xv_array_dlv_product: np.ndarray # 产品交付 + + ev_ary_is_order_material: np.ndarray # 是否订购产品 + ev_ary_num_material_to_order: np.ndarray # 订购数量 + ev_ary_num_material_order_done: np.ndarray # 当期送到的数量 + + # set the lead time of material replenishment + xv_ary_lead_time: np.ndarray + + # the list of materials in transit + ev_lst_trans_material: list # Iss交给Pss的原材料 + ev_list_back_trans_material: list # Pss返回的原材料 + + ev_lst_material_inventory: list + ev_lst_product_inventory: list + + # Material list + xv_lst_material: np.ndarray + xv_ary_bom: np.ndarray + + # 原材料订购的开始时间和到达时间 + ev_int_order_time: np.ndarray + ev_int_arrive_time: np.ndarray + ev_ary_num_material_order_done: np.ndarray # 当期原材料到货量 + + def setup(self, xv_ary_initial_material_num, + xv_ary_initial_product_num, xv_ary_lead_time): + + # Set up the initial inventory quantity + self.xv_ary_initial_material_num = xv_ary_initial_material_num + self.xv_ary_initial_product_num = xv_ary_initial_product_num + self.ev_ary_current_material = xv_ary_initial_material_num # 115*2 + self.ev_ary_current_product = xv_ary_initial_product_num #23*2 + self.ev_ary_num_material_order_done = np.zeros((115, )) + + # set the lead time of materials + # 读取各个原材料的历史平均交货周期 bom table + self.xv_ary_lead_time = pd.read_excel("bom23.xlsx").iloc[:, 4].to_numpy() + # 切换成原材料 + self.ev_ary_is_order_material = np.array([False for i in range(115)]) + self.ev_ary_num_material_to_order = np.zeros((115,)) # 初始化 + self.ev_ary_material_state_to_use = np.zeros((115,)) + + self.ev_lst_material_inventory = [] + self.ev_lst_product_inventory = [] + + self.xv_lst_material = pd.read_excel("rawmaterial.xlsx").to_numpy() + + self.xv_ary_bom = pd.read_excel("bom23.xlsx").to_numpy() + + self.ev_lst_trans_quan_material = [] # Iss传递给Pss的原材料数量 + self.ev_lst_backtrans_quan_material = [] # Pss退回的原材料数量 + + self.ev_int_order_time = np.zeros((115,)) + self.ev_int_arrive_time = np.zeros((115,)) + + def material_state_to_use(self, xv_ary_dlv_product, ev_int_produce_type): + # 读取Oss决定的生产状态,根据生产状态所需的原材料进行汇总 + # self. ev_ary_material_state_to_use = np.multiply(self.xv_array_dlv_product, 原材料表 ) + produce_state = 1 # 获取生产状态 + produce_plan = xv_plan_excel[xv_plan_excel[:, 0] == produce_state] + for plan in produce_plan: + for bom in self.xv_ary_bom: + if plan[1] == bom[0]: + self.ev_ary_material_state_to_use[np.where(self.xv_lst_material == bom[1])] += plan[3] * bom[ + 2] # 某原材料的生产数量加等产品生产量乘单位原材料消耗量 + + def material_check(self, ev_ary_material_state_to_use): + # 根据Iss决策,核对库存是否充足,并将拥有的原材料交给Pss + # 可能需要一部生成原材料列表在调用 + # Check whether materials are enough and transfer material + index_mapping = {value: idx for idx, value in enumerate(self.ev_ary_current_material[:, 0])} + sorted_indices = [index_mapping[value] for value in self.xv_lst_material] + self.ev_ary_current_material = self.ev_ary_current_material[sorted_indices] # 按照原材料制定顺序进行重排 + for i in range(115): + if self.ev_ary_current_material[i, 1] >= ev_ary_material_state_to_use[i]: + self.ev_lst_trans_quan_material[i] = ev_ary_material_state_to_use[i] + # return (self.ev_ary_current_material >= ev_ary_material_to_use).all() + else: + self.ev_lst_trans_quan_material[i] = self.ev_ary_current_material[i] + + def consume_and_store(self, ev_ary_material_to_use, ev_ary_produced_num,ev_changed_product, + ev_lst_backtrans_material): + self.ev_lst_backtrans_quan_material = ev_lst_backtrans_material + # Update the inventory after production + for i in range(115): + self.ev_ary_material_to_use[i] = self.ev_lst_trans_quan_material[i] - \ + self.ev_lst_backtrans_quan_material[i] + + if self.ev_int_arrive_time == self.model.t: # 判断材料是否到达 + self.ev_ary_num_material_order_done[i] += self.ev_ary_num_material_to_order[i] + self.ev_ary_num_material_to_order[i] = 0 + self.ev_ary_is_order_material[i] = False + + self.ev_ary_current_material = self.ev_ary_current_material - ev_ary_material_to_use \ + + self.ev_ary_num_material_order_done + self.ev_ary_current_product = ev_changed_product + ev_ary_produced_num + return self.ev_ary_current_material, self.ev_ary_current_product + + def material_replenishment(self): + # Check the inventory of material to decide whether to replenish + # 核对原材料数量是否低于s + # 带时间戳 + for i in range(115): + if self.ev_ary_current_material[i] <= s: + self.ev_ary_is_order_material[i] = True + self.ev_ary_num_material_to_order[i] = S - self.ev_ary_current_material[i] + self.ev_int_order_time[i] = self.model.t + self.ev_int_arrive_time[i] = self.ev_int_order_time[i] + \ + self.xv_ary_bom[self.xv_ary_bom[:, 1] == self.xv_lst_material[i]][0, 4] + else: + self.ev_ary_num_material_to_order[i] = 0 + diff --git a/Order.py b/Order.py new file mode 100644 index 0000000..c6a8e89 --- /dev/null +++ b/Order.py @@ -0,0 +1,36 @@ +import agentpy as ap +import random +import numpy as np +from numpy import random +import pandas as pd + + +class Order(ap.Agent): + + xv_time_created: int # 订单创建时间 + xv_time_circle: int # 随机生成的交货周期 + xv_dlv_t: int # 客户希望的交货时间 + ev_actual_dlv_t: int # 实际交付时间 + + ev_is_delivered: bool # 订单是否已交付 + ev_is_accepted: bool # 订单是否被接受 + ev_int_delay_time: int # total delay time + + xv_ary_dlv_product: np.ndarray + ev_ary_dlv_product: np.ndarray + + def setup(self, time_created): + self.xv_time_created = time_created + # read the demand of 23 productions + df = pd.read_excel("demand23.xlsx") + self.xv_ary_dlv_product = df.to_numpy() + df = df.iloc[:, 1] + self.ev_ary_dlv_product = df.to_numpy() + self.xv_time_circle = np.random.randint(7, 11, 1) + self.xv_dlv_t = self.xv_time_created + self.xv_time_circle + self.ev_actual_dlv_t = self.xv_dlv_t + self.ev_int_delay_time = self.ev_actual_dlv_t - self.xv_dlv_t + + # Set the initial status of order to be undelivered, accepted + self.ev_is_delivered = False + self.ev_is_accepted = False diff --git a/OrderSystem.py b/OrderSystem.py new file mode 100644 index 0000000..004d0b6 --- /dev/null +++ b/OrderSystem.py @@ -0,0 +1,103 @@ +import agentpy as ap +import numpy as np +from Order import Order +import pandas as pd + +# 输出一个生产状态指令,一个交付情况,一个延期时间计算 +class OrderSystem(ap.Agent): + a_lst_order: ap.AgentList[Order] + ev_int_produce_type: int + ev_ary_to_dlv: np.ndarray # 当前order list内所有产品的综合 + ev_ary_product_to_produce: np.ndarray # 用于计算 production gap + ev_lst_all_delay_time: list + ev_ave_delay_time: float + xv_plan_excel: np.ndarray + ev_lst_flag: list + ev_changed_product: np.ndarray + # ev_ary_dlv_product: np.ndarray?????? + + def setup(self): + # Create a list of order + self.a_lst_order = ap.AgentList(self, []) + self.ev_ary_to_dlv = np.zeros((23, 1)) + self.ev_int_produce_type = 0 + self.ev_ary_product_to_produce = np.zeros((23,)) + self.ev_lst_all_delay_time = [] + self.ev_ave_delay_time = 0 + # self.ev_ary_dlv_product = np.zeros((23,)) ???? + self.ev_changed_product = np.zeros((23, )) + self.xv_plan_excel = pd.read_excel("plan.xlsx").to_numpy() + pass + + def accept_order(self, new_order): + # Determine whether the order is received and all are currently received + if new_order is not None: + new_order.ev_is_accepted = True + self.a_lst_order.append(new_order) + + def rank_order(self): + # Sort order + self.a_lst_order = self.a_lst_order.sort('xv_dlv_t', reverse=False) + + def produce_status(self): + # 计算a_lst_order内所有订单包含的产品总量与当期库存的gap,排序最大缺口量,选定生产状态 + self.ev_ary_to_dlv = np.zeros((23,)) + for order in self.model.the_firm.the_os.a_lst_order: + self.ev_ary_to_dlv += order.ev_ary_dlv_product # 当前天之前所有的还未满足的需求求和 + self.ev_ary_product_to_produce[:, 1] = self.ev_ary_to_dlv - self.model.the_firm.the_is.ev_ary_current_product + # self.ev_ary_product_to_produce = self.model.the_firm.the_is.ev_ary_current_product - self.ev_ary_to_dlv + # self.ev_ary_product_to_produce > 0: + # 选出这些产品,按照数值大小进行分类,数值最大的产品对应的能带来最大生产率的状态,则选定为ev_int_produce_type + # 如果均<=0, 按照产品库存ev_ary_current_material进行排序,选择能给库存最低的产品带来最高生产率的状态 + sorted_indices = np.argsort(self.ev_ary_product_to_produce[:, 1])[::-1] + sorted_data = self.ev_ary_product_to_produce[sorted_indices] + if sorted_data[0, 1] > 0: # 判断是否存在库存不足 + pass + else: + sorted_indices = np.argsort(self.model.the_firm.the_is.ev_ary_current_product[:, 1]) # 对库存进行从小到大排序 + sorted_data = self.model.the_firm.the_is.ev_ary_current_product[sorted_indices] + + a = self.xv_plan_excel[self.xv_plan_excel[:, 1] == sorted_data[0, 0]] # 检索最大值的产品的四种方案或者最小库存产品的四种方案 + sorted_indices = np.argsort(a[:, 3])[::-1] + sorted_data = a[sorted_indices] + # return sorted_data[0, 0] + self.ev_int_produce_type = sorted_data[0, 0] + return self.ev_int_produce_type + + def do_shipment(self,ev_ary_current_product): + # Make shipments based on ranked order list + # 交付两次,第一次未交付完成的订单要标记,交货的时候先便利delay的订单,如果能够满足全部剩余量,就交货,如果不能 + # 就继续在列表中存在 + # 只有完全交付的订单,才计算delay time = order.ev_int_delay_time * 第二次交付的订单内的各类产品之和 + # 需要更新 order.ev_ary_dlv_product + # Make shipments based on ranked order list + self.ev_lst_all_delay_time = [] + self.ev_ave_delay_time = 0 + self.ev_changed_product = ev_ary_current_product # 23x1 ndarray 存储本次库存的改变 + for order in self.a_lst_order: + if order.xv_dlv_t == self.model.t: # 第一次交付 + # Check and make shipment + order.ev_is_delivered = True + for i in range(len(order.ev_ary_dlv_product)): + if order.ev_ary_dlv_product[i] <= self.ev_changed_product[i]: + order.ev_ary_dlv_product[i] = 0 + self.ev_changed_product[i] -= order.ev_ary_dlv_product[i] + else: + order.ev_is_delivered = False + elif order.xv_dlv_t < self.model.t and order.ev_is_delivered == False: # 第二次交付 + order.ev_is_delivered = True + for i in range(len(order.ev_ary_dlv_product)): + if order.ev_ary_dlv_product[i] > self.ev_changed_product[i]: # 先判断能不能一次性交付 + order.ev_is_delivered = False + + if order.ev_is_delivered: # 如果一次性交付 + delay_num = np.sum(order.ev_ary_dlv_product) + order.ev_ary_dlv_product = np.zeros((23,)) + self.ev_changed_product = self.ev_changed_product - order.ev_ary_dlv_product + + order.ev_actual_dlv_t = self.model.t + order.ev_int_delay_time = order.ev_actual_dlv_t - order.xv_dlv_t + + self.ev_ave_delay_time += order.ev_int_delay_time * delay_num / 10000 + + return self.ev_changed_product, self.ev_ave_delay_time diff --git a/ProduceSystem.py b/ProduceSystem.py new file mode 100644 index 0000000..63d25b7 --- /dev/null +++ b/ProduceSystem.py @@ -0,0 +1,60 @@ +import agentpy as ap +import numpy as np +import random + + +class ProduceSystem(ap.Agent): + ev_str_status: str # 0,6,8,10 pp_id + ev_lst_backtrans_material: list # 退回Iss的原材料 + ev_ary_produce_number: np.ndarray + + def setup(self, dct_status_info): + self.ev_str_status = 0 + self.ev_lst_backtrans_material = [] + + def change_status(self): + self.ev_str_status = self.model.the_firm.the_os.produce_status() + + + def run_produce(self, ev_lst_material, ev_lst_trans_quan_material, ev_ary_product_to_produce, xv_plan_excel, + xv_ary_bom): # ev_ary_product_to_produce 是 需求和库存的gap 23x2 + # 生产状态由Iss确定,这个函数需要计算生产数量和原材料消耗量。 + # 如果原材料不足,就按照production gap(ev_ary_product_to_produce) 大小进行生产;如果没有gap的产品了,就按照库存水平由少到多进行生产。 + # 输出生产结果和原材料消耗结果 + produce_plan = xv_plan_excel[xv_plan_excel[:, 0] == self.ev_str_status] + sorted_indices = np.argsort(ev_ary_product_to_produce[:, 1])[::-1] + sorted_data = ev_ary_product_to_produce[sorted_indices] # 对gap进行从大到小排序 + sorted_indices_product = np.argsort(self.model.the_firm.the_is.ev_ary_current_product[:, 1]) # 对库存进行从小到大排序 + sorted_data_product = self.model.the_firm.the_is.ev_ary_current_product[sorted_indices_product] + self.ev_lst_backtrans_material = ev_lst_trans_quan_material + self.ev_ary_produce_number = [] + for product in sorted_data: + if product[1] > 0: # gap存在 + product_material = xv_ary_bom[xv_ary_bom[:, 0] == product[0]] + produce_number = produce_plan[produce_plan[:, 1] == product[0]][3] + for material in product_material: + produce_number = min(produce_number, int( + self.ev_lst_backtrans_material[np.where(ev_lst_material == material[1])] / material[ + 2])) # 取能生产的最小个数 + for material in product_material: + self.ev_lst_backtrans_material[np.where(ev_lst_material == material[1])] -= produce_number * material[ + 2] # 更新原材料消耗情况 + self.ev_ary_produce_number.append([product[0], produce_number]) + sorted_data_product = sorted_data_product[sorted_data_product[:, 0] != product[0]] + else: + for current_product in sorted_data_product: + product_material = xv_ary_bom[xv_ary_bom[:, 0] == current_product[0]] + produce_number = produce_plan[produce_plan[:, 1] == current_product[0]][3] + for material in product_material: + produce_number = min(produce_number, int( + self.ev_lst_backtrans_material[np.where(ev_lst_material == material[1])] / material[ + 2])) # 取能生产的最小个数 + for material in product_material: + self.ev_lst_backtrans_material[np.where(ev_lst_material == material[1])] -= produce_number * \ + material[2] # 更新原材料消耗情况 + self.ev_ary_produce_number.append([current_product[0], produce_number]) + break + + self.ev_ary_produce_number = np.array(self.ev_ary_produce_number) + + return self.ev_ary_produce_number, self.ev_lst_backtrans_material \ No newline at end of file diff --git a/bom23.csv b/bom23.csv new file mode 100644 index 0000000..bd0886b --- /dev/null +++ b/bom23.csv @@ -0,0 +1,208 @@ +prd_id,mtr_id,qty,unit +ADTB331M0611,Z013V09501055,0.000347,ƽ +ADTB331M0611,F00VC50A055,0.000418,ƽ +ADTB331M0611,SM26040B070,0.000033,ǧ +ADTB331M0611,D12073G2126b,0.0001, +ADTB331M0611,YG00002,9.33E-06, +ADTB331M0611,YHCP50A,0.00017,ǧ +ADTB331M0611,L063-109Y,0.0001,֧ +ADTB331M0611,P06-30I,0.0001,ֻ +ADTB331M0611,GT063T,0.000039,ǧ +AGTR4R7V0812,Z510V12001070,0.000623,ƽ +AGTR4R7V0812,F30VC20A070,0.000784,ƽ +AGTR4R7V0812,EHD450Z085,0.000094,ǧ +AGTR4R7V0812,D12087F2126,0.0001, +AGTR4R7V0812,YG00001,2.07E-05, +AGTR4R7V0812,YHBH421H,0.00019,ǧ +AGTR4R7V0812,N080-130Y,0.0001,֧ +AGTR4R7V0812,P08-30I,0.0001,ֻ +AGTR4R7V0812,GT080C,0.000071,ǧ +AMSR2R2M0609,Z530V12001050,0.000295,ƽ +AMSR2R2M0609,F30VC30A050,0.000345,ƽ +AMSR2R2M0609,W19040X065,0.000045,ǧ +AMSR2R2M0609,D12073T2126b,0.0001, +AMSR2R2M0609,YG00001,9.33E-06, +AMSR2R2M0609,YHBH421H,0.00011,ǧ +AMSR2R2M0609,T063-100Y,0.0001,֧ +AMSR2R2M0609,P06-26T,0.0001,ֻ +AMSR2R2M0609,MS063T,0.000039,ǧ +RD1H108M12025,Z067V10201160,0.00576,ƽ +RD1H108M12025,F00VC40A160,0.006224,ƽ +RD1H108M12025,SM26040B190,0.000519,ǧ +RD1H108M12025,D15147G2328y,0.0001, +RD1H108M12025,YG00006,0.000031, +RD1H108M12025,YHCP50A,0.00121,ǧ +RD1H108M12025,L125-257+,0.0001,֧ +RD1H108M12025,GNH-12.5M,0.0001,ֻ +RD1H108M12025,AW125T,0.000181,ǧ +RD1E108M10020,Z036V09001140,0.002408,ƽ +RD1E108M10020,F00VC40A140,0.002982,ƽ +RD1E108M10020,SM26040B160,0.000209,ǧ +RD1E108M10020,D15147G2328y,0.0001, +RD1E108M10020,YG00005,0.000031, +RD1E108M10020,YHCP50A,0.00057,ǧ +RD1E108M10020,L100-215+,0.0001,֧ +RD1E108M10020,GNH-10F,0.0001,ֻ +RD1E108M10020,AW100T,0.000121,ǧ +AMSR100V1013I,Z530V12001070,0.00126,ƽ +AMSR100V1013I,F30VC20A070,0.00147,ƽ +AMSR100V1013I,W19040X085,0.00018,ǧ +AMSR100V1013I,D15091TL2328,0.0001, +AMSR100V1013I,YG00007,,ǧ +AMSR100V1013I,YHBH421H,0.00026,ǧ +AMSR100V1013I,T100-135Y,0.0001,֧ +AMSR100V1013I,P10-35T,0.0001,ֻ +AMSR100V1013I,MS100T,0.000086,ǧ +AGEN181V1625,Z280V12002170,0.009673,ƽ +AGEN181V1625,F30VC20A170,0.010948,ƽ +AGEN181V1625,EHD440Z200,0.001346,ǧ +AGEN181V1625,D20180G2530,0.0001, +AGEN181V1625,YG00006,0.000065, +AGEN181V1625,YHBH250H,0.0028,ǧ +AGEN181V1625,T160-270Y,0.0001,֧ +AGEN181V1625,P16-50I,0.0001,ֻ +AGEN181V1625,EF160T,0.000261,ǧ +CEGM680M1020,Z210V11501140,0.002884,ƽ +CEGM680M1020,F30VC20A140,0.003164,ƽ +CEGM680M1020,W28540X1160,0.000334,ǧ +CEGM680M1020,D15131G2328,0.0001, +CEGM680M1020,YG00005,0.000031, +CEGM680M1020,YHBH250H,0.00057,ǧ +CEGM680M1020,N100-210Y,0.0001,֧ +CEGM680M1020,P10-35I,0.0001,ֻ +CEGM680M1020,EG100T,0.000117,ǧ +RD2G475M1012M,Z660V12002070,0.000819,ƽ +RD2G475M1012M,F30VC20A070,0.001057,ƽ +RD2G475M1012M,WS28050K085,0.000127,ǧ +RD2G475M1012M,TX15084*G2328,0.0001, +RD2G475M1012M,YG00003,0.0000285, +RD2G475M1012M,YHBH450H,0.00025,ǧ +RD2G475M1012M,L100-130+,0.0001,֧ +RD2G475M1012M,GNH-10L,0.0001,ֻ +RD2G475M1012M,AW100T,0.000082,ǧ +AMSR4R7M0812,Z530V12001070,0.00063,ƽ +AMSR4R7M0812,F30VC20A070,0.000735,ƽ +AMSR4R7M0812,EHD450Z085,0.000095,ǧ +AMSR4R7M0812,D12087T2126d,0.0001, +AMSR4R7M0812,YG00001,2.07E-05, +AMSR4R7M0812,YHBH421H,0.00019,ǧ +AMSR4R7M0812,T080-130Y,0.0001,֧ +AMSR4R7M0812,P08-30T,0.0001,ֻ +AMSR4R7M0812,MS080T,0.000072,ǧ +AVSR2R2V0609,Z530V12001050,0.000305,ƽ +AVSR2R2V0609,F30VC30A050,0.00037,ƽ +AVSR2R2V0609,W19040X065,0.000046,ǧ +AVSR2R2V0609,D12073F2126b,0.0001, +AVSR2R2V0609,YG00001,9.33E-06, +AVSR2R2V0609,YHBH421H,0.00011,ǧ +AVSR2R2V0609,L063-100Y,0.0001,֧ +AVSR2R2V0609,P06-26I,0.0001,ֻ +AVSR2R2V0609,EF063C,0.000034,ǧ +AMSR6R8M1013,Z530V12001070,0.000903,ƽ +AMSR6R8M1013,F30VC20A070,0.001043,ƽ +AMSR6R8M1013,EHD450Z085,0.000136,ǧ +AMSR6R8M1013,D15091T2328,0.0001, +AMSR6R8M1013,YG00002,1.93E-05, +AMSR6R8M1013,YHBH421H,0.00026,ǧ +AMSR6R8M1013,T100-135Y,0.0001,֧ +AMSR6R8M1013,P10-35T,0.0001,ֻ +AMSR6R8M1013,MS100T,0.000086,ǧ +AMSR3R3M0810,Z530V12001050,0.000445,ƽ +AMSR3R3M0810,F30VC30A050,0.00052,ƽ +AMSR3R3M0810,EHD450Z065,0.000072,ǧ +AMSR3R3M0810,D12073T2126b,0.0001, +AMSR3R3M0810,YG00002,0.000019, +AMSR3R3M0810,YHBH421H,0.00017,ǧ +AMSR3R3M0810,T080-103Y,0.0001,֧ +AMSR3R3M0810,P08-26T,0.0001,ֻ +AMSR3R3M0810,MS080T,0.000059,ǧ +AMSN120M0812I,Z280V12001070,0.000651,ƽ +AMSN120M0812I,F30VC20A070,0.000826,ƽ +AMSN120M0812I,EHD450Z085,0.000098,ǧ +AMSN120M0812I,D12087TL2126d,0.0001, +AMSN120M0812I,YG00003,0.000031, +AMSN120M0812I,YHBH250H,0.00019,ǧ +AMSN120M0812I,T080-130Y,0.0001,֧ +AMSN120M0812I,P08-30T,0.0001,ֻ +AMSN120M0812I,MS080T,0.000072,ǧ +WL1H476M6L011,Z082V10001065,0.000371,ƽ +WL1H476M6L011,F20VC50A065,0.000436,ƽ +WL1H476M6L011,MJ24540K080,0.001368,ǧ +WL1H476M6L011,D12087G2126,0.0001, +WL1H476M6L011,YG00024,0.00001, +WL1H476M6L011,YHCP50A,0.00012,ǧ +WL1H476M6L011,L063-117+,0.0001,֧ +WL1H476M6L011,GAH-6.3L,0.0001,ֻ +WL1H476M6L011,AW063T,0.000043,ǧ +AMSR8R2M1013,Z530V12001070,0.001085,ƽ +AMSR8R2M1013,F30VC20A070,0.001225,ƽ +AMSR8R2M1013,EHD450Z085,0.000164,ǧ +AMSR8R2M1013,D15091T2328,0.0001, +AMSR8R2M1013,YG00001,1.93E-05, +AMSR8R2M1013,YHBH421H,0.00026,ǧ +AMSR8R2M1013,T100-135Y,0.0001,֧ +AMSR8R2M1013,P10-35T,0.0001,ֻ +AMSR8R2M1013,MS100T,0.000086,ǧ +AGFM121M1320,Z210V11501140,0.004998,ƽ +AGFM121M1320,F30VC20A140,0.005348,ƽ +AGFM121M1320,EHD440Z160,0.000579,ǧ +AGFM121M1320,D15147G2328bd,0.0001, +AGFM121M1320,YG00004,0.0000375, +AGFM121M1320,YHBH250H,0.00099,ǧ +AGFM121M1320,L130-215Y,0.0001,֧ +AGFM121M1320,P13-35I,0.0001,ֻ +AGFM121M1320,EF130T,0.000155,ǧ +AGSS100V1013,Z590V10503075,0.001493,ƽ +AGSS100V1013,F30VC20A075,0.00162,ƽ +AGSS100V1013,W19040X090,0.00021,ǧ +AGSS100V1013,D15091F2328,0.0001, +AGSS100V1013,YG00003,0.000029, +AGSS100V1013,YHBH450H,0.00049,ǧ +AGSS100V1013,L100-140Y,0.0001,֧ +AGSS100V1013,P10-35I,0.0001,ֻ +AGSS100V1013,GS100C,0.000099,ǧ +AVSR3R3V0609,Z490V12501055,0.000358,ƽ +AVSR3R3V0609,F30VC20A055,0.000413,ƽ +AVSR3R3V0609,W19040X070,0.000053,ǧ +AVSR3R3V0609,D12073F2126b,0.0001, +AVSR3R3V0609,YG00001,9.33E-06, +AVSR3R3V0609,YHBH421H,0.00011,ǧ +AVSR3R3V0609,L063-100Y,0.0001,֧ +AVSR3R3V0609,P06-20I,0.0001,ֻ +AVSR3R3V0609,EF063C,0.000034,ǧ +ACSR4R7V0812,Z530V12001070,0.000623,ƽ +ACSR4R7V0812,F30VC20A070,0.000728,ƽ +ACSR4R7V0812,EHD450Z085,0.000094,ǧ +ACSR4R7V0812,D12087F2126,0.0001, +ACSR4R7V0812,YG00001,2.07E-05, +ACSR4R7V0812,YHBH421H,0.00019,ǧ +ACSR4R7V0812,N080-130Y,0.0001,֧ +ACSR4R7V0812,P08-30I,0.0001,ֻ +ACSR4R7V0812,GS080T,0.000072,ǧ +AMSR1R0M0609VI,Z480V12002050,0.000115,ƽ +AMSR1R0M0609VI,F30VC30A050,0.000165,ƽ +AMSR1R0M0609VI,EHD450Z065,0.000018,ǧ +AMSR1R0M0609VI,D12073TL2126b,0.0001, +AMSR1R0M0609VI,YG00002,9.33E-06, +AMSR1R0M0609VI,YHBH421H,0.00011,ǧ +AMSR1R0M0609VI,T063-100Y,0.0001,֧ +AMSR1R0M0609VI,P06-26T,0.0001,ֻ +AMSR1R0M0609VI,MS063T,0.000039,ǧ +AGTR4R7V0812V,Z510V12001070,0.000623,ƽ +AGTR4R7V0812V,F30VC20A070,0.000784,ƽ +AGTR4R7V0812V,W19020K085,0.000094,ǧ +AGTR4R7V0812V,D12087F2126,0.0001, +AGTR4R7V0812V,YG00001,2.07E-05, +AGTR4R7V0812V,YHBH421H,0.00019,ǧ +AGTR4R7V0812V,N080-130Y,0.0001,֧ +AGTR4R7V0812V,P08-30I,0.0001,ֻ +AGTR4R7V0812V,GT080C,0.000071,ǧ +WL1V477M10016,Z047V10401100,0.00153,ƽ +WL1V477M10016,F00VC40A100,0.00202,ƽ +WL1V477M10016,SM26050B120,0.00017,ǧ +WL1V477M10016,D15131G2328,0.0001, +WL1V477M10016,YG00004,0.00003, +WL1V477M10016,YHCP50A,0.00049,ǧ +WL1V477M10016,L100-175+,0.0001,֧ +WL1V477M10016,GNH-10F,0.0001,ֻ +WL1V477M10016,AW100T,0.000101,ǧ diff --git a/bom23.xlsx b/bom23.xlsx new file mode 100644 index 0000000..43a982b Binary files /dev/null and b/bom23.xlsx differ diff --git a/demand23.xlsx b/demand23.xlsx new file mode 100644 index 0000000..b661fff Binary files /dev/null and b/demand23.xlsx differ diff --git a/fake_api.py b/fake_api.py new file mode 100644 index 0000000..341cf75 --- /dev/null +++ b/fake_api.py @@ -0,0 +1,20 @@ +import pandas as pd + +df_bom = pd.read_excel('bom23.xlsx', engine='openpyxl') + +df_plan = pd.read_excel('plan.xlsx', engine='openpyxl') + + +def get_bom_by_prd_id(prd_id): + df_sub = df_bom.loc[df_bom['prd_id'] == prd_id] + return df_sub[['mtr_id', 'qty']] + + +def get_plan_by_pp_id(pp_id): + df_sub = df_plan.loc[df_plan['pp_id'] == int(pp_id)] + return df_sub[['prd_id', 'size', 'rate']] + + +if __name__ == '__main__': + print(get_bom_by_prd_id('ADTB331M0611')) + print(get_plan_by_pp_id('0')) # 0, 6, 8, 10 diff --git a/plan.xlsx b/plan.xlsx new file mode 100644 index 0000000..2b9bb7c Binary files /dev/null and b/plan.xlsx differ diff --git a/rawmaterial.xlsx b/rawmaterial.xlsx new file mode 100644 index 0000000..fd5bbd1 Binary files /dev/null and b/rawmaterial.xlsx differ