关于 prefab-optimization
prefab-optimization 是用于优化预制和模块化施工的技能,涵盖模块设计、工厂排程、运输、现场装配顺序、设备规划和质量检查点。
主要功能
- 01优化模块运输设计
- 02安排工厂生产计划
- 03规划物流与运输
- 04优化现场装配顺序
- 05规划起重机和设备
- 06设置质量控制检查点
适用场景
- 01规划模块化建筑生产
- 02为模块分配运输车辆
- 03安排现场模块装配顺序
- 04协调设备规划与质量检查
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ datadrivenconstruction/ ddc_skills_for_ai_agents_in_construction --skill prefab-optimization安装后在 Claude Code 中输入/prefab-optimization确认已加载。
附带文件claw.jsoninstructions.md
详细介绍
预制优化
概述
此技能实现了预制和模块化施工的优化算法。提高工厂利用率,降低运输成本,并优化现场装配顺序。
优化领域:
- 面向运输的模块设计
- 工厂生产排程
- 物流与运输
- 现场装配排序
- 起重机与设备规划
- 质量控制检查点
快速入门
from dataclasses import dataclass, field
from datetime import date, datetime, timedelta
from typing import List, Dict, Tuple, Optional
from enum import Enum
class ModuleStatus(Enum):
DESIGN = "design"
PRODUCTION = "production"
QC = "quality_control"
STORAGE = "storage"
TRANSPORT = "transport"
ON_SITE = "on_site"
INSTALLED = "installed"
@dataclass
class PrefabModule:
module_id: str
name: str
module_type: str
dimensions: Tuple[float, float, float] # L, W, H in meters
weight_kg: float
status: ModuleStatus = ModuleStatus.DESIGN
production_hours: float = 0
dependencies: List[str] = field(default_factory=list)
@dataclass
class ProductionSlot:
slot_id: str
start_time: datetime
end_time: datetime
bay_id: str
module_id: str
def calculate_transport_constraints(module: PrefabModule) -> Dict:
"""Calculate transport constraints for module"""
L, W, H = module.dimensions
# Standard transport limits (varies by region)
max_width = 4.0 # meters
max_height = 4.5 # meters
max_length = 12.0 # meters
max_weight = 40000 # kg
constraints = {
'within_standard': True,
'requires_escort': False,
'requires_permit': False,
'transport_type': 'standard'
}
if W > max_width or H > max_height:
constraints['within_standard'] = False
constraints['requires_escort'] = True
constraints['requires_permit'] = True
constraints['transport_type'] = 'wide_load'
if L > max_length:
constraints['requires_permit'] = True
constraints['transport_type'] = 'long_load'
if module.weight_kg > max_weight:
constraints['requires_permit'] = True
constraints['transport_type'] = 'heavy_load'
return constraints
# Example
module = PrefabModule(
module_id="MOD-001",
name="Bathroom Pod Type A",
module_type="bathroom",
dimensions=(4.5, 3.0, 3.2),
weight_kg=8500,
production_hours=40
)
constraints = calculate_transport_constraints(module)
print(f"Module {module.name}: {constraints}")
综合预制系统
模块定义与分析
from dataclasses import dataclass, field
from datetime import date, datetime, timedelta
from typing import List, Dict, Tuple, Optional, Set
from enum import Enum
import numpy as np
class ModuleCategory(Enum):
BATHROOM_POD = "bathroom_pod"
KITCHEN_POD = "kitchen_pod"
STRUCTURAL = "structural"
FACADE = "facade"
MEP = "mep"
STAIR = "stair"
ELEVATOR = "elevator"
ROOM_MODULE = "room_module"
@dataclass
class ModuleConnection:
connection_id: str
connection_type: str # structural, mep, electrical
from_module: str
to_module: str
from_point: Tuple[float, float, float]
to_point: Tuple[float, float, float]
tolerance_mm: float = 10
@dataclass
class ModuleDesign:
module_id: str
name: str
category: ModuleCategory
version: str
# Dimensions and weight
length_m: float
width_m: float
height_m: float
weight_kg: float
# Production
production_hours: float
required_skills: List[str]
materials_list: List[Dict]
# Connections
connections: List[ModuleConnection] = field(default_factory=list)
# Dependencies
required_modules: List[str] = field(default_factory=list) # Must be installed before
blocks_modules: List[str] = field(default_factory=list) # Cannot install until this is done
# Metadata
floor_level: int = 0
grid_position: Tuple[str, str] = ('', '') # Grid reference
zone: str = ''
@property
def volume_m3(self) -> float:
return self.length_m * self.width_m * self.height_m
@property
def footprint_m2(self) -> float:
return self.length_m * self.width_m
class ModuleAnalyzer:
"""Analyze prefab modules for optimization"""
def __init__(self):
self.transport_limits = {
'standard': {'width': 2.55, 'height': 4.0, 'length': 12.0, 'weight': 25000},
'wide_load': {'width': 4.0, 'height': 4.5, 'length': 16.0, 'weight': 40000},
'special': {'width': 6.0, 'height': 5.0, 'length': 25.0, 'weight': 100000}
}
def analyze_transportability(self, module: ModuleDesign) -> Dict:
"""Analyze module transportability"""
dims = (module.length_m, module.width_m, module.height_m)
# Check against limits
for transport_type, limits in self.transport_limits.items():
if (max(dims[0], dims[1]) <= limits['length'] and
min(dims[0], dims[1]) <= limits['width'] and
dims[2] <= limits['height'] and
module.weight_kg <= limits['weight']):
analysis = {
'feasible': True,
'transport_type': transport_type,
'orientation': 'length_first' if dims[0] >= dims[1] else 'width_first',
'utilization': {
'length': max(dims[0], dims[1]) / limits['length'],
'width': min(dims[0], dims[1]) / limits['width'],
'height': dims[2] / limits['height'],
'weight': module.weight_kg / limits['weight']
}
}
if transport_type == 'standard':
analysis['cost_factor'] = 1.0
elif transport_type == 'wide_load':
analysis['cost_factor'] = 1.5
analysis['requirements'] = ['escort_vehicle', 'permit', 'route_survey']
else:
analysis['cost_factor'] = 3.0
analysis['requirements'] = ['police_escort', 'special_permit', 'night_transport']
return analysis
return {
'feasible': False,
'reason': 'Exceeds maximum transport dimensions',
'max_dimension': max(dims),
'recommendation': 'Consider splitting into smaller modules'
}
def analyze_lifting(self, module: ModuleDesign) -> Dict:
"""Analyze lifting requirements"""
# Estimate crane capacity needed (with safety factor)
safety_factor = 1.25
required_capacity = module.weight_kg * safety_factor / 1000 # tonnes
# Estimate boom length based on typical building heights
floor_height = 3.5 # meters per floor
estimated_height = module.floor_level * floor_height + 10 # +10m clearance
# Rough crane selection
if required_capacity <= 50 and estimated_height <= 30:
crane_type = 'mobile_50t'
elif required_capacity <= 100 and estimated_height <= 50:
crane_type = 'mobile_100t'
elif required_capacity <= 200:
crane_type = 'crawler_200t'
else:
crane_type = 'tower_crane'
return {
'required_capacity_tonnes': required_capacity,
'estimated_lift_height_m': estimated_height,
'recommended_crane': crane_type,
'lift_points': self._calculate_lift_points(module),
'center_of_gravity': (module.length_m / 2, module.width_m / 2, module.height_m / 3)
}
def _calculate_lift_points(self, module: ModuleDesign) -> List[Tuple[float, float]]:
"""Calculate optimal lift point positions"""
L, W = module.length_m, module.width_m
# Standard 4-point lift
offset = 0.2 # 20% from edges
return [
(L * offset, W * offset),
(L * (1 - offset), W * offset),
(L * offset, W * (1 - offset)),
(L * (1 - offset), W * (1 - offset))
]
生产排程
from datetime import datetime, timedelta
from typing import List, Dict, Optional
import heapq
@dataclass
class ProductionBay:
bay_id: str
bay_type: str # assembly, finishing, storage
capacity_m2: float
available_from: datetime
skills_available: List[str]
@dataclass
class ProductionOrder:
module_id: str
required_date: date
priority: int # 1 = highest
production_hours: float
required_bay_type: str
required_skills: List[str]
class ProductionScheduler:
"""Schedule prefab module production"""
def __init__(self, work_hours_per_day: float = 8):
self.bays: Dict[str, ProductionBay] = {}
self.schedule: Dict[str, List[ProductionSlot]] = {}
self.work_hours = work_hours_per_day
def add_bay(self, bay: ProductionBay):
"""Add production bay"""
self.bays[bay.bay_id] = bay
self.schedule[bay.bay_id] = []
def schedule_production(self, orders: List[ProductionOrder]) -> Dict:
"""Schedule all production orders"""
# Sort by priority and required date
sorted_orders = sorted(orders, key=lambda o: (o.priority, o.required_date))
scheduled = []
unscheduled = []
for order in sorted_orders:
slot = self._find_best_slot(order)
if slot:
self.schedule[slot.bay_id].append(slot)
scheduled.append({
'module_id': order.module_id,
'bay_id': slot.bay_id,
'start': slot.start_time.isoformat(),
'end': slot.end_time.isoformat(),
'duration_hours': order.production_hours
})
else:
unscheduled.append(order.module_id)
return {
'scheduled': scheduled,
'unscheduled': unscheduled,
'utilization': self._calculate_utilization()
}
def _find_best_slot(self, order: ProductionOrder) -> Optional[ProductionSlot]:
"""Find best production slot for order"""
best_slot = None
best_end_time = datetime.max
for bay_id, bay in self.bays.items():
if bay.bay_type != order.required_bay_type:
continue
if not set(order.required_skills).issubset(set(bay.skills_available)):
continue
# Find earliest available time
existing_slots = self.schedule.get(bay_id, [])
if existing_slots:
last_end = max(s.end_time for s in existing_slots)
start_time = max(bay.available_from, last_end)
else:
start_time = bay.available_from
# Calculate end time
production_days = order.production_hours / self.work_hours
end_time = start_time + timedelta(days=production_days)
# Check if this meets deadline
required_datetime = datetime.combine(order.required_date, datetime.min.time())
if end_time <= required_datetime and end_time < best_end_time:
best_end_time = end_time
best_slot = ProductionSlot(
slot_id=f"SLOT-{bay_id}-{len(existing_slots)}",
start_time=start_time,
end_time=end_time,
bay_id=bay_id,
module_id=order.module_id
)
return best_slot
def _calculate_utilization(self) -> Dict[str, float]:
"""Calculate bay utilization"""
utilization = {}
for bay_id, slots in self.schedule.items():
if not slots:
utilization[bay_id] = 0.0
continue
total_time = (max(s.end_time for s in slots) -
min(s.start_time for s in slots)).total_seconds()
used_time = sum((s.end_time - s.start_time).total_seconds() for s in slots)
utilization[bay_id] = used_time / total_time if total_time > 0 else 0
return utilization
def get_gantt_data(self) -> List[Dict]:
"""Get data for Gantt chart visualization"""
gantt_data = []
for bay_id, slots in self.schedule.items():
for slot in slots:
gantt_data.append({
'bay': bay_id,
'module': slot.module_id,
'start': slot.start_time.isoformat(),
'end': slot.end_time.isoformat()
})
return sorted(gantt_data, key=lambda x: x['start'])
装配顺序优化
from collections import defaultdict, deque
from typing import List, Dict, Set
class AssemblySequencer:
"""Optimize on-site module assembly sequence"""
def __init__(self, modules: List[ModuleDesign]):
self.modules = {m.module_id: m for m in modules}
self.dependency_graph = self._build_dependency_graph()
def _build_dependency_graph(self) -> Dict[str, Set[str]]:
"""Build dependency graph from module dependencies"""
graph = defaultdict(set)
for module_id, module in self.modules.items():
for dep_id in module.required_modules:
graph[module_id].add(dep_id)
return graph
def calculate_sequence(self) -> List[List[str]]:
"""Calculate optimal assembly sequence using topological sort"""
# Calculate in-degree for each node
in_degree = defaultdict(int)
for module_id in self.modules:
in_degree[module_id] = 0
for deps in self.dependency_graph.values():
for dep in deps:
in_degree[dep] += 1
# Start with modules that have no dependencies
queue = deque([
m_id for m_id in self.modules
if len(self.dependency_graph[m_id]) == 0
])
sequence = []
current_level = []
while queue:
# Process current level
current_level = list(queue)
queue.clear()
sequence.append(current_level)
# Find next level
for module_id in current_level:
for dependent in self.modules:
if module_id in self.dependency_graph[dependent]:
self.dependency_graph[dependent].remove(module_id)
if len(self.dependency_graph[dependent]) == 0:
queue.append(dependent)
# Check for cycles
remaining = [m_id for m_id in self.modules if m_id not in
[item for sublist in sequence for item in sublist]]
if remaining:
print(f"Warning: Circular dependencies detected for: {remaining}")
return sequence
def optimize_for_crane(self, crane_positions: List[Tuple[float, float]]) -> List[Dict]:
"""Optimize sequence considering crane movement"""
base_sequence = self.calculate_sequence()
optimized = []
for level in base_sequence:
# Sort modules in level by proximity to crane positions
level_with_positions = []
for module_id in level:
module = self.modules[module_id]
# Use grid position to calculate distance
grid_x = ord(module.grid_position[0]) if module.grid_position[0] else 0
grid_y = int(module.grid_position[1]) if module.grid_position[1].isdigit() else 0
# Find nearest crane
min_dist = float('inf')
for cx, cy in crane_positions:
dist = ((grid_x - cx) ** 2 + (grid_y - cy) ** 2) ** 0.5
min_dist = min(min_dist, dist)
level_with_positions.append({
'module_id': module_id,
'floor': module.floor_level,
'distance_to_crane': min_dist
})
# Sort by floor (bottom-up) then by crane distance
level_with_positions.sort(key=lambda x: (x['floor'], x['distance_to_crane']))
optimized.append(level_with_positions)
return optimized
def generate_installation_plan(self) -> List[Dict]:
"""Generate detailed installation plan"""
sequence = self.calculate_sequence()
plan = []
day = 1
modules_per_day = 4 # Adjust based on crane capacity
for level_idx, level in enumerate(sequence):
for i in range(0, len(level), modules_per_day):
batch = level[i:i + modules_per_day]
for module_id in batch:
module = self.modules[module_id]
plan.append({
'day': day,
'sequence': len(plan) + 1,
'module_id': module_id,
'module_name': module.name,
'floor': module.floor_level,
'grid': module.grid_position,
'weight_kg': module.weight_kg,
'connections': len(module.connections),
'level': level_idx + 1
})
day += 1
return plan
运输优化
from scipy.optimize import linear_sum_assignment
import numpy as np
@dataclass
class TransportVehicle:
vehicle_id: str
capacity_kg: float
max_length_m: float
max_width_m: float
max_height_m: float
cost_per_km: float
available_from: datetime
class TransportOptimizer:
"""Optimize module transportation logistics"""
def __init__(self, factory_location: Tuple[float, float],
site_location: Tuple[float, float]):
self.factory = factory_location
self.site = site_location
self.distance_km = self._calculate_distance()
self.vehicles: List[TransportVehicle] = []
self.routes: List[Dict] = []
def _calculate_distance(self) -> float:
"""Calculate distance between factory and site"""
# Simplified Haversine for demonstration
lat1, lon1 = self.factory
lat2, lon2 = self.site
R = 6371 # Earth radius in km
dlat = np.radians(lat2 - lat1)
dlon = np.radians(lon2 - lon1)
a = (np.sin(dlat/2)**2 +
np.cos(np.radians(lat1)) * np.cos(np.radians(lat2)) *
np.sin(dlon/2)**2)
c = 2 * np.arctan2(np.sqrt(a), np.sqrt(1-a))
return R * c
def add_vehicle(self, vehicle: TransportVehicle):
self.vehicles.append(vehicle)
def optimize_loading(self, modules: List[ModuleDesign],
required_dates: Dict[str, date]) -> Dict:
"""Optimize which modules go on which vehicle"""
# Sort modules by required date
sorted_modules = sorted(
modules,
key=lambda m: required_dates.get(m.module_id, date.max)
)
assignments = []
remaining_modules = list(sorted_modules)
while remaining_modules:
# Find best vehicle for next batch
for vehicle in self.vehicles:
batch = self._pack_vehicle(vehicle, remaining_modules)
if batch:
assignments.append({
'vehicle_id': vehicle.vehicle_id,
'modules': [m.module_id for m in batch],
'total_weight_kg': sum(m.weight_kg for m in batch),
'capacity_used': sum(m.weight_kg for m in batch) / vehicle.capacity_kg,
'cost': vehicle.cost_per_km * self.distance_km * 2 # Round trip
})
for m in batch:
remaining_modules.remove(m)
break
else:
# No vehicle can take remaining modules
break
return {
'assignments': assignments,
'total_trips': len(assignments),
'total_cost': sum(a['cost'] for a in assignments),
'unassigned': [m.module_id for m in remaining_modules]
}
def _pack_vehicle(self, vehicle: TransportVehicle,
modules: List[ModuleDesign]) -> List[ModuleDesign]:
"""Pack modules onto vehicle (simplified bin packing)"""
packed = []
total_weight = 0
for module in modules:
# Check if module fits
dims = sorted([module.length_m, module.width_m])
if (dims[0] <= vehicle.max_width_m and
dims[1] <= vehicle.max_length_m and
module.height_m <= vehicle.max_height_m and
total_weight + module.weight_kg <= vehicle.capacity_kg):
packed.append(module)
total_weight += module.weight_kg
# Simple: one module per trip for large items
if max(dims) > 6 or module.weight_kg > vehicle.capacity_kg * 0.7:
break
return packed
def schedule_deliveries(self, assignments: List[Dict],
site_constraints: Dict = None) -> List[Dict]:
"""Schedule deliveries considering site constraints"""
schedule = []
# Default constraints
if site_constraints is None:
site_constraints = {
'unload_start_hour': 7,
'unload_end_hour': 17,
'max_deliveries_per_day': 4,
'unload_time_minutes': 60
}
current_date = date.today()
deliveries_today = 0
current_hour = site_constraints['unload_start_hour']
for assignment in assignments:
if deliveries_today >= site_constraints['max_deliveries_per_day']:
current_date += timedelta(days=1)
deliveries_today = 0
current_hour = site_constraints['unload_start_hour']
if current_hour >= site_constraints['unload_end_hour']:
current_date += timedelta(days=1)
deliveries_today = 0
current_hour = site_constraints['unload_start_hour']
schedule.append({
**assignment,
'delivery_date': current_date.isoformat(),
'arrival_time': f"{current_hour:02d}:00",
'departure_time': f"{current_hour + 1:02d}:00"
})
current_hour += 2 # 1 hour unload + 1 hour buffer
deliveries_today += 1
return schedule
快速参考
| 模块类型 | 典型尺寸(长×宽×高) | 典型重量 | 生产时间 |
|---|---|---|---|
| 浴室模块 | 3.0 x 2.4 x 2.7m | 4,000-8,000 kg | 30-50 hours |
| 厨房模块 | 4.0 x 2.4 x 2.7m | 5,000-10,000 kg | 40-60 hours |
| 房间模块 | 6.0 x 3.0 x 3.0m | 15,000-25,000 kg | 60-100 hours |
| 外墙板 | 6.0 x 3.0 x 0.3m | 2,000-4,000 kg | 15-25 hours |
| 楼梯模块 | 4.0 x 2.5 x 3.5m | 8,000-12,000 kg | 35-50 hours |
各地区运输限制
| 地区 | 最大宽度 | 最大高度 | 最大长度 | 最大重量 |
|---|---|---|---|---|
| 欧盟标准 | 2.55m | 4.0m | 12.0m | 40t |
| 欧盟超宽载荷 | 4.0m | 4.5m | 16.5m | 60t |
| 美国标准 | 2.6m | 4.1m | 14.6m | 36t |
| 美国超限尺寸 | 4.3m | 4.6m | 22.0m | 60t |
资源
- 模块化建筑协会:https://www.modular.org
- 预制中心:https://www.prefabhub.org
- DDC 网站:https://datadrivenconstruction.io
后续步骤
- 参阅
site-logistics-optimization,了解现场交付排程 - 参阅
4d-simulation,了解装配顺序可视化 - 参阅
bim-validation-pipeline,了解模块质量检查
评论
支持 Markdown