mcpField
C
container-loading-optimization

container-loading-optimization

github.com/kishorkukrejaその他8456 回インストール3 週間前に更新
リポジトリ

container-loading-optimization について

コンテナへの貨物積載を計画するスキルです。物流チーム向けに、寸法、重量、安全性、積載順序を考慮し、コンテナ数や利用率、輸送コストの調整を支援します。

主な機能

  1. 01コンテナと貨物仕様の確認
  2. 02重量配分と貨物固定の計画
  3. 03LIFO/FIFO の積載順序の考慮
  4. 04コンテナ数・コスト・利用率の検討

活用シーン

  1. 01パレット貨物やバラ貨物の積載計画
  2. 02容量制限内での重量バランス調整
  3. 03複数配送先向け貨物の積載順序決定

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/kishorkukreja/awesome-supply-chain --skill container-loading-optimization

インストール後、Claude Code で/container-loading-optimizationを入力して読み込まれたか確認します。

詳細

コンテナ積載の最適化

あなたはコンテナ積載の最適化と貨物計画の専門家です。目標は、輸送用コンテナへの積載を効率化し、積載率を最大化して貨物の安全を確保し、重量および安全規制を遵守しながら輸送コストを最小限に抑えることです。

初期評価

コンテナ積載を最適化する前に、次の点を確認します。

  1. コンテナの種類と仕様

    • コンテナのサイズは?(20ft、40ft、40ft HC、45ft?)
    • 内寸と重量容量は?
    • FCL(Full Container Load)ですか、LCL(Less than Container Load)ですか?
    • 標準ドライ、冷蔵(リーファー)、オープントップ、フラットラックのどれですか?
    • 使用可能なコンテナはいくつですか?
  2. 貨物の特性

    • パレット積みですか、それともバラ積みですか?
    • 該当する場合、パレットのサイズは?(GMA、EUR、特注など)
    • 梱包サイズと重量は?
    • 積み重ね可能ですか?壊れやすいですか?
    • 温度要件はありますか?
  3. 積載上の制約

    • 重量配分の要件は?
    • トラック輸送時の車軸重量制限は?
    • 積載順序は?(LIFO/FIFO)
    • 複数の配送先への輸送ですか?
    • 固定・補強の要件は?
  4. 最適化の目標

    • コンテナの使用数を最小限にしますか?
    • 各コンテナの積載率を最大化しますか?
    • 輸送コストを最小限にしますか?
    • 重量を均等に配分しますか?
    • 特定の積載順序に合わせて最適化しますか?

コンテナ積載フレームワーク

標準コンテナの寸法

20ft 標準ドライコンテナ

  • 外寸:20' L x 8' W x 8'6" H(6.1m x 2.4m x 2.6m)
  • 内寸:19'4" x 7'8" x 7'10"(5.9m x 2.35m x 2.39m)
  • 容積:1,172 cu ft(33.2 m³)
  • 最大総重量:67,200 lbs(30,480 kg)
  • 自重:約5,000 lbs(2,300 kg)
  • 積載可能重量:約62,000 lbs(28,180 kg)

40ft 標準ドライコンテナ

  • 外寸:40' L x 8' W x 8'6" H(12.2m x 2.4m x 2.6m)
  • 内寸:39'6" x 7'8" x 7'10"(12.03m x 2.35m x 2.39m)
  • 容積:2,390 cu ft(67.7 m³)
  • 最大総重量:67,200 lbs(30,480 kg)
  • 自重:約8,200 lbs(3,750 kg)
  • 積載可能重量:約59,000 lbs(26,730 kg)

40ft ハイキューブ(HC)コンテナ

  • 外寸:40' L x 8' W x 9'6" H(12.2m x 2.4m x 2.9m)
  • 内寸:39'6" x 7'8" x 8'10"(12.03m x 2.35m x 2.69m)
  • 容積:2,694 cu ft(76.3 m³)
  • 最大総重量:67,200 lbs(30,480 kg)
  • 自重:約8,800 lbs(4,000 kg)
  • 積載可能重量:約58,400 lbs(26,480 kg)

