AnyLogic
Развернуть
Размер шрифта

Шаг 4. Моделирование заказа товара

Мы закончили разрабатывать структуру модели: добавили дистрибьютора, ритейлеров и грузовики. Давайте приступим к заданию логики модели.

Пусть ритейлеры периодически заказывают товары, отправляя заказы дистрибьютору.

Подобный подход подразумевает, что мы создадим новый тип агента — заказ.

Создайте новый тип агента — заказ

  1. Перетащите элемент Агент из палитры Агент на диаграмму Main. В окне мастера Создание агента укажите, что хотите Просто создать тип агента.
    В этот раз мы воспользуемся этой опцией мастера, поскольку изначально в нашей модели не будет агентов этого типа, и нам нет необходимости создавать популяцию агентов. Агенты-заказы будут создаваться ритейлерами динамически в процессе моделирования, так что сейчас мы просто создадим тип агента, в котором зададим структуру данных этого агента. Экземпляры данного типа (заказы) будут создаваться уже во время выполнения модели.
  2. Введите Имя нового типа: ProductOrder. Щелкните по кнопке Далее.
  3. Чаще всего мы создаем агентов, у которых есть какое-то визуальное представление, для чего мы выбираем фигуру анимации агента. Но в данном случае создавать анимацию для заказов смысла нет, поэтому просто выберите у опции Выберите анимацию агента пункт Нет. Щелкните по кнопке Далее.
  4. На этот раз мы воспользуемся мастером Создание агента, чтобы задать параметры для агента. Слева вы видите секцию Параметры. Щелкните по кнопке < добавить ... >, чтобы задать параметр. Свойства параметра появятся в правой части мастера.
    Задайте имя нового параметра в поле Параметр: amount. Затем укажите Тип: int (целое число). Этот параметр будет хранить число единиц товара, заказанных ритейлером у дистрибьютора.

  5. Добавьте еще один параметр: щелкните по кнопке < добавить ... > в секции Параметры. На этот раз мы создадим параметр, в котором будем указывать, какой именно ритейлер осуществил заказ. Зададим для него имя - retailer - и тип: Retailer. Поскольку мы специально создали этот тип агента для нашей модели, для его использования в качестве типа параметра нужно сначала выбрать Тип: <Другой...>, а затем - Retailer в появившемся справа выпадающем списке.

  6. Щелкните по кнопке Готово. Откроется диаграмма агента ProductOrder, и мы увидим заданные нами в мастере элементы.

Ритейлеры отправляют заказ не единожды, а с определенной периодичностью. Чтобы задать расписание для повторяющихся действий в модели, мы воспользуемся элементом Событие.

Создайте событие для генерации заказов

  1. Дважды щелкните по типу агента Retailer в панели Проекты, чтобы открыть диаграмму этого типа.
  2. Перетащите элемент Событие из палитры Агент на диаграмму Retailer. Назовите это событие requestDelivery.
  3. Мы хотим, чтобы ритейлеры заказывали товар стохастически с определенной периодичностью. Давайте изменим Тип события: с По таймауту на С заданной интенсивностью. Предположим, что ритейлеры в среднем оформляют один заказ в день: измените значение поля Интенсивность на 1 в день.
  4. Мы задали, когда должно срабатывать событие, — давайте теперь сообщим AnyLogic, какое действие должно выполняться после срабатывания. Разверните секцию свойств Действие. В этой секции находится поле, в которое можно ввести вызываемый код. Введите Java код, приведенный ниже:
    ProductOrder order = new ProductOrder(uniform_discr(10,20), this);
    Vehicle truck = getNearestAgentByRoute(filter(main.vehicles, v -> v.inState(Vehicle.AtDistributor)));
    send (order, truck);

    Рассмотрим, как работает этот код. Сначала мы создаем заказ, вызывая конструктор типа агента ProductOrder. Затем мы используем ранее созданные нами для ProductOrder параметры, чтобы сохранить данные этого заказа. Обратите внимание, что мы передаем значения параметров в том же порядке, в котором задавали их: сначала количество (число заказанных единиц) товара, а затем — ссылку на ритейлера, оформившего заказ. Мы обращаемся к ритейлеру с помощью ключевого слова языка Java: this. Оно возвращает ссылку на агента, внутри которого мы используем этот код. Поскольку мы задаем действие для события, находящегося на диаграмме Retailer, this будет возвращать конкретного ритейлера.

    С помощью второго выражения производится поиск ближайшего грузовика. Функция getNearestAgentByRoute(population) возвращает ближайшего агента из популяции population. Мы не рассматриваем всю популяцию, а осуществляем предварительную фильтрацию с помощью функции filter(): таким образом, поиск производится по части популяции, включающей только бездействующие грузовики.

    Первый аргумент функции filter() передает популяцию агентов — в нашем случае main.vehicles. Затем задается имя для проверяемого в данный момент агента этой популяции (v ->). После этого условие для фильтрации передается в следующем формате: v.<условие>. Функция вернет часть популяции, состоящую из агентов, которые отвечают заданному условию.

    Функция inState(state) проверяет, находится ли агент в текущий момент в указанном состоянии state. Таким образом, мы фильтруем результаты и включаем в выборку только бездействующие грузовики (находящиеся у центра дистрибуции).

    Последнее выражение отправляет созданный заказ грузовику, выбранному для его исполнения. Первый аргумент функции send() — это само отсылаемое функцией сообщение, а второй — это адресат сообщения (грузовик).

