3232
3333
3434def incrementer (text ):
35+ '''
36+ Increments the last integer found in a string.
37+
38+ Inputs
39+ ------
40+ text : str
41+ The input string to increment.
42+
43+ Returns
44+ -------
45+ str
46+ The incremented string.
47+ '''
3548 split_text = text .split ()[::- 1 ]
3649 for ind , spl in enumerate (split_text ):
3750 try :
@@ -43,7 +56,19 @@ def incrementer(text):
4356
4457
4558def increment_name (name ):
46- '''Increments an end integer after a dash in a name'''
59+ '''
60+ Increments an end integer after a dash in a name.
61+
62+ Inputs
63+ ------
64+ name : str
65+ The input name string.
66+
67+ Returns
68+ -------
69+ str
70+ The incremented name string.
71+ '''
4772 name_parts = name .split (sep = '-' )
4873
4974 # if no numeric suffix yet, add one
@@ -72,7 +97,7 @@ def __init__(self, actionType, name, **kwargs):
7297 It must be given a name.
7398 The remaining parameters should correspond to items in the actionType dict...
7499
75- Parameters
100+ Inputs
76101 ----------
77102 actionType : dict
78103 Dictionary defining the action type (typically taken from a yaml).
@@ -83,7 +108,10 @@ def __init__(self, actionType, name, **kwargs):
83108 Additional arguments may depend on the action type and typically
84109 include a list of FAModel objects that are acted upon, or
85110 a list of dependencies (other action names/objects).
86-
111+
112+ Returns
113+ -------
114+ None
87115 '''
88116
89117 # list of things that will be controlled during this action
@@ -139,7 +167,7 @@ def __init__(self, actionType, name, **kwargs):
139167 for role , caplist in actionType ['roles' ].items ():
140168 self .requirements [role ] = {key : None for key in caplist } # each role requirment holds a dict of capabilities with values set to None for now
141169 for cap in caplist :
142- # self.requirements[role][cap] = {} # fill in each required capacity with {'metric': 0.0}
170+ # self.requirements[role][cap] = {} # fill in each required capacity with empty dict
143171 self .requirements [role ][cap ] = {'area_m2' : 1000 , 'max_load_t' : 1600 } # dummy values for now, just larger than MPSV_01 values to trigger failure
144172
145173 self .assets [role ] = None # placeholder for the asset assigned to this role
@@ -155,12 +183,17 @@ def __init__(self, actionType, name, **kwargs):
155183
156184
157185 def addDependency (self , dep ):
158- '''Registers other action as a dependency of this one.
186+ '''
187+ Registers other action as a dependency of this one.
159188
160189 Inputs
161190 ------
162191 dep : Action
163192 The action to be added as a dependency.
193+
194+ Returns
195+ -------
196+ None
164197 '''
165198 self .dependencies [dep .name ] = dep
166199 # could see if already a dependency and raise a warning if so...
@@ -169,12 +202,16 @@ def addDependency(self, dep):
169202 def assignObjects (self , objects ):
170203 '''
171204 Adds a list of objects to the actions objects list,
172- checking they are valid for the actions supported objects
205+ checking they are valid for the actions supported objects.
173206
174207 Inputs
175208 ------
176209 objects : list
177210 A list of FAModel objects to be added to the action.
211+
212+ Returns
213+ -------
214+ None
178215 '''
179216
180217 for obj in objects :
@@ -189,6 +226,17 @@ def assignObjects(self, objects):
189226
190227
191228 # def setUpCapability(self):
229+ # '''
230+ # Example of what needs to happen to create a metric.
231+ #
232+ # Inputs
233+ # ------
234+ # None
235+ #
236+ # Returns
237+ # -------
238+ # None
239+ # '''
192240 # # WIP: example of what needs to happen to create a metric
193241
194242 # # figure out how to assign required metrics to capabilies in the roles based on the objects
@@ -204,6 +252,20 @@ def assignObjects(self, objects):
204252 def checkAsset (self , role_name , asset ):
205253 '''Checks if a specified asset has sufficient capabilities to fulfil
206254 a specified role in this action.
255+
256+ Inputs
257+ ------
258+ role_name : string
259+ The name of the role to check.
260+ asset : dict
261+ The asset to check against the role's requirements.
262+
263+ Returns
264+ -------
265+ bool
266+ True if the asset meets the role's requirements, False otherwise.
267+ str
268+ A message providing additional information about the check.
207269 '''
208270
209271 # Make sure role_name is valid for this action
@@ -212,44 +274,62 @@ def checkAsset(self, role_name, asset):
212274
213275 for capability in self .requirements [role_name ].keys ():
214276
215- if capability in asset ['capabilities' ].keys (): # check capability
216- # does this work if there are no metrics in a capability? This should be possible, as not all capabilities will require a constraint.
277+ if capability in asset ['capabilities' ].keys (): # check capability is in asset
278+
279+ # TODO: does this work if there are no metrics in a capability? This should be possible, as not all capabilities will require a constraint.
217280 for metric in self .requirements [role_name ][capability ].keys (): # loop over the capacity requirements for the capability (if more than one)
218- if self .requirements [role_name ][capability ][metric ] > asset ['capabilities' ][capability ][metric ]: # check capacity
219- # TODO: can we throw a message here that explains what metric is violated?
220- return False # the asset does not have the capacity for this capability
221- return True
281+
282+ if metric not in asset ['capabilities' ][capability ].keys (): # value error because capabilities are defined in capabilities.yaml. This should only be triggered if something has gone wrong (i.e. overwriting values somewhere)
283+ raise ValueError (f"The '{ capability } ' capability does not have metric: '{ metric } '." )
284+
285+ if self .requirements [role_name ][capability ][metric ] > asset ['capabilities' ][capability ][metric ]: # check requirement is met
286+ return False , f"The asset does not have sufficient '{ metric } ' for '{ capability } ' capability in '{ role_name } ' role of '{ self .name } ' action."
287+
288+ return True , 'All capabilities in role met'
222289
223290 else :
224- return False # at least one capability is not met
225-
226- return True
227-
291+ return False , f"The asset does not have the '{ capability } ' capability for '{ role_name } ' role of '{ self .name } ' action." # a capability is not met
292+
228293
229294 def assignAsset (self , role_name , asset ):
230- '''Assigns a vessel or port to a certain role in the action.
231-
232- Parameters
233- ----------
295+ '''
296+ Assigns a vessel or port to a certain role in the action.
297+
298+ Inputs
299+ ------
234300 role_name : string
235301 Name of the asset role being filled (must be in the action's list)
236302 asset : Vessel or Port object
237303 The asset to be registered with the class.
304+
305+ Returns
306+ -------
307+ None
238308 '''
239309
240310 # Make sure role_name is valid for this action
241311 if not role_name in self .assets .keys ():
242312 raise Exception (f"The specified role name '{ role_name } ' is not a named asset role in this action." )
243313
244- if self .checkAsset (role_name , asset ):
314+ assignable , message = self .checkAsset (role_name , asset )
315+ if assignable :
245316 self .assets [role_name ] = asset
246317 else :
247- raise Exception (f"The asset does not have the capabilities for role ' { role_name } '." )
318+ raise Exception (message ) # throw error message
248319
249320
250321 def calcDurationAndCost (self ):
251- '''The structure here is dependent on actions.yaml.
322+ '''
323+ Calculates duration and cost for the action. The structure here is dependent on actions.yaml.
252324 TODO: finish description
325+
326+ Inputs
327+ ------
328+ None
329+
330+ Returns
331+ -------
332+ None
253333 '''
254334
255335 print ('Calculating duration and cost for action:' , self .name )
@@ -305,13 +385,19 @@ def calcDurationAndCost(self):
305385
306386
307387 def evaluateAssets (self , assets ):
308- '''Check whether an asset can perform the task, and if so calculate
388+ '''
389+ Check whether an asset can perform the task, and if so calculate
309390 the time and cost associated with using those assets.
310-
391+
392+ Inputs
393+ ------
311394 assets : dict
312- Dictionary of role_name, asset object pairs for assignment to the action.
313- Each asset is a vessel or port object.
314-
395+ Dictionary of {role_name: asset} pairs for assignment of the
396+ assets to the roles in the action.
397+
398+ Returns
399+ -------
400+ None
315401 '''
316402
317403 # error check that assets is a dict of {role_name, asset dict}, and not just an asset dict?
@@ -330,23 +416,53 @@ def evaluateAssets(self, assets):
330416 # ----- Below are drafts of methods for use by the engine -----
331417 """
332418 def begin(self):
333- '''Take control of all objects'''
419+ '''
420+ Take control of all objects.
421+
422+ Inputs
423+ ------
424+ None
425+
426+ Returns
427+ -------
428+ None
429+ '''
334430 for vessel in self.vesselList:
335431 vessel._attach_to(self)
336432 for object in self.objectList:
337433 object._attach_to(self)
338434
339435
340436 def end(self):
341- '''Release all objects'''
437+ '''
438+ Release all objects.
439+
440+ Inputs
441+ ------
442+ None
443+
444+ Returns
445+ -------
446+ None
447+ '''
342448 for vessel in self.vesselList:
343449 vessel._detach_from()
344450 for object in self.objectList:
345451 object._detach_from()
346452 """
347453
348454 def timestep (self ):
349- '''Advance the simulation of this action forward one step in time.'''
455+ '''
456+ Advance the simulation of this action forward one step in time.
457+
458+ Inputs
459+ ------
460+ None
461+
462+ Returns
463+ -------
464+ None
465+ '''
350466
351467 # (this is just documenting an idea for possible future implementation)
352468 # Perform the hourly action of the task
0 commit comments