Файл: Разработка имитационных моделей управления запасами в цепях поставок Москва 2011 2 Введение.pdf
ВУЗ: Не указан
Категория: Не указан
Дисциплина: Не указана
Добавлен: 04.12.2023
Просмотров: 88
Скачиваний: 1
ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.
68
Меняем тип и значения по умолчанию для данных переменных: retStock – массив уровня запасов розничных точек. Тип: int[]
Массив инициализируется строкой new int[]
{0,0,0,0,0,0,0,0}
. Каждый элемент приравнивается нулю. Нумерация элементов начинается от нуля. Индекс первого элемента 0, восьмого 7. demandMean, demandStd – массивы параметров нормального распределения спроса в розничных точках. Оба массива типа int[].
Начальное значение demandMean: new int[]{80,90,30,57,73,91,120,91}
Начальное значение demandStd: new int[]{18,20,30,12,25,17,34,25} retShortage – массив учета случаев дефицита для каждой из розничных точек. Тип массива int[].
Начальное значение: new int[]{0,0,0,0,0,0,0,0}
69 retailCoordx и retailCoordy – массивы координат x и y розничных точек (координаты взяты из постановки задачи)
Начальное значение retailCoordx: new int[]{10,100,40,60,90,30,50,80}
Начальное значение retailCoordy: new int[]{10,50,30,60,100,80,90,60}
Изменим код Действия при запуске класса Main:
Добавим код, генерирующий и размещающий на карте розничные точки и генерирующий транспортные средства: for (int i = 0; i < 8; i++) {
Retailer a = add_retailer(); a.setXY(4*retailCoordx[i],4*retailCoordy[i]); a.retDist= sqrt(pow(retailCoordx[i]-distrCoordx,2)+ pow(retailCoordy[i]-distrCoordy,2) ); retStock[i] = retEOQ[i]+retROP[i];
Truck d = add_truck(); d.setXY(4*distrCoordx,4*distrCoordy); d.rectangle.setVisible(false);
}
70
В модели восемь розничных точек, поэтому инициализацию нужно выполнить для каждой из них. Для этого используем циклическая конструкция For. Границы цикла обозначены фигурными скобками.
Переменная i – счетчик цикла. Каждую итерацию она увеличивается на единицу, начальное значение 0, конечное значение 7. Более подробная информация об использовании циклических конструкций в Java в материале
«Java for Anylogic Users»[1,p37]. retailCoordx[i] – выбирает элемент массива с индексом i.
Переменные уровня запасов и параметров управления запасами розничных точек также представлены в виде массивов.
Далее в модель добавляется восемь транспортных средств, объектов класса Truck. Анимация модели будет организована таким образом, что транспортные средства видны лишь в процессе движения от дистрибьютора к розничной точке. Поэтому при запуске модели координаты должны соответствовать координатам дистрибьютора, но не быть видны в окне презентации.
Метод d.rectangle.setVisible(false); делает объекты невидимыми на презентации.
Код Действия при запуске класса Main:
Distributor b = add_distributor(); b.setXY(4*distrCoordx,4*distrCoordy); for (int i = 0; i < 8; i++) {
Retailer a = add_retailer(); a.setXY(4*retailCoordx[i],4*retailCoordy[i]); a.retDist= sqrt(pow(retailCoordx[i]-distrCoordx,2)+ pow(retailCoordy[i]-distrCoordy,2) ); retStock[i] = retEOQ[i]+retROP[i];
Truck d = add_truck(); d.setXY(4*distrCoordx,4*distrCoordy); d.rectangle.setVisible(false);
}
71
Изменение алгоритма управления запасами
Модифицируем диаграмму действий actionChart. В новой версии модели все действия выполняются для каждой из восьми розничных точек.
Добавляем цикл For:
Меняем параметры цикла:
Тип: итератор по коллекции, элемент: Retailer ret, коллекция: retailer
. Данный цикл перебирает все элементы коллекции retailer, которые мы создали в классе Main (всего восемь элементов). При этом
«счетчиком цикла» будет выступать переменная ret. Переменная ret служит ссылкой на объект, по аналогии с использованием переменных a, b в
Действии при запуске класса Main. В классе Main они использовались для инициализации, здесь – для удобства обработки. Перебор осуществляется, пока не закончатся элементы коллекции. В нашем случае у цикла будет восемь итераций. Более подробно о коллекциях в “Java for AnyLogic Users”
[1,p21]
Остальной код диаграммы действий нужно переместить внутрь цикла:
72
Для этого вырезаем (Ctrl+X) элемент «Спрос превышает запас ритейлера?» выделяем диаграмму цикла и вставляем (Ctrl+V) его около выделенной цветом области цикла, когда подсвечивается зеленая точка в конструкции цикла:
Результат:
73
Элемент окончания работы диаграммы действий должен быть в единственном экземпляре и за пределами цикла:
Добавим элемент Локальная переменная. Данная переменная будет соответствовать индексу элемента коллекции розничных точек:
Изменяем параметры локальной переменной:
74
Добавим элемент Код сразу после локальной переменной:
Меняем свойства элемента Код. Комментарий: Обновление retHoldingcost и генерация спроса, код: retHoldingcost+=ret.retholdingrate*retStock[j]; ret.currentDemand = round( max
(normal(demandStd[j],demandMean[j]),0));
Код остальных модулей диаграммы действий изменяем с учетом работы с коллекцией агентов типа «розничная точка» (Retailer):
Модуль: Спрос превышает запас ритейлера?
75
Код:
ret.currentDemand > retStock[j]
Модуль: Обновление дефицита
Код: retShortage[j]++;
Модуль: Нет заказа в пути?
Код: truck.get(j).isMoving() == false
Модуль: Обработка заказа дистрибьютором
Код:
create_RetReplenishment(ret.retDist/10,ret.retDist/10,j
); truck.get(j).rectangle.setVisible(true); truck.get(j).moveTo(ret.getX(),ret.getY());
Модуль: обновление уровня запаса ритейлера
Код: retStock[j]-= ret.currentDemand;
Модуль: Заказ ритейлера меньше запаса распр. центра и нет заказа в пути?
Код: retStock[j] < retROP[j] && truck.get(j).isMoving() == false
Модификация событий
В событии ordering оставляем только две строки: totalCost=retHoldingcost+retTrcost; actionChart();
76
Добавим параметр index (index соответствует индексу розничной точки – переменной j) в динамическое событие RetReplenishment: retStock[index]+=retEOQ[index]; truck.get(index).jumpTo(distributor.get(0).getX(),distr ibutor.get(0).getY()); truck.get(index).rectangle.setVisible(false); retTrcost+=time*retailer.get(index).rettrrate;
Добавление элементов презентации
Поменяем параметры Временного графика:
77
Добавим линию на окно редактирования класса Main:
Поменяем динамические свойства линии line:
Количество: 8. Данный массив линий будет использоваться для маршрутов «дистрибьютор – розничная точка». Чтобы линии автоматически перерисовывались при изменении конфигурации сети, изменим параметры расположения линий в пространстве: index – индекс линии (от 0 до 7)
78
Начальная точка каждой из линий – это координата розничной точки.
Для получения координат используются методы getX() и getY().
X: retailer.get(index).getX()
Y: retailer.get(index).getY()
Параметры dX и dY определяют смещение конечной точки прямой по отношению к начальной. В нашем случае это разность между координатами дистрибьютора и розничной точки:
dX: distributor.get(0).getX() - retailer.get(index).getX()
dY: distributor.get(0).getY()- retailer.get(index).getY()
Отображение уровня запаса в текстовом поле
Добавим на презентацию модели переменные уровня запаса элементов сети. Для этого создадим элемент Текст:
Переименуем текст в textRet. Текст должен отображать текущий уровень запаса розничной точки и быть расположен рядом с розничной точкой на карте презентации. Для этого снова воспользуемся динамическими параметрами:
79
Количество текстовых полей соответствует количеству розничных точек в модели.
X: retailer.get(index).getX()+5
Y: retailer.get(index).getY()
Текст: retStock[index]
Координаты X и Y подобраны так, что текст будет располагаться немного правее (на 5 единиц) пиктограммы презентации розничной точки.
Текстовое поле показывает текущий уровень запаса розничной точки retStock[].
Модифицируем текст, отображающий количество случаев возникновения дефицита. На его основе будут создаваться восемь текстовых полей, показывающих количество случаев возникновения дефицита в каждой из розничных точек:
80
Количество: 8
X: 500
Y: 10+15*index
Текст: "Не выполненные в срок заказы,"+" Ритейлер №
"+(1+index)+ ": "+retShortage[index]
Координата Y задана таким образом, что строки будут располагаться вертикальным списком с отступом 15 единиц.
Строка в поле текст состоит из нескольких элементов. Текст в кавычках будет отображаться как статическое текстовое поле, знак «+» объединяет части строки[1,p20]. Номер розничной точки на единицу больше индекса розничной точки, так как индекс начинает нумерацию с нуля. retShortage[index] выводит значение переменной, обозначающей уровень дефицита у данной розничной точки.
Запустим модель:
81
На презентации отображаются запасы розничных точек, каждому маршруту соответствует линия, отображаются данные уровня издержек, количество случаев дефицита.
Запись данных о ежедневном уровне запасов в текстовый файл
Данные будут записываться в файл каждый день, поэтому отредактируем элемент «Обновление retHoldingcost и генерация спроса» диаграммы действий actionChart – добавим код для записи данных об уровне запасов в файл. В файле должно быть восемь столбцов (по количеству розничных точек) и тысяча строк (по количеству дней работы модели). Для записи используем методы print() – запись в строку и println() – начало новой строки.
82 filestock.print(" "+retStock[j]); if(j==7){ filestock.println(" ");
}
В текстовый файл добавляются пробел “ “ и величина текущего заказа розничной точки ret.retStock. Знак «+» используется для объединения двух частей выражения.
Если выбран последний элемент коллекции с индексом 7, то начинается запись новой строки (в java нумерация элементов начинается с нуля).
Запустим модель и откроем текстовый файл, в который были записаны данные во время работы симуляции:
83
Для того чтобы можно было открыть файл в Excel с нужным форматированием выбираем в Excel следующие параметры:
Получаем следующую форму представления данных:
84
По аналогии с уровнем запасов розничной точки можно записывать в текстовые файлы и другие важные параметры работы модели для последующего более детального анализа полученных данных.
Оптимизационный эксперимент
Ограничения
Модифицируем оптимизационный эксперимент. По условию ни в одной из розничных точек недопустимо количество дефицита более 15 случаев. Для того чтобы контролировать данное условие, добавим дополнительные переменные и код.
Переменная shortageLevel соответствует допустимому уровню дефицита. Значение по умолчанию: 15. Переменная restriction равна нулю, если допустимый уровень дефицита не превышен, и единице в обратном случае. Обе переменные типа int и размещены в классе Main.
Добавим код проверки превышения допустимого уровня дефицита в диаграмму действий:
85
Модуль: Обновление retHoldingcost и генерация спроса.
Добавляем код: if (retShortage[j]>shortageLevel){ restriction = 1;
}
Вернемся к редактированию оптимизационного эксперимента:
86
В новой версии 16 изменяемых параметров модели.
Настройки ограничений:
Заново создаем интерфейс:
Переместим элементы презентации оптимизационного эксперимента:
87
Поиск решения
88
Как мы видим, после определенного момента целевая функция
(выделена синим цветом на графике) практически не улучшает значение.
Задания:
1)Рассчитайте аналитически при помощи метода «центра тяжести» оптимальные координаты размещения дистрибьютора. Измените координаты distrCoordx и distrCoordy на полученные значения и проведите оптимизационный эксперимент. Сравните издержки новой конфигурации системы.
89 2)Доработайте модель таким образом, чтобы собирались данные по издержкам каждой розничной точки на хранение и транспортировку.
2.3 Расширенная модель цепи поставок
Описание задачи
Добавим в цепь поставок еще один уровень – поставщика. Ставка содержания запаса дистрибьютора: 1 единица за хранение единицы товара в течение периода, ставка на транспортировку: 20000 единиц за 10 единиц пройденного расстояния. Система управления запасами дистрибьютора реализована по аналогии с розничными точками: оптимальный размер заказа
EOQ и пороговый уровень запаса ROP. Координаты поставщика: (60;120)
90
В модели восемь розничных точек, один дистрибьютор и один поставщик. Получаем восемнадцать изменяемых переменных, отвечающих за параметры управления запасами
(запасы поставщика приняты неограниченными). Две дополнительные переменные определяют координаты расположения дистрибьютора.
Таким образом, в модели двадцать изменяемых переменных. Дополнительные сложности связаны с вероятностной структурой спроса и ограничениями по допустимому уровню сервиса.[7]
Задачи:
1.смоделировать и отразить на презентации работу расширенной цепи поставок;
2.найти оптимальные значения параметров управления запасами и оптимальные координаты размещения дистрибьютора.
Добавление класса поставщика
Создадим переменные координат поставщика в классе Main:
Тип обеих переменных: int, значение по умолчанию supplyCoordx:
60, supplyCoordy: 120.
По аналогии с агентом Distributor (во второй части практикума) добавим новый класс агентов Supplier. Цвет заливки для прямоугольника презентации Supplier – red, ширина и высота 7. Не забываем указать среду и выбрать реплицированный тип агента.
Добавим параметры класса Distributor: