В этом руководстве описываются loadDemands
и loadLimits
, а также их взаимосвязь.
Как упоминалось в разделе Ограничения окна времени вывоза и доставки , сообщение OptimizeToursRequest
( REST , gRPC ) содержит ряд свойств, которые определяют ограничения для оптимизируемой проблемы. Несколько свойств OptimizeToursRequest
представляют ограничения нагрузки .
Транспортные средства и грузы имеют физические свойства, которые необходимо учитывать при планировании маршрута.
- Транспортные средства : свойство
loadLimits
определяет максимальную нагрузку, которую может выдержать транспортное средство. См. документацию по сообщениямVehicle
( REST , gRPC ). - Shipments : Свойство
loadDemands
определяет, сколько нагрузки потребляет данная отправка. См. документациюShipment
message ( REST , gRPC ).
В совокупности эти два ограничения позволяют оптимизатору правильно распределять грузы по транспортным средствам таким образом, чтобы они наилучшим образом соответствовали вместимости вашего автопарка и потребностям в грузоперевозках.
В оставшейся части документа подробно обсуждаются loadLimits
и loadDemands
.
Требования и ограничения по нагрузке: типы
Вы выражаете каждое требование нагрузки и ограничение предела в терминах типа .
Вы можете предоставить свой собственный набор типов нагрузки, как в следующих примерах:
- масса
- объем
- линейные измерения
- наименования перевозимых предметов или оборудования
В данном руководстве в качестве примера используется тип weightKg
.
Оба типа Shipment.loadDemands
и Vehicle.loadLimits
используют тип map
Protocol Buffers со string
ключами, представляющими типы нагрузки.
Значения Shipment.loadDemands
используют сообщение Load
( REST , gRPC ). Сообщение Load
имеет единственное свойство amount
, представляющее, сколько мощности требуется для завершения отгрузки указанного типа.
Значения Vehicle.loadLimits
используют сообщение LoadLimit
( REST , gRPC ). Сообщение LoadLimit
имеет несколько свойств, при этом maxLoad
представляет максимальную грузоподъемность транспортного средства в указанном типе.
loadDemands
отправления потребляет loadLimits
назначенного транспортного средства только в том случае, если у них есть совпадающие ключи типа нагрузки. Например, отправление с loadDemands
:
"loadDemands": {
"weightKg": {
"amount": 50
}
}
Для завершения перевозки требуется 50 единиц груза в типе weightKg
. Транспортное средство с loadLimits
:
"loadLimits": {
"weightKg": {
"maxLoad": 100
}
}
может быть в состоянии завершить отправку, так как maxLoad
транспортного средства в типе weightKg
больше или равен loadDemands
отправки в типе weightKg
. Однако, транспортное средство с loadLimits
:
"loadLimits": {
"equipmentRackStorage": {
"maxLoad": 10
}
}
неявно имеет неограниченную грузоподъемность weightKg
из-за отсутствия ограничения по весу weightKg
, поэтому транспортное средство не ограничено требуемым весом груза.
Перераспределение нагрузки между партиями и транспортными средствами
Поскольку грузы забираются и доставляются транспортными средствами, loadDemand
груза передается между грузом и транспортным средством. Вы можете увидеть загрузку транспортного средства в записи routes.transitions
сообщения OptimizeToursResponse
( REST , gRPC ) для данного транспортного средства. Последовательность выглядит следующим образом:
- Требуемая грузоподъемность определяется для отправки как
loadDemand
. - Груз забирается назначенным ему транспортным средством, и
vehicleLoads
транспортного средства увеличивается на величинуloadDemand
груза. Этот перенос представлен положительнымиvisits.loadDemands
в ответном сообщении. - Транспортное средство доставляет груз, и
vehicleLoads
транспортного средства уменьшается на величинуloadDemand
доставленного груза. Этот перенос представлен отрицательнымиvisits.loadDemands
в ответном сообщении.
vehicleLoads
транспортного средства не может превышать указанные loadLimits
ни в одной точке маршрута.
Полный пример с требованиями к нагрузке и ограничениями
Посмотрите пример запроса с требованиями к нагрузке и ограничениями
{ "populatePolylines": false, "populateTransitionPolylines": false, "model": { "globalStartTime": "2023-01-13T16:00:00Z", "globalEndTime": "2023-01-14T16:00:00Z", "shipments": [ { "deliveries": [ { "arrivalLocation": { "latitude": 37.789456, "longitude": -122.390192 }, "duration": "250s" } ], "pickups": [ { "arrivalLocation": { "latitude": 37.794465, "longitude": -122.394839 }, "duration": "150s" } ], "penaltyCost": 100.0, "loadDemands": { "weightKg": { "amount": 50 } } }, { "deliveries": [ { "arrivalLocation": { "latitude": 37.789116, "longitude": -122.395080 }, "duration": "250s" } ], "pickups": [ { "arrivalLocation": { "latitude": 37.794465, "longitude": -122.394839 }, "duration": "150s" } ], "penaltyCost": 15.0, "loadDemands": { "weightKg": { "amount": 10 } } }, { "deliveries": [ { "arrivalLocation": { "latitude": 37.795242, "longitude": -122.399347 }, "duration": "250s" } ], "pickups": [ { "arrivalLocation": { "latitude": 37.794465, "longitude": -122.394839 }, "duration": "150s" } ], "penaltyCost": 50.0, "loadDemands": { "weightKg": { "amount": 80 } } } ], "vehicles": [ { "endLocation": { "latitude": 37.794465, "longitude": -122.394839 }, "startLocation": { "latitude": 37.794465, "longitude": -122.394839 }, "costPerHour": 40.0, "costPerKilometer": 10.0, "loadLimits": { "weightKg": { "maxLoad": 100 } } } ] } }
Пример запроса содержит несколько параметров, связанных с нагрузкой:
-
shipments[0]
имеет потребность в загрузке 50weightKg
. -
shipments[1]
имеет потребность в нагрузке 10weightKg
. -
shipments[2]
имеют требуемую загрузкуweightKg
80 кг. -
vehicles[0]
имеют предельную нагрузку 100weightKg
.
Посмотрите ответ на запрос с требованиями и ограничениями по нагрузке
{ "routes": [ { "vehicleStartTime": "2023-01-13T16:00:00Z", "vehicleEndTime": "2023-01-13T16:43:27Z", "visits": [ { "isPickup": true, "startTime": "2023-01-13T16:00:00Z", "detour": "0s", "loadDemands": { "weightKg": { "amount": "50" } } }, { "shipmentIndex": 1, "isPickup": true, "startTime": "2023-01-13T16:02:30Z", "detour": "150s", "loadDemands": { "weightKg": { "amount": "10" } } }, { "startTime": "2023-01-13T16:08:55Z", "detour": "150s", "loadDemands": { "weightKg": { "amount": "-50" } } }, { "shipmentIndex": 1, "startTime": "2023-01-13T16:16:37Z", "detour": "343s", "loadDemands": { "weightKg": { "amount": "-10" } } }, { "shipmentIndex": 2, "isPickup": true, "startTime": "2023-01-13T16:27:07Z", "detour": "1627s", "loadDemands": { "weightKg": { "amount": "80" } } }, { "shipmentIndex": 2, "startTime": "2023-01-13T16:36:26Z", "detour": "0s", "loadDemands": { "weightKg": { "amount": "-80" } } } ], "transitions": [ { "travelDuration": "0s", "waitDuration": "0s", "totalDuration": "0s", "startTime": "2023-01-13T16:00:00Z", "vehicleLoads": { "weightKg": {} } }, { "travelDuration": "0s", "waitDuration": "0s", "totalDuration": "0s", "startTime": "2023-01-13T16:02:30Z", "vehicleLoads": { "weightKg": { "amount": "50" } } }, { "travelDuration": "235s", "travelDistanceMeters": 795, "waitDuration": "0s", "totalDuration": "235s", "startTime": "2023-01-13T16:05:00Z", "vehicleLoads": { "weightKg": { "amount": "60" } } }, { "travelDuration": "212s", "travelDistanceMeters": 791, "waitDuration": "0s", "totalDuration": "212s", "startTime": "2023-01-13T16:13:05Z", "vehicleLoads": { "weightKg": { "amount": "10" } } }, { "travelDuration": "380s", "travelDistanceMeters": 1190, "waitDuration": "0s", "totalDuration": "380s", "startTime": "2023-01-13T16:20:47Z", "vehicleLoads": { "weightKg": {} } }, { "travelDuration": "409s", "travelDistanceMeters": 1371, "waitDuration": "0s", "totalDuration": "409s", "startTime": "2023-01-13T16:29:37Z", "vehicleLoads": { "weightKg": { "amount": "80" } } }, { "travelDuration": "171s", "travelDistanceMeters": 665, "waitDuration": "0s", "totalDuration": "171s", "startTime": "2023-01-13T16:40:36Z", "vehicleLoads": { "weightKg": {} } } ], "metrics": { "performedShipmentCount": 3, "travelDuration": "1407s", "waitDuration": "0s", "delayDuration": "0s", "breakDuration": "0s", "visitDuration": "1200s", "totalDuration": "2607s", "travelDistanceMeters": 4812, "maxLoads": { "weightKg": { "amount": "80" } } }, "routeCosts": { "model.vehicles.cost_per_kilometer": 48.12, "model.vehicles.cost_per_hour": 28.966666666666665 }, "routeTotalCost": 77.086666666666659 } ], "metrics": { "aggregatedRouteMetrics": { "performedShipmentCount": 3, "travelDuration": "1407s", "waitDuration": "0s", "delayDuration": "0s", "breakDuration": "0s", "visitDuration": "1200s", "totalDuration": "2607s", "travelDistanceMeters": 4812, "maxLoads": { "weightKg": { "amount": "80" } } }, "usedVehicleCount": 1, "earliestVehicleStartTime": "2023-01-13T16:00:00Z", "latestVehicleEndTime": "2023-01-13T16:43:27Z", "totalCost": 77.086666666666659, "costs": { "model.vehicles.cost_per_hour": 28.966666666666665, "model.vehicles.cost_per_kilometer": 48.12 } } }
Дополнительные ограничения по нагрузке влияют на порядок visits
:
-
shipment[0]
забран -
shipment[1]
забран -
shipment[0]
доставлена -
shipment[1]
доставлен -
shipment[2]
забран -
shipment[2]
доставлен
Этот заказ отражает тот факт, что три поставки не могут быть выполнены транспортным средством одновременно, поскольку их общая loadDemands
превышает loadLimits
транспортного средства.
Каждая запись visits
включает изменение загрузки транспортного средства в результате завершения Visit
. Положительные значения загрузки представляют собой загрузку груза, а отрицательные значения представляют собой разгрузку груза.
Каждая запись transitions
включает общую загрузку транспортного средства во время Transition
. Например, transitions[2]
имеет нагрузку weightKg
60, что представляет собой объединенные загрузки shipment[0]
и shipment[1]
.
Метрики объектов routes[0].metrics
и metrics.aggregatedRouteMetrics
включают свойство maxLoads
. Значение для типа weightKg
равно 80, что представляет собой часть маршрута транспортного средства, которая перевезла shipments[2]
к месту доставки.
Мягкие ограничения по пределу нагрузки
Как и временные окна, описанные в разделе Ограничения окон времени вывоза и доставки , ограничения предела нагрузки имеют жесткие и мягкие варианты. Свойство maxLoad
сообщения LoadLimit
выражает жесткое ограничение: транспортное средство никогда не должно перевозить груз, превышающий значение maxLoad
в указанном типе. Свойства softMaxLoad
и costPerUnitAboveSoftMax
выражают мягкое ограничение, при котором каждая единица, превышающая softMaxLoad
, влечет за собой стоимость costPerUnitAboveSoftMax
.
Мягкие ограничения по пределу нагрузки имеют несколько применений, например:
- балансировка поставок по большему количеству транспортных средств, чем минимально необходимое количество, когда это экономически эффективно
- выражение предпочтений водителя относительно количества товаров, которые он может с комфортом забрать и доставить по заданному маршруту
- загрузка транспортных средств ниже их максимальной физической грузоподъемности для ограничения износа и снижения затрат на техническое обслуживание
Жесткие и мягкие ограничения по нагрузке могут использоваться вместе. Например, жесткий предел нагрузки может выражать максимальный вес груза, который транспортное средство может безопасно перевозить, или максимальное количество предметов, которые поместятся в транспортное средство за один раз, в то время как мягкий предел нагрузки может быть максимальным весом или количеством предметов, которые потребуют от водителя возможности разместить все в транспортном средстве.