Node Attribute Functions
CSL supports the following functions related to node attributes. The use of these functions is illustrated in Examples, below.
getAttributeValue(op, attributeName)
Returns, as a string, the value of the attribute named attributeName for the node op, if the attribute exists; returns null otherwise.
getAttributeValueAsBoolean(op, attributeName)
Returns, as a Boolean, the value of the attribute named attributeName for the node op, if the attribute exists; returns false otherwise.
getAttributeValueAsNumber(op, attributeName)
Returns, as a number, the value of the attribute named attributeName for the node op, if the attribute exists; returns 0.0 otherwise.
getNodeInTree(op, attributeName)
This function searches the process routing or operation sequence in which op occurs, as well as the ancestors of op in the process-operation hierarchy (see Hierarchies). The function returns a node with the specified attribute, if there is one, and returns null otherwise.
Note that the search includes optional nodes, regardless of whether they are active in the process routing or operation sequence. To determine if an optional node is active, check the value of its inclusionStatus property (see InclusionStatus and Examples).
Note that a process routing or operation sequence is a template instantiation (see Hierarchies), and so is potentially tree structured. The function searches all the nodes in that tree. The function also searches ancestors of op in the process-operation hierarchy; so, for example, if op is a Bending operation on a SimpleHole child of a MultistepHole, the function checks the parent operation node, MultistepHolemaking, as well as all the nodes in the SimpleHole’s operation sequence.
hasAttribute(op, attributeName)
Returns true if the node op has an attribute named attributeName; returns false otherwise.
hasNodeInTree(op, attributeName)
This function searches the process routing or operation sequence in which op occurs. It returns true if any node in the routing or sequence has the attribute with the specified name; it returns false otherwise.
Note that the search includes optional nodes, regardless of whether they are active in the process routing or operation sequence. To determine if an optional node is active, check the value of its inclusionStatus property (see InclusionStatus and Examples).
hasNodeInTreeWithTrueValue(op, attributeName)
This function searches the process routing or operation sequence in which op occurs. It returns true if any node in the routing or sequence has the attribute with the specified name and that attribute evaluates to true; it returns false otherwise.
Note that the search includes optional nodes, regardless of whether they are active in the process routing or operation sequence. To determine if an optional node is active, check the value of its inclusionStatus property (see InclusionStatus and Examples).
Examples
Following is an example of checking a simple hole to see if its operation sequence includes a hole finishing operation. The check is performed by feasibility modules of primary holemaking operations. If a finishing operation is included in the sequence, feasibility doesn’t require that the primary holemaking operation be capable of achieving, by itself, the GCD’s desired tolerance. (The library function IsProcessAllGtolCapable2() tests whether the primary operation alone can achieve the required tolerance.)
Note that optional nodes always return true when you use hasNodeInTree(), regardless of whether they are ultimately evaluated. To determine if an optional node is active, use getNodeInTree() to retrieve the node in question, and then check the value of its inclusionStatus property, as in the example below.
IsProcessAllGtolCapable(gcd, process) = {
true if not(gcd.isAnyToleranceSpecified)
true if hasAttribute(op, 'primaryHolemakingOp') and _
(safeEval(getNodeInTree( op, 'SimpleHoleFinishing' ).inclusionStatus, _
null) == InclusionStatus.AUTO_INCLUDE or _
safeEval(getNodeInTree( op, 'SimpleHoleFinishing' ).inclusionStatus, _
null) == InclusionStatus.USER_INCLUDE)
true if hasAttribute(op, 'primaryGtolOp') and _
(safeEval(getNodeInTree( op, 'FinishGrinding' ).inclusionStatus, _
null) == InclusionStatus.AUTO_INCLUDE or _
safeEval(getNodeInTree( op, 'FinishGrinding' ).inclusionStatus, _
null) == InclusionStatus.USER_INCLUDE)
IsProcessAllGtolCapable2(gcd, process) otherwise }
 
The following example illustrates working with parent/child GCD relationships. It considers a child Planar Face of a Ring, and uses getNodeInTree() to check whether heat treatment is included in the component’s routing (the parent’s parent’s process routing). This approach also works with basic getAttributeValue() functions.
(safeEval( _
getNodeInTree( _
op.parentArtifactResult.parentArtifactResult, _
'heatTreatProcess' ).inclusionStatus, _
null) == InclusionStatus.AUTO_INCLUDE or _
safeEval( _
getNodeInTree( _
op.parentArtifactResult.parentArtifactResult, _
'heatTreatProcess').inclusionStatus, _
null) == InclusionStatus.USER_INCLUDE)
 
The following example is used in Casting, and is related to yields. aPriori starting point models assume that any parts scrapped within the Casting process group (that is, within a casting foundry) can be remelted. So the starting point calculates two different versions of final yield. One is based on the number of parts scrapped both within Casting and by any secondary processes (this is used to calculate overhead costs for Casting). The other is based on the number of parts scrapped outside of the foundry, that is, by secondary processes only (this is used to calculate material cost in Casting).
The code below checks to see if the node in question has the inFoundryProcess attribute, which indicates that the process occurs within the Casting foundry (where scrapped parts are remelted).
 
set {
global.numScrapPartsDownStream = {
numScrapParts if safeEval(global.numScrapPartsDownStream, null) == null
numScrapParts + global.numScrapPartsDownStream otherwise }
      
global.numScrapPartsOutsideFoundry = {
_LEAVE_UNCHANGED_ if hasAttribute( op, 'inFoundryProcess' )
numScrapParts if safeEval(global.numScrapPartsOutsideFoundry, null) == null
numScrapParts + global.numScrapPartsOutsideFoundry otherwise }
}
The following example illustrates how to populate Machining custom outputs that support the display of total times for holemaking, roughing, and finishing. Each machining operation is tagged with the node attribute operationCategory whose values is Roughing, Finishing, or Holemaking. The library libCustomProcessOutputs.csl runs through all the operation cycle times and categorizes them based on the operation category.
 
ca_totalSurfaceFinishingOperations3 = _
select sum(op.formulaResults.cycleTime) from allSetupOps op where _
op.formulaResults.cycleTime != null and _
getAttributeValue( op, 'operationCategory' ) == 'Finishing'
 
Following is an example that uses a node attribute to tag an operation so that other operations can determine whether the tagged operation is present in the current operation sequence. This example checks whether a Simple Hole has been previously threaded, where other processes in the routing that perform threading are tagged with the node attribute PreviouslyThreaded. You'll find this attribute on operations such as Simple Hole Tapping in Progressive Die.
 
Rule IsThisThreaded: gcd.threaded == true and _
not(hasNodeInTree(op, 'PreviouslyThreaded'))
 
Message IsThisThreaded: _
'This hole is unthreaded or threaded by a prior operation'
 
The following example uses getNodeInTree() together with getAttributeValue() to check a machining operation sequence for the presence of a finishing operation:
 
foo = getNodeInTree(op, 'operationCategory')
 
Rule foo: getAttributeValue(foo, 'operationCategory') == 'Finishing'
 
Note that if there are multiple nodes with the specified attribute, getNodeInTree() returns only the first one.