Еще одна вещь, которую мы хотим учесть в нашей модели: каждый агент Vehicle должен содержать информацию о своем текущем заказе.

Предоставьте доступ к заказам

  1. Откройте диаграмму типа агента Vehicle в панели Проекты.
  2. Перетащите элемент Переменная из палитры Агент на диаграмму агента Vehicle. Назовите переменную order.
  3. Укажите Тип переменной: ProductOrder. С помощью этой переменной мы получим доступ к текущему заказу грузовика.

Теперь зададим поведение грузовика после получения сообщения о заказе.

Измените диаграмму состояний грузовика

  1. Дважды щелкните по типу агента Vehicle в панели Проекты, чтобы открыть диаграмму этого типа.
  2. Пока что грузовик начинает путь к ритейлеру в соответствии с заданным типом срабатывания, переходя из состояния AtDistributor в состояние MovingToRetailer. Переход срабатывает с заданной интенсивностью: раз в день. Мы хотим изменить эту логику: грузовик должен начинать движение, получив сообщение о заказе.

  3. Установите значение опции Происходит: При получении сообщения.
  4. Укажите Тип сообщения: ProductOrder. Таким образом мы сообщаем AnyLogic, что только сообщения типа ProductOrder вызовут срабатывание этого перехода.
  5. Измените значение поля Действие. Теперь грузовик будет отправляться не к случайному ритейлеру, а к ритейлеру, оформившему полученный именно этим грузовиком заказ. Для этого мы используем в Java коде переменную msg — она ссылается на полученное сообщение. msg — это локальная переменная, которая доступна только в определенном контексте. Чтобы просмотреть список локальных переменных, щелкните в поле и затем наведите курсор мыши на иконку лампочки, которая появится слева от поля.
    Вторая строчка нужна, чтобы сохранить сведения о заказе в переменной order этого грузовика.

Мы задали логику отправки и получения сообщений — теперь запустим модель и посмотрим, как она работает.

Вы увидите, что грузовики перемещаются по карте и выполняют полученные заказы. Тем не менее, через некоторое время появится ошибка, показанная на изображении ниже:

Согласно тексту ошибки, агент назначения — это "null". null — это ключевое слово языка Java. Оно означает, что объекта, к которому пытается обратиться код, не существует. В нашем случае из этого следует, что мы дошли до момента, когда все грузовики отправились выполнять заказы, поэтому второе выражение, заданное в действии события requestDelivery, вернуло null в качестве результата и присвоило это значение переменной truck. Это значение было использовано функцией send() в качестве адресата сообщения, поэтому AnyLogic не удалось назначить исполнителя на заказ: все грузовики были заняты, поэтому мы получили сообщение об ошибке.

Исправим ошибку, изменив действие события.

Измените действие события

  1. Выберите событие requestDelivery и в свойствах этого события раскройте секцию Действие.
  2. Внесите изменения в код в поле Действие так, как показано на изображении ниже.

Теперь перед отправкой сообщения мы будем проверять, есть ли в наличии бездействующий грузовик, — и только если есть, сообщение с заказом будет отправлено этому грузовику.

Запустите модель еще раз. Вы увидите, что грузовики успешно справляются с доставкой товара, и новых сообщений об ошибках не появляется.

Демо-модель: Supply Chain GIS - Phase 4 Открыть страницу модели в AnyLogic Cloud. Там можно запустить модель или скачать ее по ссылке Исходные файлы модели.
Как мы можем улучшить эту статью?