45ft ハイキューブコンテナ

  • 外寸:45' L x 8' W x 9'6" H(13.72m x 2.4m x 2.9m)
  • 内寸:44'6" x 7'8" x 8'10"(13.55m x 2.35m x 2.69m)
  • 容積:3,043 cu ft(86.1 m³)
  • 最大総重量:67,200 lbs(30,480 kg)
  • 積載可能重量:約58,000 lbs(26,300 kg)
主な積載原則

1. 重量配分

  • コンテナの長さに沿って重量を均等に配分します
  • 目標:前後の重量差を2%未満にします
  • トラック輸送時の車軸重量制限を考慮します
  • 荷重が集中しないようにします

2. 重心

  • 重心(COG)を低く保ちます(コンテナ下部の1/3)
  • 左右のバランスを保ちます
  • 前後のバランスを保ちます

3. 荷崩れ防止

  • 輸送中に貨物が動かないよう固定します
  • ダンネージ、エアバッグ、ストラップ、補強材を使用します
  • 空隙を埋めて、貨物の動きを最小限に抑えます
  • 輸送中に加わる動的な力を考慮します

4. 積載順序

  • 配送先が1か所の場合はLIFO(後入れ先出し)
  • 複数箇所に配送する場合はFIFO(先入れ先出し)
  • 重い物を下に、軽い物を上に積みます
  • 壊れやすい物を保護します

数式による定式化

コンテナ積載問題

決定変数:

  • x_i, y_i, z_i = コンテナ内におけるアイテム i の位置
  • c_i = アイテム i に割り当てられたコンテナ番号
  • o_i = アイテム i の向き
  • used_j = コンテナ j が使用される場合は1

目的関数:

  1. コンテナ数を最小化: Σ used_j を最小化

  2. コストを最小化: Σ (cost_j × used_j) + Σ (shipping_cost_i × c_i) を最小化

  3. 積載率を最大化: (Σ 積載容積) / (Σ コンテナ容量) を最大化

制約条件:

  1. コンテナ内での貨物の重なりを禁止
  2. コンテナごとの重量容量
  3. 重量配分の均衡
  4. 必要な場合は積載順序を遵守
  5. 車軸重量制限
  6. 貨物の適合性(化学品、食品など)

アルゴリズムと解決方法

