Skip to content

Commit 5c3ec25

Browse files
author
Moreno
committed
CalWave task 1 - anchor installation plan files upgrades and updates with new task and chart files
1 parent 3e5cc84 commit 5c3ec25

12 files changed

+1158
-1602
lines changed

famodel/irma/calwave_action.py

Lines changed: 386 additions & 29 deletions
Large diffs are not rendered by default.

famodel/irma/calwave_actions.yaml

Lines changed: 24 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ demobilize:
4040
operator:
4141
- deck_space
4242
capabilities: []
43-
default_duration_h: 1.0
43+
duration_h: 1.0
4444
description: "Demobilization of vessel in homeport"
4545

4646
load_cargo:
@@ -61,37 +61,41 @@ load_cargo:
6161

6262
# --- Towing & Transport ---
6363

64-
transit:
65-
objects: []
64+
transit_linehaul_self:
65+
objects: [anchor]
6666
roles:
67-
carrier:
67+
vessel:
6868
- engine
69-
# operator:
70-
# - bollard_pull
71-
#capabilities: [engine]
72-
duration_h: 1.0
73-
description: "Transit of self-propelled vessel/tugboat"
69+
duration_h:
70+
description: "Self-propelled line-haul between port and site"
7471

75-
transit_tug:
76-
objects: []
72+
transit_linehaul_tug:
73+
objects: [anchor]
7774
roles:
7875
carrier:
7976
- engine
8077
operator:
8178
- bollard_pull
82-
#capabilities: [bollard_pull]
83-
default_duration_h: 1.0
84-
description: "Transit of tugged barge"
79+
duration_h:
80+
description: "Tugged line-haul convoy (tug + barge) between port and site"
81+
82+
transit_onsite_self:
83+
objects: [anchor]
84+
roles:
85+
vessel:
86+
- engine
87+
duration_h:
88+
description: "Self-propelled in-field move between site locations"
8589

86-
transit_deployport:
87-
objects: []
90+
transit_onsite_tug:
91+
objects: [anchor]
8892
roles:
8993
carrier:
9094
- engine
9195
operator:
9296
- bollard_pull
93-
# capabilities: [engine]
94-
default_duration_h: 1.0
97+
duration_h:
98+
description: "Tug + barge in-field move between site locations"
9599

96100
tow:
97101
objects: [platform]
@@ -149,7 +153,7 @@ install_anchor:
149153
- pump_subsea # pump_surface, drilling_machine, torque_machine
150154
- positioning_system
151155
- monitoring_system
152-
duration_h:
156+
duration_h:
153157
Hs_m:
154158
description: "Anchor installation (suction, driven, helical, DEA, SEPLA) with tensioning and verification."
155159

@@ -362,7 +366,7 @@ monitor_installation:
362366
- positioning_system
363367
- monitoring_system
364368
- rov
365-
duration_h:
369+
duration_h: 4.5
366370
Hs_m:
367371
description: "Real-time monitoring of installation operations using ROV and sensor packages."
368372

