SelectOutput路由导致NullPointerException - Anylogic

SelectOutput routing causing NullPointerException - Anylogic

提问人:Luca 提问时间:7/11/2023 最后编辑:Luca 更新时间:7/14/2023 访问量:65

问:

我正在用Anylogic版本8.1做一个大学项目。我们必须使用这个版本,因为大学许可证只涵盖Anylogic,直到这个版本。

在这个项目中,我们的任务是对具有 12 个订单拣选站的订单拣选系统进行建模。四个站点通过电路相互连接,从而形成三个区域。这三个区域也通过电路连接。订单在主圆的两个不同点被注入和弹出。然后,它可以移动到较小的圆圈中以访问站点。

因此,(代理)类型的 Order 的每个实例都具有以下属性:

Order

  • stations_to访问:ArrayList,它保存(代理)类型 Station 的实例,并包含订单应访问的所有订单拣选站
  • visited_stations:ArrayList,它保存(代理)类型 Station 的实例,并包含订单已访问的所有订单拣选站
  • next_station:接下来应该访问的(代理)类型 Station 的实例

一个工位最多可以处理 3 个订单:一个在延迟块上处理,两个在传送带上处理。

Station

从连接四个站点的圆圈进入一个站点。这个圆圈被命名为 SubArea:

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,看起来像这样:

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 的实例:

Main

FLowController 是进行创建、注入和next_station选择的地方。

FlowController

订单的创建过程如下:源根据时间表 (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块和默认代理:

Third try

NullPointer 仍会出现。这可能是Anylogic的错误吗?

nullpointerexception 运行时错误 anylogic

评论

1赞 Benjamin 7/11/2023
最简单的方法是剥离模型,直到错误消失。然后,重新包含,直到它出现。然后,要么你找到了你的答案,要么你回到这里并编辑你的问题,这实际上导致了这种情况(否则很难诊断):)
0赞 Luca 7/11/2023
嘿,@Benjamin,所以我听从了你的建议,把我的模型拆开了。我删除了通过系统传输的代理的整个 prio 逻辑,并且错误不断出现。后来,我还删除了selectOutput块中的拆分逻辑,并将它们切换为随机。当我这样做时,错误不再出现。我不知道为什么会这样。即使我在选择条件中添加一行代码,它也会再次抛出错误。你知道问题出在哪里吗?
0赞 Benjamin 7/12/2023
始终编辑原始问题或从头开始创建一个清晰的新问题。SOF 不像论坛那样工作,请参阅此处的提示:benjamin-schumann.com/blog/anylogic-stackoverflow
0赞 Benjamin 7/12/2023
(并赞扬更进一步,干得好:))
0赞 Luca 7/13/2023
谢谢@Benjamin - 昨天我试图重建模型。错误再次发生。现在我要写一篇新文章,希望能更好地解释我的问题。完成后,我将在这里发布一个链接。

答:

0赞 Luca 7/14/2023 #1

我终于找到了解决方案。

似乎 anylogic 无法在一个传送带上处理许多代理/订单。例如,当输送机的长度为 1.5 米时,最多可能需要两个代理,这有点令人困惑并导致 NullPointer。

所以我把每个传送带都包裹在一个限制区域,它的工作:)