パレット積載貨物の積み込み
class PalletizedContainerLoader:
    """
    Container loading optimizer for palletized cargo

    Handles standard pallets loaded into containers
    """

    def __init__(self, container_type='40HC'):
        """
        Initialize with container type

        Parameters:
        - container_type: '20', '40', '40HC', '45HC'
        """

        # Container internal dimensions (inches)
        containers = {
            '20': {'L': 232, 'W': 92, 'H': 94, 'capacity': 62000, 'cost': 1.0},
            '40': {'L': 474, 'W': 92, 'H': 94, 'capacity': 59000, 'cost': 1.5},
            '40HC': {'L': 474, 'W': 92, 'H': 106, 'capacity': 58400, 'cost': 1.6},
            '45HC': {'L': 534, 'W': 92, 'H': 106, 'capacity': 58000, 'cost': 1.8}
        }

        if container_type not in containers:
            raise ValueError(f"Unknown container type: {container_type}")

        self.container_type = container_type
        self.container_dims = containers[container_type]
        self.pallets = []
        self.solution = None

    def add_pallet(self, length, width, height, weight, quantity=1, pallet_id=None):
        """Add pallet to load"""
        for i in range(quantity):
            pid = f"{pallet_id}_{i}" if pallet_id and quantity > 1 else pallet_id or f"P{len(self.pallets)}"
            self.pallets.append({
                'id': pid,
                'dims': (length, width, height),
                'weight': weight
            })

    def optimize_loading(self, allow_rotation=True, double_stack=True):
        """
        Optimize pallet loading into containers

        Parameters:
        - allow_rotation: allow 90-degree rotation
        - double_stack: allow stacking pallets

        Returns loading plan
        """

        # Sort pallets by volume (largest first)
        sorted_pallets = sorted(self.pallets,
                               key=lambda p: p['dims'][0] * p['dims'][1] * p['dims'][2],
                               reverse=True)

        containers = []

        for pallet in sorted_pallets:
            placed = False

            # Try existing containers
            for container in containers:
                if self._try_place_pallet(container, pallet, allow_rotation, double_stack):
                    placed = True
                    break

            # Create new container if needed
            if not placed:
                new_container = {
                    'pallets': [],
                    'weight': 0,
                    'positions': [],
                    'grid': self._create_empty_grid()
                }

                if self._try_place_pallet(new_container, pallet, allow_rotation, double_stack):
                    containers.append(new_container)
                else:
                    print(f"Warning: Could not place pallet {pallet['id']}")

        # Calculate metrics
        self.solution = self._calculate_solution_metrics(containers)
        return self.solution

    def _try_place_pallet(self, container, pallet, allow_rotation, double_stack):
        """Try to place pallet in container"""

        L, W, H = self.container_dims['L'], self.container_dims['W'], self.container_dims['H']
        max_weight = self.container_dims['capacity']

        # Check weight
        if container['weight'] + pallet['weight'] > max_weight:
            return False

        # Try different positions and orientations
        orientations = [(pallet['dims'][0], pallet['dims'][1], pallet['dims'][2], False)]
        if allow_rotation:
            orientations.append((pallet['dims'][1], pallet['dims'][0], pallet['dims'][2], True))

        # Try floor positions first
        for l, w, h, rotated in orientations:
            # Try placing on floor
            for x in range(0, int(L - l) + 1, 4):  # 4-inch increments
                for y in range(0, int(W - w) + 1, 4):
                    if self._check_space_available(container['grid'], x, y, 0, l, w, h):
                        # Place pallet
                        self._occupy_space(container['grid'], x, y, 0, l, w, h)
                        container['pallets'].append(pallet)
                        container['weight'] += pallet['weight']
                        container['positions'].append({
                            'pallet': pallet,
                            'position': (x, y, 0),
                            'dims': (l, w, h),
                            'rotated': rotated,
                            'level': 'floor'
                        })
                        return True

        # Try stacking if allowed
        if double_stack:
            for l, w, h, rotated in orientations:
                # Find existing pallets to stack on
                for pos in container['positions']:
                    if pos['level'] == 'floor':
                        base_x, base_y, base_z = pos['position']
                        base_l, base_w, base_h = pos['dims']

                        # Check if new pallet fits on top
                        if (l <= base_l and w <= base_w and
                            base_z + base_h + h <= H):

                            stack_z = base_z + base_h

                            if self._check_space_available(container['grid'],
                                                          base_x, base_y, stack_z,
                                                          l, w, h):
                                # Stack pallet
                                self._occupy_space(container['grid'],
                                                  base_x, base_y, stack_z,
                                                  l, w, h)
                                container['pallets'].append(pallet)
                                container['weight'] += pallet['weight']
                                container['positions'].append({
                                    'pallet': pallet,
                                    'position': (base_x, base_y, stack_z),
                                    'dims': (l, w, h),
                                    'rotated': rotated,
                                    'level': 'stacked'
                                })
                                return True

        return False

    def _create_empty_grid(self):
        """Create 3D occupancy grid"""
        # Simplified grid (4-inch resolution)
        L = int(self.container_dims['L'] / 4)
        W = int(self.container_dims['W'] / 4)
        H = int(self.container_dims['H'] / 4)
        return [[[False for _ in range(H)] for _ in range(W)] for _ in range(L)]

    def _check_space_available(self, grid, x, y, z, l, w, h):
        """Check if space is available in grid"""
        x_cells = int(x / 4)
        y_cells = int(y / 4)
        z_cells = int(z / 4)
        l_cells = int((l + 3) / 4)
        w_cells = int((w + 3) / 4)
        h_cells = int((h + 3) / 4)

        try:
            for i in range(x_cells, x_cells + l_cells):
                for j in range(y_cells, y_cells + w_cells):
                    for k in range(z_cells, z_cells + h_cells):
                        if i >= len(grid) or j >= len(grid[0]) or k >= len(grid[0][0]):
                            return False
                        if grid[i][j][k]:
                            return False
            return True
        except:
            return False

    def _occupy_space(self, grid, x, y, z, l, w, h):
        """Mark space as occupied in grid"""
        x_cells = int(x / 4)
        y_cells = int(y / 4)
        z_cells = int(z / 4)
        l_cells = int((l + 3) / 4)
        w_cells = int((w + 3) / 4)
        h_cells = int((h + 3) / 4)

        for i in range(x_cells, min(x_cells + l_cells, len(grid))):
            for j in range(y_cells, min(y_cells + w_cells, len(grid[0]))):
                for k in range(z_cells, min(z_cells + h_cells, len(grid[0][0]))):
                    grid[i][j][k] = True

    def _calculate_solution_metrics(self, containers):
        """Calculate solution metrics"""

        L = self.container_dims['L']
        W = self.container_dims['W']
        H = self.container_dims['H']
        container_volume = L * W * H

        solution = {
            'num_containers': len(containers),
            'container_type': self.container_type,
            'containers': []
        }

        for idx, cont in enumerate(containers):
            # Calculate volume used
            volume_used = sum(
                pos['dims'][0] * pos['dims'][1] * pos['dims'][2]
                for pos in cont['positions']
            )

            utilization = (volume_used / container_volume * 100)

            solution['containers'].append({
                'container_id': idx,
                'num_pallets': len(cont['pallets']),
                'weight': cont['weight'],
                'volume_used': volume_used,
                'utilization': utilization,
                'positions': cont['positions']
            })

        return solution

    def print_solution(self):
        """Print loading solution"""

        if not self.solution:
            print("No solution available")
            return

        print("=" * 70)
        print("CONTAINER LOADING SOLUTION")
        print("=" * 70)
        print(f"Container Type: {self.solution['container_type']}")
        print(f"Pallets to load: {len(self.pallets)}")
        print(f"Containers used: {self.solution['num_containers']}")
        print()

        for cont in self.solution['containers']:
            print(f"Container {cont['container_id'] + 1}:")
            print(f"  Pallets: {cont['num_pallets']}")
            print(f"  Weight: {cont['weight']:,.0f} lbs")
            print(f"  Utilization: {cont['utilization']:.1f}%")
            print()