Lines changed: 216 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,216 @@
1+
# calwave_task1.py
2+
# Build CalWave Task 1 (Anchor installation) following the theory flow:
3+
# 1) addAction → structure only (type, name, objects, deps)
4+
# 2) evaluateAssets → assign vessels/roles (+ durations/costs)
5+
# 3) (schedule/plot handled by your existing tooling)
6+
7+
from famodel.project import Project
8+
from calwave_irma import Scenario
9+
import calwave_chart as chart
10+
from calwave_task import Task
11+
12+
sc = Scenario() # now sc exists in *this* session
13+
14+
def eval_set(a, roles, duration=None, **params):
15+
"""
16+
Convenience: call evaluateAssets with roles/params and optionally set .duration.
17+
Always stores assigned_assets for plotting/scheduling attribution.
18+
"""
19+
# Your Action.evaluateAssets may return (duration, cost); we still set explicit duration if passed.
20+
res = a.evaluateAssets(roles | params)
21+
if duration is not None:
22+
a.duration = float(duration)
23+
elif isinstance(res, tuple) and len(res) > 0 and res[0] is not None:
24+
try:
25+
a.duration = float(res[0])
26+
except Exception:
27+
pass
28+
# keep roles visible on the action
29+
a.assigned_assets = roles
30+
return a
31+
32+
# ---------- Core builder ----------
33+
def build_task1_calwave(sc: Scenario, project: Project):
34+
"""
35+
Creates Task 1 actions + dependencies (no scheduling/plotting here).
36+
"""
37+
38+
# --- Pre-ops ---
39+
mob_sd = sc.addAction('mobilize', 'mobilize_SanDiego')
40+
linehaul_convoy = sc.addAction(
41+
'transit_linehaul_tug', 'linehaul_to_site_convoy',
42+
dependencies=[mob_sd])
43+
44+
mob_by = sc.addAction(
45+
'mobilize', 'mobilize_Beyster',
46+
#dependencies=[mob_sd]
47+
)
48+
linehaul_by = sc.addAction(
49+
'transit_linehaul_self', 'linehaul_to_site_Beyster',
50+
dependencies=[mob_sd])
51+
52+
# --- Compute anchor centroid (x,y) for first onsite leg start ---
53+
anchors_all = list(project.anchorList.values())
54+
rs = [getattr(a, 'r', None) for a in anchors_all if getattr(a, 'r', None) is not None]
55+
xs = [float(r[0]) for r in rs]
56+
ys = [float(r[1]) for r in rs]
57+
anchor_centroid = (sum(xs)/len(xs), sum(ys)/len(ys)) if xs and ys else None
58+
try:
59+
print('[task1] anchor_centroid =', anchor_centroid)
60+
except Exception:
61+
pass
62+
63+
# --- On-site (domain objects REQUIRED) ---
64+
installs, onsite_tug, onsite_by, monitors = [], [], [], []
65+
66+
# first convoy leg starts after the linehaul convoy reaches site
67+
prev_for_next_tug = linehaul_convoy
68+
# Beyster’s first in-field leg starts after her own linehaul
69+
prev_for_by = linehaul_by
70+
71+
for i, (key, anchor) in enumerate(project.anchorList.items(), start=1):
72+
# 1) Onsite convoy (tug + barge) to this anchor
73+
a_tug = sc.addAction(
74+
'transit_onsite_tug', f'transit_convoy-{key}',
75+
objects=[anchor],
76+
dependencies=[prev_for_next_tug] # first = linehaul_convoy; then = previous install
77+
)
78+
79+
# 2) Beyster to this anchor (after previous monitor), independent of tug
80+
a_by = sc.addAction(
81+
'transit_onsite_self', f'transit_Beyster-{key}',
82+
objects=[anchor],
83+
dependencies=[prev_for_by, prev_for_next_tug]
84+
)
85+
86+
# Inject centroid for the FIRST onsite legs only (centroid → first anchor)
87+
if i == 1 and anchor_centroid is not None:
88+
a_by.meta = getattr(a_by, 'meta', {}) or {}
89+
a_by.meta['anchor_centroid'] = anchor_centroid
90+
a_tug.meta = getattr(a_tug, 'meta', {}) or {}
91+
a_tug.meta['anchor_centroid'] = anchor_centroid
92+
93+
# 3) Install at this anchor (wait for both tug+barge and Beyster on station)
94+
a_inst = sc.addAction(
95+
'install_anchor', f'install_anchor-{key}',
96+
objects=[anchor],
97+
dependencies=[a_tug, a_by]
98+
)
99+
100+
# 4) Monitor at this anchor (while anchor is installed)
101+
a_mon = sc.addAction(
102+
'monitor_installation', f'monitor_installation-{key}',
103+
objects=[anchor],
104+
dependencies=[a_tug]
105+
)
106+
107+
# collect handles
108+
onsite_tug.append(a_tug)
109+
installs.append(a_inst)
110+
onsite_by.append(a_by)
111+
monitors.append(a_mon)
112+
113+
# chain next legs:
114+
prev_for_next_tug = a_inst # next convoy starts from this installed anchor
115+
prev_for_by = a_mon # or set to a_inst if you want Beyster to move immediately post-install
116+
117+
118+
# --- Post-ops (objectless) ---
119+
linehome_convoy = sc.addAction(
120+
'transit_linehaul_tug', 'linehaul_to_home_convoy',
121+
dependencies=monitors)
122+
123+
linehome_by = sc.addAction(
124+
'transit_linehaul_self', 'transit_to_home_Beyster',
125+
dependencies=monitors)
126+
127+
# --- Post-ops ---
128+
demob_sd = sc.addAction(
129+
'demobilize', 'demobilize_SanDiego',
130+
dependencies=[linehome_convoy])
131+
132+
demob_by = sc.addAction(
133+
'demobilize', 'demobilize_Beyster',
134+
dependencies=[linehome_by])
135+
136+
# Return a simple list for downstream evaluate/schedule/plot steps
137+
return {
138+
'mobilize': [mob_sd, mob_by],
139+
'linehaul_to_site': [linehaul_convoy, linehaul_by],
140+
'install': installs,
141+
'onsite_tug': onsite_tug,
142+
'onsite_by': onsite_by,
143+
'monitor': monitors,
144+
'linehaul_to_home': [linehome_convoy, linehome_by],
145+
'demobilize': [demob_sd, demob_by]}
146+
147+
# ---------- Evaluation step (assign vessels & durations) ----------
148+
def evaluate_task1(sc: Scenario, actions: dict):
149+
"""
150+
Assign vessels/roles and set durations where the evaluator doesn't.
151+
Keeps creation and evaluation clearly separated.
152+
"""
153+
V = sc.vessels # shorthand
154+
155+
# Mobilize
156+
eval_set(actions['mobilize'][0], {'operator': V['San_Diego']}, duration=3.0)
157+
eval_set(actions['mobilize'][1], {'operator': V['Beyster']}, duration=1.0)
158+
159+
# Transit to site
160+
convoy_to_site, beyster_to_site = actions['linehaul_to_site']
161+
eval_set(convoy_to_site, {'carrier': V['Jag'], 'operator': V['San_Diego']})
162+
eval_set(beyster_to_site, {'vessel': V['Beyster']})
163+
164+
# Onsite convoy (tug+barge)
165+
for a_tug in actions['onsite_tug']:
166+
eval_set(a_tug, {'carrier': V['Jag'], 'operator': V['San_Diego']})
167+
168+
# Install (Jag carries, San_Diego operates the install)
169+
for a_inst in actions['install']:
170+
eval_set(a_inst, {'carrier': V['Jag'], 'operator': V['San_Diego']})
171+
172+
# Onsite self-propelled (Beyster)
173+
for a_by in actions['onsite_by']:
174+
eval_set(a_by, {'vessel': V['Beyster']})
175+
176+
# Monitor (Beyster as support)
177+
for a_mon in actions['monitor']:
178+
eval_set(a_mon, {'support': V['Beyster']})
179+
180+
# Transit to home
181+
convoy_to_home, beyster_to_home = actions['linehaul_to_home']
182+
eval_set(convoy_to_home, {'carrier': V['Jag'], 'operator': V['San_Diego']})
183+
eval_set(beyster_to_home, {'vessel': V['Beyster']})
184+
185+
# Demobilize
186+
eval_set(actions['demobilize'][0], {'operator': V['San_Diego']}, duration=3.0)
187+
eval_set(actions['demobilize'][1], {'operator': V['Beyster']}, duration=1.0)
188+
189+
190+
if __name__ == '__main__':
191+
# 1) Load ontology that mirrors the sample schema (mooring_systems + mooring_line_configs)
192+
project = Project(file='calwave_ontology.yaml', raft=False)
193+
project.getMoorPyArray(cables=1)
194+
195+
# 2) Scenario with CalWave catalogs
196+
sc = Scenario()
197+
198+
# 3) Build (structure only)
199+
actions = build_task1_calwave(sc, project)
200+
201+
# 4) Evaluate (assign vessels/roles + durations)
202+
evaluate_task1(sc, actions)
203+
204+
# 5) schedule once, in the Task
205+
calwave_task1 = Task.from_scenario(
206+
sc,
207+
strategy='levels', # or 'levels'
208+
enforce_resources=False, # keep single-resource blocking if you want it
209+
resource_roles=('vessel', 'carrier', 'operator'))
210+
211+
# 6) build the chart input directly from the Task and plot
212+
chart_view = chart.view_from_task(calwave_task1, sc, title='CalWave Task 1 - Anchor installation plan')
213+
chart.plot_task(chart_view)
214+
215+
216+

famodel/irma/calwave_capabilities.yaml

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,19 +12,20 @@
1212
- name: engine
1313
# description: Engine on-board of the vessel
1414
# fields:
15-
power_hp: # power [horsepower]
16-
speed_kn: # speed [knot]
15+
power_hp: # power [horsepower]
16+
site_speed_mps: # speed [m/s]
1717

1818
- name: bollard_pull
1919
# description: Towing/holding force capability
2020
# fields:
2121
max_force_t: # bollard pull [t]
22+
site_speed_mps: # speed [m/s]
2223

2324
- name: deck_space
2425
# description: Clear usable deck area and allowable load
2526
# fields:
26-
area_m2: # usable area [m2]
27-
max_load_t: # allowable deck load [t]
27+
area_m2: # usable area [m2]
28+
max_load_t: # allowable deck load [t]
2829

2930
- name: chain_locker
3031
# description: Chain storage capacity

0 commit comments

Comments
 (0)