提问人:Luca 提问时间:7/11/2023 最后编辑:Luca 更新时间:7/14/2023 访问量:65
SelectOutput路由导致NullPointerException - Anylogic
SelectOutput routing causing NullPointerException - Anylogic
问:
我正在用Anylogic版本8.1做一个大学项目。我们必须使用这个版本,因为大学许可证只涵盖Anylogic,直到这个版本。
在这个项目中,我们的任务是对具有 12 个订单拣选站的订单拣选系统进行建模。四个站点通过电路相互连接,从而形成三个区域。这三个区域也通过电路连接。订单在主圆的两个不同点被注入和弹出。然后,它可以移动到较小的圆圈中以访问站点。
因此,(代理)类型的 Order 的每个实例都具有以下属性:
- stations_to访问:ArrayList,它保存(代理)类型 Station 的实例,并包含订单应访问的所有订单拣选站
- visited_stations:ArrayList,它保存(代理)类型 Station 的实例,并包含订单已访问的所有订单拣选站
- next_station:接下来应该访问的(代理)类型 Station 的实例
一个工位最多可以处理 3 个订单:一个在延迟块上处理,两个在传送带上处理。
从连接四个站点的圆圈进入一个站点。这个圆圈被命名为 SubArea:
该子区域也有可以接受的订单限制。订单由 selectOutput 块引导:前四个调用 select_output_branch 函数,最后一个调用 select_output_exit 函数。
- select_output_branch:检查next_station的订单是否是下面的工位,以及该工位的容量是否剩余。如果是这种情况,它会将订单路由到下面的站点。
if(!order.stations_to_visit.isEmpty() && order.next_station == station && station.number_of_orders < station.max_number_of_orders) {
return false;
} else {
return true;
}
- select_output_exit:检查订单中的next_station是否位于不同的子区域,或者订单是否访问了所有站点。如果是这种情况,它会将订单路由到连接所有三个子区域的大圆圈。
if(order.stations_to_visit.isEmpty() || order.next_station.subArea != sub_area) {
return true;
} else {
return false;
}
这个大圆圈叫做 Area,看起来像这样:
与 SubArea 一样,订单由 selectOutput 块路由。前三个再次使用 select_output_branch 函数,最后一个使用 select_output_exit 函数。
- select_output_branch:检查订单的next_station是否包含在子区域中,以及子区域中的产能是否剩余。如果是这种情况,它会将订单路由到下面的子区域。
if(!order.stations_to_visit.isEmpty() && order.next_station.subArea == sub_area && order.next_station.subArea.number_of_orders < order.next_station.subArea.max_number_of_orders) {
return false;
} else {
return true;
}
- select_output_exit:检查订单是否访问了所有站点。如果是这种情况,它会将订单路由到出口。
if(order.stations_to_visit.isEmpty()) {
return true;
} else {
return false;
}
在每个进入和延迟块中,强制推送被禁用。
Main 包括 Area agent 的实例和 Flow Controller 的实例:
FLowController 是进行创建、注入和next_station选择的地方。
订单的创建过程如下:源根据时间表 (order_load) 在离散时间点(例如 10:00)创建指定数量的订单。这些被添加到默认填充中,并调用 onExit generate_new_stations_to_visit函数。此函数采用所有站点的随机数量,并将它们设置为按顺序stations_to_visit,并将下一个站点的订单设置为stations_to_visit的第一个元素。 在那之后,订单在那一刻退出,它移动到人口orders_to_inject。
该区域的订单注入是通过injection_event进行的。这将调用 inject_order 函数。
// Check if there is a order to inject available && if area has capacities left
if(!orders_to_inject.isEmpty() && injected_orders.size() < max_injected_orders) {
// Select order to inject
Order order_to_inject = orders_to_inject.random();
// Move to injected orders
order_to_inject.goToPopulation(injected_orders);
// Select first station to visit
select_next_station_to_visit(order_to_inject);
// Inject to area entry
main.area.enter_flow_controller.take(order_to_inject);
}
函数visited_station由站中的延迟块调用:
// Check if the correct station was visited
if(order.next_station == station) {
// Move station to visited stations
order.visited_stations.add(station);
order.stations_to_visit.remove(station);
// Select next station
select_next_station_to_visit(order);
} else {
System.out.println("Visited wrong station");
}
访问selcet_next_station执行以下操作:
// If any stations to visit are left
if(!order.stations_to_visit.isEmpty()) {
// Set next station
order.next_station = order.stations_to_visit.get(0);
}
订单离开该区域后,它将移动到已完成订单的人口。
到目前为止,模型就是这样:
在运行时,会发生 NullPointerException:
Exception during discrete event execution:
NullPointerException
at com.anylogic.libraries.processmodeling.Conveyor.e(Unknown Source)
at com.anylogic.libraries.processmodeling.Conveyor.b(Unknown Source)
at com.anylogic.libraries.processmodeling.Conveyor$5.onExit(Unknown Source)
at com.anylogic.libraries.processmodeling.Delay.d(Unknown Source)
at com.anylogic.libraries.processmodeling.Delay.b(Unknown Source)
at com.anylogic.libraries.processmodeling.Delay$6.onExit(Unknown Source)
at com.anylogic.libraries.processmodeling.OutputBuffer.e(Unknown Source)
at com.anylogic.libraries.processmodeling.OutputBuffer.c(Unknown Source)
at com.anylogic.libraries.processmodeling.OutputBuffer$1.onExit(Unknown Source)
at com.anylogic.libraries.processmodeling.OutputBlock.d(Unknown Source)
at com.anylogic.libraries.processmodeling.OutputBlock.a(Unknown Source)
at com.anylogic.libraries.processmodeling.OutputBlock$1.a(Unknown Source)
at com.anylogic.libraries.processmodeling.OutPort.a(Unknown Source)
at com.anylogic.libraries.processmodeling.InPort.receiveImmediately(Unknown Source)
at com.anylogic.libraries.processmodeling.InputBlock$1.a(Unknown Source)
at com.anylogic.libraries.processmodeling.OutPort.a(Unknown Source)
at com.anylogic.libraries.processmodeling.OutPort.c(Unknown Source)
at com.anylogic.libraries.processmodeling.OutPort.b(Unknown Source)
at com.anylogic.libraries.processmodeling.OutputBlock.c(Unknown Source)
at com.anylogic.libraries.processmodeling.OutputBlock.a(Unknown Source)
at com.anylogic.libraries.processmodeling.OutputBlock$2.a(Unknown Source)
at com.anylogic.libraries.processmodeling.OutputBlock$2.action(Unknown Source)
at com.anylogic.libraries.processmodeling.AsynchronousExecutor_xjal.executeActionOf(Unknown Source)
at com.anylogic.engine.EventTimeout.execute(Unknown Source)
at com.anylogic.engine.Engine.d(Unknown Source)
at com.anylogic.engine.Engine.nd(Unknown Source)
at com.anylogic.engine.Engine.f(Unknown Source)
at com.anylogic.engine.Engine$e.run(Unknown Source)
以下是我到目前为止为解决这个问题所做的工作:
- 显示订单从传送带的每次退出、延迟、进入和退出块:No Order is null
- 调查了错误发生的位置:我怀疑在区域代理实例中的输入块。这是因为区域的number_of_agents计数器在每个子区域的出口处都会增加,并且当发生错误时,计数器的值与输送机包含的值不同
- 剥离了原始模型,该模型具有用于喷射和工位选择的prios
- 重新生成模型
无论如何,所有这些都将问题缩小到:当我从选择输出块中删除路由逻辑时,问题不会发生。当我把它放回去时,错误再次发生。
编辑:当我仅从子区域中删除路由逻辑(select_ouput_branch 和 select_output_exit)并将其更改为 random(0.5) 时,不会发生错误。
感谢您的时间和精力。如果有人能帮忙,我很高兴。
编辑:我构建了第三个模型,根本没有逻辑,只有anylogic块和默认代理:
NullPointer 仍会出现。这可能是Anylogic的错误吗?
答:
我终于找到了解决方案。
似乎 anylogic 无法在一个传送带上处理许多代理/订单。例如,当输送机的长度为 1.5 米时,最多可能需要两个代理,这有点令人困惑并导致 NullPointer。
所以我把每个传送带都包裹在一个限制区域,它的工作:)
评论