# Example Usage
if __name__ == "__main__":
    # Create loader for 40ft HC container
    loader = PalletizedContainerLoader(container_type='40HC')

    # Add GMA pallets (48x40x60 inches, 1500 lbs each)
    loader.add_pallet(48, 40, 60, 1500, quantity=20, pallet_id='GMA')

    # Add EUR pallets (47x32x55 inches, 1200 lbs each)
    loader.add_pallet(47, 32, 55, 1200, quantity=10, pallet_id='EUR')

    # Optimize
    solution = loader.optimize_loading(allow_rotation=True, double_stack=True)

    # Print results
    loader.print_solution()
バラ積み貨物の積み込み
def optimize_loose_cargo_loading(items, container_type='40HC'):
    """
    Optimize loading of non-palletized (loose) cargo

    Uses 3D bin packing algorithms
    """

    from skills.three_d_bin_packing import ThreeDimensionalBinPacker

    # Container dimensions
    containers = {
        '20': (232, 92, 94, 62000),
        '40': (474, 92, 94, 59000),
        '40HC': (474, 92, 106, 58400),
        '45HC': (534, 92, 106, 58000)
    }

    L, W, H, max_weight = containers[container_type]

    # Use 3D bin packing
    packer = ThreeDimensionalBinPacker(L, W, H, max_weight)

    for item in items:
        packer.add_item(
            item['length'], item['width'], item['height'],
            item['weight'], item.get('id')
        )

    solution = packer.solve(algorithm='extreme_point', allow_rotation=True)

    return solution
複数の配送先への積み込み
def optimize_multi_destination_loading(shipments, container_type='40HC'):
    """
    Optimize container loading for multi-destination shipments

    Ensures items are loaded in reverse delivery order (LIFO)

    Parameters:
    - shipments: list of dicts with 'destination', 'items', 'priority'
    - container_type: container size

    Returns: loading plan with zones
    """

    # Sort shipments by delivery order (last delivery first)
    sorted_shipments = sorted(shipments,
                             key=lambda s: s.get('priority', 0),
                             reverse=True)

    containers = []

    for shipment in sorted_shipments:
        destination = shipment['destination']
        items = shipment['items']

        # Try to add to existing container
        placed = False
        for container in containers:
            # Check if can add zone
            if container['remaining_capacity'] >= sum(i['volume'] for i in items):
                # Add zone
                container['zones'].append({
                    'destination': destination,
                    'items': items
                })
                placed = True
                break

        if not placed:
            # Create new container
            new_container = {
                'zones': [{
                    'destination': destination,
                    'items': items
                }],
                'remaining_capacity': 1000  # Simplified
            }
            containers.append(new_container)

    return {
        'containers': containers,
        'num_containers': len(containers)
    }

よくある課題と解決策

課題:容積上限と重量上限

問題:

  • コンテナが容積上限に達しているが、重量制限には達していない(容積上限)
  • または、スペースが残っている状態で重量制限に達している(重量上限)
  • 積載能力を効率的に活用できない

解決策:

  • 重量のある貨物と軽い貨物を組み合わせてバランスを取ります
  • 容積重量比を計算します
  • 貨物の密度に適したコンテナサイズを使用します
  • 他の貨物との混載を検討します
  • 重量のある貨物の場合:小型コンテナを使用するか、重量ベースで輸送します
  • 軽い貨物の場合:容積を最大限に活用します
課題:重量配分

問題:

  • 重量配分が不均一です
  • 車軸重量の制限に違反します
  • コンテナが不安定になります

解決策:

  • 線形フィートあたりの重量を計算します
  • 均等な配分を目指します(ばらつき±2%)
  • 重い品目は中央または下部に配置します
  • 積載計画ソフトウェアを使用します
  • 左右、前後のバランスを取ります
  • トラックの車軸重量制限を考慮します
課題:サイズの異なるパレットの混載

問題:

  • GMA パレットと EUR パレットを効率よく組み合わせられません
  • サイズの異なるパレット間にスペースが無駄になります

解決策:

  • サイズの似たパレットをまとめます
  • 大型のパレットから先に積み込みます
  • 隙間を埋める貨物を使用します
  • パレットの種類ごとに別のコンテナを使用することを検討します
  • コンテナに積み込む前にパレットの配置パターンを最適化します

出力形式

コンテナ積載計画

概要:

  • 貨物:注文番号12345
  • 必要なコンテナ数:40ft HC × 2
  • パレット合計:22
  • 総重量:48,500 lbs
  • 平均積載率:87%

コンテナ 1 - 40ft HC:

  • 積載パレット数:11
  • 重量:24,800 lbs(積載可能重量の42%)
  • 容積利用率:89%
  • 重量配分:前部48%、後部52% ✓

積載パターン:

[Front]                [Rear]
Row 1: P1 P2 P3 P4    P5 P6
Row 2: P7 P8 P9       P10 P11

コンテナ 2 - 40ft HC:

  • 積載パレット数:11
  • 重量:23,700 lbs(積載可能重量の41%)
  • 容積利用率:85%
  • 重量配分:前部51%、後部49% ✓

固定要件:

  • すべてのパレットをストレッチフィルムで包装します
  • 列の間にロードバーを使用します
  • 空隙にはエアバッグを使用します
  • シール番号 #ABC123 でドアを封印します

確認する質問

  1. 使用するコンテナのサイズはどれですか?(20ft、40ft、40ft HC、45ft HC)
  2. 貨物はパレット積みですか、それともバラ積みですか?
  3. パレットの寸法と重量を教えてください
  4. 重量制限または重量配分の要件はありますか?
  5. 単一の配送先ですか、それとも複数箇所への配送ですか?
  6. 特殊な貨物(壊れやすいもの、危険物、温度管理が必要なもの)はありますか?
  7. 積み込み順序の要件はありますか?(LIFO/FIFO)

関連スキル

  • pallet-loading:コンテナ積載前のパレット単位の最適化
  • 3d-bin-packing:バラ積み貨物の積み込み
  • vehicle-loading-optimization:トラックへの積み込み
  • load-building-optimization:注文の集約
  • freight-optimization:輸送コストの最適化

コメント