214 lines
84 KiB
XML
214 lines
84 KiB
XML
<?xml version="1.1" encoding="UTF-8"?>
|
|
<xmi:XMI xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:OCLConstraints="http://www.ikv.de/OCLConstraints.ecore">
|
|
<OCLConstraints:Constraint xmi:id="_27zdAI5bEd-ROOssltGSNA" description="Checks if for each safety goal at least one functional safety requirement is specified (ISO 26262-3 8.4.2.2)" message="Safety Goal {1} has no functional safety requirement specified" constraintExpression="inv:
let
MessageArg1:String= self.identifier
in
self.targetRelations->exists(rel|rel.source.oclIsTypeOf(SafetyRequirement) and rel.source.oclAsType(SafetyRequirement).kind= safetygoals::SafetyReqKind::FUNCTIONAL)" mediniIdentifier="0003">
|
|
<target xmi:id="_27zdAY5bEd-ROOssltGSNA" class="safetygoals::SafetyGoal"/>
|
|
</OCLConstraints:Constraint>
|
|
<OCLConstraints:Constraint xmi:id="_STSLgI5cEd-ROOssltGSNA" severity="WARNING" description="Checks that each Hazard model is traced to an item" message="{0} Hazard has no item traced" constraintExpression="inv:
self.mediniGetTracedElements(PlainItem)->notEmpty()
" mediniIdentifier="0013">
|
|
<target xmi:id="_STSLgY5cEd-ROOssltGSNA" class="hazard::HazardAnalysisModel"/>
|
|
</OCLConstraints:Constraint>
|
|
<OCLConstraints:Constraint xmi:id="_cAD0sEvLEeC8vaXAN0jU6Q" description="Checks if every safety requirement has an unique identifier (ISO 26262-8 6.4.2.5 a)" message="The requirement ''{1}'' has no unique identifier" constraintExpression="inv:
let
MessageArg1:String= self.identifier
in
if ((not self.identifier.oclIsUndefined()) and (self.identifier<>'')) then	
		safetygoals::SafetyRequirement.allInstances()->one(element|element.identifier = self.identifier)
else
	true
endif" mediniIdentifier="0005">
|
|
<target xmi:id="_cAD0sUvLEeC8vaXAN0jU6Q" class="safetygoals::SafetyRequirement"/>
|
|
</OCLConstraints:Constraint>
|
|
<OCLConstraints:Constraint xmi:id="_yUb1sEvLEeC8vaXAN0jU6Q" description="Checks if every hazardous event has an unique identifier" message="The ''{0}'' has no (unique) identifier" constraintExpression="inv:
if ((not self.id.oclIsUndefined()) and (self.id<>'')) then
	hazard::HazardousEvent.allInstances()->one(element|element.id = self.id)
else
	false
endif" mediniIdentifier="0033">
|
|
<target xmi:id="_yUb1sUvLEeC8vaXAN0jU6Q" class="hazard::HazardousEvent"/>
|
|
</OCLConstraints:Constraint>
|
|
<OCLConstraints:Constraint xmi:id="_zsMS0EvLEeC8vaXAN0jU6Q" description="Checks if every function has an unique identifier" message="The ''{0}'' has no (unique) identifier" constraintExpression="inv:
if self.typeCode ='function' then	
		if ((not self.id.oclIsUndefined()) and (self.id<>'')) then
				 sysml::SysMLActivity.allInstances()->one(element|element.typeCode ='function' and element.id = self.id)
		else
			false
		endif
else
	true
endif" mediniIdentifier="0034">
|
|
<target xmi:id="_zsMS0UvLEeC8vaXAN0jU6Q" class="sysml::SysMLActivity"/>
|
|
</OCLConstraints:Constraint>
|
|
<OCLConstraints:Constraint xmi:id="_1CKnQEvLEeC8vaXAN0jU6Q" description="Checks if every malfunction has an unique identifier" message="The ''{0}'' has no (unique) identifier" constraintExpression="inv:
if ((not self.id.oclIsUndefined()) and (self.id<>'')) then
		 safetyModel::Malfunction.allInstances()->one(element|element.id = self.id)
else
	false
endif" mediniIdentifier="0035">
|
|
<target xmi:id="_1CKnQUvLEeC8vaXAN0jU6Q" class="safetyModel::Malfunction"/>
|
|
</OCLConstraints:Constraint>
|
|
<OCLConstraints:Constraint xmi:id="_2NGwYEvLEeC8vaXAN0jU6Q" severity="WARNING" description="Checks if every FMEA worksheet has an unique number" message="The ''{0}'' has no (unique) number" constraintExpression="inv:
if ((not self.fmeaNumber.oclIsUndefined()) and (self.fmeaNumber<>'')) then
	FMEA::FMEAWorksheet.allInstances()->one(element|element.fmeaNumber = self.fmeaNumber)
else
	false
endif" mediniIdentifier="0036">
|
|
<target xmi:id="_2NGwYUvLEeC8vaXAN0jU6Q" class="FMEA::FMEAWorksheet"/>
|
|
</OCLConstraints:Constraint>
|
|
<OCLConstraints:Constraint xmi:id="_4S5_QEvLEeC8vaXAN0jU6Q" description="Checks that voting gates have at least as much inputs as the threshold set" message="Number of inputs for ''{0}'' is less than its threshold set" constraintExpression="inv:
not (self.inputs.outputNode->
	collect(node|
		if node.oclIsTypeOf(fta::EventNode) then
			node.oclAsType(fta::EventNode).event
		else
			node
		endif
	)->asSet()->size()<self.threshold)" mediniIdentifier="0037">
|
|
<target xmi:id="_4S5_QUvLEeC8vaXAN0jU6Q" class="FTA::VotingGate"/>
|
|
</OCLConstraints:Constraint>
|
|
<OCLConstraints:Constraint xmi:id="_5p61gEvLEeC8vaXAN0jU6Q" description="Checks that transfer gates have a target set" message="The ''{0}'' has no target set" constraintExpression="inv:
not self.targetEventNode.oclIsUndefined()" mediniIdentifier="0038">
|
|
<target xmi:id="_5p61gUvLEeC8vaXAN0jU6Q" class="FTA::TransferGate"/>
|
|
</OCLConstraints:Constraint>
|
|
<OCLConstraints:Constraint xmi:id="_7eubAEvLEeC8vaXAN0jU6Q" description="Checks that voting gates do not have threshold of zero" message="The threshold of zero for ''{0}'' is not allowed" constraintExpression="inv:
self.threshold<>0" mediniIdentifier="0039">
|
|
<target xmi:id="_7eubAUvLEeC8vaXAN0jU6Q" class="FTA::VotingGate"/>
|
|
</OCLConstraints:Constraint>
|
|
<OCLConstraints:Constraint xmi:id="_Pum5oDo1EeSM7dc93wKcuw" severity="WARNING" description="Checks for components with failure rate 0.0" message="The ''{0}'' has failure rate 0.0" constraintExpression="inv:
if self.oclIsTypeOf(FMEA::Component) then
	-- detached FMEA
	self.failureRate<>0.0
else
 -- ignore as this is already reported by constraint #42 
 -- if	 self.element.oclIsTypeOf(sysml::SysMLPart) or self.element.oclIsKindOf(sysml::SysMLBlock) or self.element.oclIsKindOf(sysml::SysMLPort) or self.element.oclIsKindOf(sysml::SysMLPortUsage) then
		-- derived FMEA
	--	self.element.oclAsType(sysml::SysMLElement).failureRate<>0.0
	--	else
	--		true
	--	endif
	true -- added as reply
endif" mediniIdentifier="0043">
|
|
<target xmi:id="_Pum5oTo1EeSM7dc93wKcuw" class="FMEA::ComponentEntry"/>
|
|
</OCLConstraints:Constraint>
|
|
<OCLConstraints:Constraint xmi:id="_zOwkALIVEeCQYIKxeQ-Alw" severity="INFO" description="Checks that for every checked task in a checklist a reviewer is set." message="There is a checked task in checklist {1} which misses a reviewer." constraintExpression="-- determine the checklist
def: getChecklist(item:ChecklistItem):Checklist
	= if item.eContainer().oclIsUndefined() then
			null -- not in a resource
		else
			if item.eContainer().oclIsKindOf(Checklist) then
				item.eContainer().oclAsType(Checklist) -- found the containing checklist
			else
				if item.eContainer().oclIsKindOf(ChecklistItem) then
					getChecklist(item.eContainer().oclAsType(ChecklistItem))
				else
					null -- unknown container type
				endif
			endif
		endif

inv:
let
	checklist:Checklist = getChecklist(self),
	MessageArg1:String = if checklist.oclIsUndefined() then 'unknown' else checklist.name endif
in
if (self.checked) then
	not (self.checkedBy.oclIsUndefined()) and not (self.checkedBy.trim().isEmpty())
else 
	true
endif" mediniIdentifier="0026">
|
|
<target xmi:id="_zOwkAbIVEeCQYIKxeQ-Alw" class="checklist::ChecklistItem"/>
|
|
</OCLConstraints:Constraint>
|
|
<OCLConstraints:Constraint xmi:id="_dxTDJtq1EeCu8-fFdTERtg" description="Checks if each safety related hazardous event has a safety goal assigned (ISO 26262-3 7.4.4.3)" message="The ''{0}'' is safety related and has no safety goal assigned" constraintExpression="inv:
let
	isoAsil:String= self.integrityLevel,
	safetyGoal:safetygoals::SafetyGoal = self.getProfilePropertyValue('ISO26262_safetyGoal')->first().oclAsType(safetygoals::SafetyGoal)
in
	if (not isoAsil.oclIsUndefined()) then
		-- we cannot check for ASIL enum value 'None' here because its literal has been changed to empty string and the engine queries the enum by its literal
		(if isoAsil = 'A' or isoAsil = 'B' or isoAsil = 'C' or isoAsil = 'D' then
			not (safetyGoal.oclIsUndefined())
		else
			true
		endif)
	else
		true
	endif" mediniIdentifier="0002">
|
|
<target xmi:id="_dxTDJ9q1EeCu8-fFdTERtg" class="hazard::HazardousEvent"/>
|
|
</OCLConstraints:Constraint>
|
|
<OCLConstraints:Constraint xmi:id="_dxTDL9q1EeCu8-fFdTERtg" description="Checks that classification of severity (ISO 26262-3 7.4.3.2), exposure (ISO 26262-3 7.4.3.4) and controllability (ISO 26262-3 7.4.3.7) have a justifications given" message="{0} has no justification given for the estimated classification of: {1}" constraintExpression="--util to append 
def:
	append(value:String, suffix: String):String
	=	if value<>'' then
			if suffix<>'' then
				value .concat( ', ').concat(suffix)
			else
				value
			endif
		else
			suffix
		endif

-- util to check comment	
def:
	check(comment:String, message:String):String
	=	if comment.oclIsUndefined() then
			message
		else
			if comment.trim()='' then
				message
			else
				''
			endif
		endif
inv:
let
	exposureComment:String = self.getProfilePropertyValue('ISO26262_exposureComment')->first().oclAsType(String),
	severityComment:String = self.getProfilePropertyValue('ISO26262_severityComment')->first().oclAsType(String),
	controllabilityComment:String = self.getProfilePropertyValue('ISO26262_controllabilityComment')->first().oclAsType(String),
	defaultExposureComment:String = self.operationalSituation.getProfilePropertyValue('ISO26262_defaultExposureComment')->first().oclAsType(String),
	val1:String= check(severityComment, 'severity'),
	val2:String =append(val1,if exposureComment.oclIsUndefined() then
								check(defaultExposureComment, 'exposure')
							else
								if exposureComment.trim()='' then
									check(defaultExposureComment, 'exposure')
								else
									''
								endif
							endif),
	MessageArg1:String= append(val2,check(controllabilityComment, 'controllability'))
in
	if not self.integrityLevel.oclIsUndefined() then
		MessageArg1=''
	else
		true
	endif

" mediniIdentifier="0010">
|
|
<target xmi:id="_dxTDMNq1EeCu8-fFdTERtg" class="hazard::HazardousEvent"/>
|
|
</OCLConstraints:Constraint>
|
|
<OCLConstraints:Constraint xmi:id="_dxTDQdq1EeCu8-fFdTERtg" description="Checks if every safety goal has an unique identifier (ISO 26262-8 6.4.2.5 a)" message="The safety goal ''{1}'' has no unique identifier" constraintExpression="inv:
let
MessageArg1:String= self.identifier
in
if ((not self.identifier.oclIsUndefined()) and (self.identifier<>'')) then
		 safetygoals::SafetyGoal.allInstances()->one(element|element.identifier = self.identifier)
else
	true
endif" mediniIdentifier="0032">
|
|
<target xmi:id="_dxTDQtq1EeCu8-fFdTERtg" class="safetygoals::SafetyGoal"/>
|
|
</OCLConstraints:Constraint>
|
|
<OCLConstraints:Constraint xmi:id="__rEBgG0GEeG_ushRuE058g" description="Checks if for each decomposed safety requirement an independence argument requirement is specified" message="Decomposed requirement {1} has no independence argument requirement specified" constraintExpression="inv:
let
MessageArg1:String= self.identifier
in
if(self.subRequirements->exists(sub|sub.oclIsTypeOf(SafetyRequirement) and sub.oclAsType(SafetyRequirement).decomposingRequirement= true)) then
	self.targetRelations->exists(rel|rel.source.oclIsTypeOf(SafetyRequirement) and rel.oclAsType(SafetyReqRelation).kind= SafetyReqRelationKind::INDEPENDENCY)
else
	true
endif" mediniIdentifier="0049">
|
|
<target xmi:id="__rEBgW0GEeG_ushRuE058g" class="safetygoals::SafetyRequirement"/>
|
|
</OCLConstraints:Constraint>
|
|
<OCLConstraints:Constraint xmi:id="_cpBWBDloEeK6Vagv30244g" severity="WARNING" description="Checks that no decomposing requirement is allocated to the same system model or software element as its neighbor" message="The decomposing requirement {1} is allocated to the same system model or software element as its neighbor" constraintExpression="inv:
let
MessageArg1:String= self.identifier
in
if self.decomposingRequirement and self.container.oclIsKindOf(safetygoals::SafetyRequirement) then
	let
		neighbors:Set(SafetyRequirement)= self.container.oclAsType(safetygoals::SafetyRequirement).getDecomposingRequirements(false,false)->excluding(self)->asSet()
	in
		if neighbors->isEmpty() then
			true
		else
			let
				selfSWElements:Bag(Structure::SimulinkNamedElement)=self.mediniGetTracedElements(Structure::SimulinkNamedElement)->asBag(),
				selfHWElements:Bag(sysml::SysMLElement)=self.mediniGetTracedElements(sysml::SysMLElement)->asBag(),
				-- collect elements allocated to neighbors of self		
				swElements:Bag(Structure::SimulinkNamedElement)=neighbors->collect(element|element.mediniGetTracedElements(Structure::SimulinkNamedElement))->asBag(),
				hwElements:Bag(sysml::SysMLElement)=neighbors->collect(element|element.mediniGetTracedElements(sysml::SysMLElement))->asBag()
			in		
				selfSWElements->intersection(swElements)->isEmpty() and	selfHWElements->intersection(hwElements)->isEmpty()
		endif		
else
	true
endif
" mediniIdentifier="0016">
|
|
<target xmi:id="_cpBWBTloEeK6Vagv30244g" class="safetygoals::SafetyRequirement"/>
|
|
</OCLConstraints:Constraint>
|
|
<OCLConstraints:Constraint xmi:id="_cpBWCjloEeK6Vagv30244g" description="Checks if each system model element has a name set (except for connectors and dependencies)" message="{0} has no name set" constraintExpression="inv:
if (self.oclIsKindOf(SysMLFailable) and not (self.oclIsKindOf(SysMLConnector)))
	or self.oclIsKindOf(SysMLContainerPackage)
then
	self.name<>''
else
	true
endif" mediniIdentifier="0007">
|
|
<target xmi:id="_cpBWCzloEeK6Vagv30244g" class="sysml::SysMLElement"/>
|
|
</OCLConstraints:Constraint>
|
|
<OCLConstraints:Constraint xmi:id="_cpBWDTloEeK6Vagv30244g" description="Checks if each system model port is connected" message="{0} is not connected" constraintExpression="inv:
self.end->exists(x | x.oclIsTypeOf(EUML::Generic::CompositeStructures::UMLConnectorEnd))
" mediniIdentifier="0008">
|
|
<target xmi:id="_cpBWDjloEeK6Vagv30244g" class="sysml::SysMLFlowPortUsage"/>
|
|
</OCLConstraints:Constraint>
|
|
<OCLConstraints:Constraint xmi:id="_OIEZoDo1EeSM7dc93wKcuw" severity="WARNING" description="Checks for hardware parts with failure rate 0.0" message="The ''{0}'' has failure rate 0.0" constraintExpression="inv:
	self.typeCode <> 'Hardware Part' or self.failureRate<>0.0" mediniIdentifier="0042">
|
|
<target xmi:id="_OIEZoTo1EeSM7dc93wKcuw" class="sysml::SysMLPart"/>
|
|
</OCLConstraints:Constraint>
|
|
<OCLConstraints:Constraint xmi:id="_cpBWIjloEeK6Vagv30244g" description="Checks that system model elements have independence comment if independence flag is set" message="No independence comment given for {0}" constraintExpression="inv:
let
	info:safetyModel::SafetyInformation= self.safetyInformation
in
	if not info.oclIsUndefined() then
		info.independent implies (not info.independenceComment.oclIsUndefined() and info.independenceComment<>'')
	else
		true
	endif" mediniIdentifier="0047">
|
|
<target xmi:id="_cpBWIzloEeK6Vagv30244g" class="sysml::SysMLElement"/>
|
|
</OCLConstraints:Constraint>
|
|
<OCLConstraints:Constraint xmi:id="_m_uDw2xjEeK8N_FfTXiZgA" severity="WARNING" description="Checks that all worksheets do have at least on safety goal defined" message="{0} has no safety goal defined" constraintExpression="inv:
self.safetyGoal->exists(goal|goal.oclIsTypeOf(safetygoals::SafetyGoal))
" mediniIdentifier="0050">
|
|
<target xmi:id="_m_uDxGxjEeK8N_FfTXiZgA" class="dc::DCWorksheet"/>
|
|
</OCLConstraints:Constraint>
|
|
<OCLConstraints:Constraint xmi:id="_gsAu19UCEeKAJpTEiBQAAQ" description="Checks if a valid decomposition has been applied (ISO 26262-9 5.4.10)" message="Requirement {1} is not correctly decomposed" constraintExpression="def: isQM(asil : String): Boolean = asil.trim().matches('QM(\\((A|B|C|D)\\))?')
def: isA(asil : String): Boolean = asil.trim().matches('A(\\((A|B|C|D)\\))?')
def: isB(asil : String): Boolean = asil.trim().matches('B(\\((B|C|D)\\))?')
def: isC(asil : String): Boolean = asil.trim().matches('C(\\((C|D)\\))?')
def: isD(asil : String): Boolean = asil.trim().matches('D(\\((D)\\))?')

def: isLower(first : String,second: String): Boolean =
	( (first = 'D') implies (false) ) and
	( (first = 'C') implies (second = 'D') ) and
	( (first = 'B') implies (second = 'C' or second = 'D') ) and
	( (first = 'A') implies (second = 'B' or second = 'C' or second = 'D') ) and
	( (first = 'QM') implies (second = 'A' or second = 'B' or second = 'C' or second = 'D') ) and
	( (first = 'NONE') implies (true) )

def: isHigherOrEqual(first: String, second: String): Boolean =
		( (first = second) or ( isLower(second,first) ) )
def: getAsilContext(asil : String): String = if
	asil.trim().matches('QM\\((A|B|C|D)\\)') then
			asil.trim().substring(4,4)
	else if asil.trim().matches('A\\((A|B|C|D)\\)') or asil.trim().matches('B\\((B|C|D)\\)') or asil.trim().matches('C\\((C|D)\\)') or asil.trim().matches('D\\((D)\\)') then
			asil.trim().substring(3,3)
		else
			'NONE'
		endif
	endif

inv:
let
	decompositions:Bag(SafetyRequirement)= self.getDecomposingRequirements(false,false)->asBag(), 
	number:Integer=decompositions->size(),
 MessageArg1:String= self.identifier

in
	if number = 0 then
		true
	else if number = 2 then	
			let
				asils:Bag(String)=decompositions->collect(a|a.asil),
				notAll_QM:Boolean= not asils->forAll(a| isQM(a)),
				notAll_A:Boolean= not asils->forAll(a|isA(a)),
				notA_and_QM:Boolean= not (asils->one(a|isQM(a)) and asils->one(a|isA(a))),
				notB_and_QM:Boolean= not (asils->one(a|isQM(a)) and asils->one(a|isB(a))),
				notC_and_QM:Boolean= not (asils->one(a|isQM(a)) and asils->one(a|isC(a))),
				notB_and_A:Boolean= not (asils->one(a|isB(a)) and asils->one(a|isA(a))),
				asilContext:String = getAsilContext(self.asil)
			in --check ASIL decompositions rules
				(isA(self.asil) implies	(notAll_QM))
			and
				(isB(self.asil) implies	(notAll_QM and notA_and_QM))
			and
				(isC(self.asil) implies (notAll_QM and notA_and_QM and notB_and_QM and notAll_A))
			and
				(isD(self.asil) implies (notAll_QM and notA_and_QM and notB_and_QM and notAll_A and notC_and_QM and notB_and_A))
			and if (not (asilContext = 'NONE')) then
					asils->forAll(asil | isHigherOrEqual(getAsilContext(asil),asilContext) )
				 else
					asils->forAll(asil | isHigherOrEqual(getAsilContext(asil),self.asil) )
				endif
	else
		false
	endif
	endif
	" mediniIdentifier="0009">
|
|
<target xmi:id="_gsAu2NUCEeKAJpTEiBQAAQ" class="safetygoals::SafetyRequirement"/>
|
|
</OCLConstraints:Constraint>
|
|
<OCLConstraints:Constraint xmi:id="_gsAu2tUCEeKAJpTEiBQAAQ" description="Checks that the ASIL of a hazardous event matches the ASIL of an associated goal (ISO 26262-3 7.4.4.4)" message="The ASIL of ''{0}'' does not match to ASIL of associated goal" constraintExpression="inv:
let
	safetyGoal:safetygoals::SafetyGoal = self.getProfilePropertyValue('ISO26262_safetyGoal')->first().oclAsType(safetygoals::SafetyGoal)
in

if (not (safetyGoal.oclIsUndefined())) then
	let
		hazardAsil:String=self.integrityLevel,
		goalAsil:String=safetyGoal.integrityLevel
	in	
		(hazardAsil = 'A' implies (goalAsil ='A' or goalAsil ='B' or goalAsil ='C' or goalAsil ='D')) and
		(hazardAsil = 'B' implies (goalAsil ='B' or goalAsil ='C' or goalAsil ='D')) and 
		(hazardAsil = 'C' implies (goalAsil ='C' or goalAsil ='D')) and
		(hazardAsil = 'D' implies goalAsil ='D') or
		hazardAsil = '' or
		hazardAsil.oclIsUndefined()
else
	true
endif
	" mediniIdentifier="0012">
|
|
<target xmi:id="_gsAu29UCEeKAJpTEiBQAAQ" class="hazard::HazardousEvent"/>
|
|
</OCLConstraints:Constraint>
|
|
<OCLConstraints:Constraint xmi:id="_gsAu3dUCEeKAJpTEiBQAAQ" description="Checks if safety requirements have the same or higher ASIL than of goals they contribute to" message="Safety requirement {1} has an invalid ASIL. ASIL has to be the same or higher than of goals it contributes to." constraintExpression="def: isQM(asil : String): Boolean = asil.trim().matches('QM(\\((A|B|C|D)\\))?')
def: isA(asil : String): Boolean = asil.trim().matches('A(\\((A|B|C|D)\\))?')
def: isC(asil : String): Boolean = asil.trim().matches('C(\\((C|D)\\))?')
def: isD(asil : String): Boolean = asil.trim().matches('D(\\((D)\\))?')
inv:
let
	goalContributions:Set(goal::Relation)=self.sourceRelations->select(rel| rel.oclIsKindOf(SafetyReqRelation) and rel.oclAsType(SafetyReqRelation).kind = SafetyReqRelationKind::UNSPECIFIED and rel.target.oclIsKindOf(SafetyGoal)),
	targets:Bag(SafetyGoal)= goalContributions->collect(rel| rel.target),
 MessageArg1:String= self.identifier

in
	targets->forAll(target|	((target.asil='D') implies (isD(self.asil)))
		and
			((target.asil= 'C') implies ((isC(self.asil)) or (isD(self.asil))))
		and
			((target.asil= 'B') implies ((not isA(self.asil)) and (not isQM(self.asil))))
		and
			((target.asil= 'A') implies ((not isQM(self.asil))))
	)

" mediniIdentifier="0014">
|
|
<target xmi:id="_gsAu3tUCEeKAJpTEiBQAAQ" class="safetygoals::SafetyRequirement"/>
|
|
</OCLConstraints:Constraint>
|
|
<OCLConstraints:Constraint xmi:id="_gsAu4NUCEeKAJpTEiBQAAQ" severity="WARNING" description="Checks that decomposition does not increase ASIL" message="Decompositions of requirement {1} increase ASIL" constraintExpression="def: isQM(asil : String): Boolean = asil.trim().matches('QM(\\((A|B|C|D)\\))?')
def: isA(asil : String): Boolean = asil.trim().matches('A(\\((A|B|C|D)\\))?')
def: isB(asil : String): Boolean = asil.trim().matches('B(\\((B|C|D)\\))?')
def: isC(asil : String): Boolean = asil.trim().matches('C(\\((C|D)\\))?')
def: isD(asil : String): Boolean = asil.trim().matches('D(\\((D)\\))?')
def: getAsilContext(asil : String): String = if
	asil.trim().matches('QM\\((A|B|C|D)\\)') then
			asil.trim().substring(4,4)
	else if asil.trim().matches('A\\((A|B|C|D)\\)') or asil.trim().matches('B\\((B|C|D)\\)') or asil.trim().matches('C\\((C|D)\\)') or asil.trim().matches('D\\((D)\\)') then
			asil.trim().substring(3,3)
		else
			'NONE'
		endif
	endif
def: isLower(first : String,second: String): Boolean =
	( (first = 'D') implies (false) ) and
	( (first = 'C') implies (second = 'D') ) and
	( (first = 'B') implies (second = 'C' or second = 'D') ) and
	( (first = 'A') implies (second = 'B' or second = 'C' or second = 'D') ) and
	( (first = 'QM') implies (second = 'A' or second = 'B' or second = 'C' or second = 'D') ) and
	( (first = 'NONE') implies (true) )

inv:
let
	decompositions:Bag(SafetyRequirement)= self.getDecomposingRequirements(false,false)->asBag(), 
	number:Integer=decompositions->size(),
	asils:Bag(String)=decompositions->collect(a|a.asil),
	asilContext:String = getAsilContext(self.asil),
	MessageArg1:String= self.identifier

in
	if number = 1 or number = 2 then	
			( ( isQM(self.asil) ) implies ( asils->forAll(asil|isQM(asil)) ) )
		and 
			( ( isA(self.asil) ) implies ( (asils->one(asil|isA(asil)) or
																asils->exists(asil|isQM(asil)))
													and not asils->exists(asil|isB(asil) or isC(asil) or isD(asil)) ) )
		and
			( ( isB(self.asil) ) implies ( ((asils->one(asil|isB(asil)) xor asils->exists(asil|isA(asil))) or
																asils->exists(asil|isQM(asil)))
													and not asils->exists(asil|isC(asil) or isD(asil)) ) )
		and
			( ( isC(self.asil) ) implies ( ((asils->one(asil|isC(asil)) xor (asils->one(asil|isB(asil)) or asils->exists(asil|isA(asil)))) or
																asils->exists(asil|isQM(asil)))
													and not asils->exists(asil|isD(asil)) ) )
		and ( ( isD(self.asil) ) implies ( (asils->one(asil|isD(asil)) xor asils->one(asil|isC(asil) or isB(asil) or isA(asil))) or
																(asils->forAll(asil|isB(asil))) or
																(asils->exists(asil|isA(asil)) and not asils->exists(asil|isD(asil))) or
																asils->exists(asil|isQM(asil)) ) )
		and ( if not( asilContext = 'NONE' ) then
				 asils->forAll(asil| (asilContext = getAsilContext(asil)) or (isLower(getAsilContext(asil),asilContext)) ) 
					else
				 asils->forAll(asil| (self.asil = getAsilContext(asil)) or (isLower(getAsilContext(asil),self.asil)) ) 
					endif
				)
	else
		true -- does not check general decomposition rules 
	endif

" mediniIdentifier="0022">
|
|
<target xmi:id="_gsAu4dUCEeKAJpTEiBQAAQ" class="safetygoals::SafetyRequirement"/>
|
|
</OCLConstraints:Constraint>
|
|
<OCLConstraints:Constraint xmi:id="_gsAu49UCEeKAJpTEiBQAAQ" description="Checks if safety requirements have the same or higher ASIL than of requirements they contribute, also as independency argument, to" message="Requirement {2} has an invalid ASIL. ASIL has to be the same or higher than of requirement(s): {1}" constraintExpression="def: isQM(asil : String): Boolean = asil.trim().matches('QM(\\((A|B|C|D)\\))?')
def: isA(asil : String): Boolean = asil.trim().matches('A(\\((A|B|C|D)\\))?')
def: isB(asil : String): Boolean = asil.trim().matches('B(\\((B|C|D)\\))?')
def: isC(asil : String): Boolean = asil.trim().matches('C(\\((C|D)\\))?')
def: isD(asil : String): Boolean = asil.trim().matches('D(\\((D)\\))?')

-- this function returns the asil context ; example ;QM(A) returns A, B(D) returns D
def: getAsilContext(asil : String): String = if
	asil.trim().matches('QM\\((A|B|C|D)\\)') then
			asil.trim().substring(4,4)
	else if ( asil.trim().matches('A\\((A|B|C|D)\\)') or asil.trim().matches('B\\((B|C|D)\\)') or asil.trim().matches('C\\((C|D)\\)') or asil.trim().matches('D\\((D)\\)') ) then
			asil.trim().substring(3,3)
		else
			'NONE'
		endif
	endif
	
-- this function checks which asil is lower ;if first is lower it returns true
def: isLower(first : String,second: String): Boolean =
	( (first = 'D') implies (false) ) and
	( (first = 'C') implies (second = 'D') ) and
	( (first = 'B') implies (second = 'C' or second = 'D') ) and
	( (first = 'A') implies (second = 'B' or second = 'C' or second = 'D') ) and
	( (first = 'QM') implies (second = 'A' or second = 'B' or second = 'C' or second = 'D') ) and
	( (first = 'NONE') implies (second = 'A' or second = 'B' or second = 'C' or second = 'D' or second='QM') )
	
-- this function is resturns first asil example; QM(B) returns QM, A(D) return A
def: getRawAsil(asil : String): String = if
	asil.trim().matches('QM\\((A|B|C|D)\\)') then
		'QM'
	else if ( asil.trim().matches('A\\((A|B|C|D)\\)') or asil.trim().matches('B\\((B|C|D)\\)') or asil.trim().matches('C\\((C|D)\\)') or asil.trim().matches('D\\((D)\\)') ) then
			asil.trim().substring(1,1)
		else
			'NONE'
		endif
	endif
	
def: hasSameRawAsil(first : String,second:String): Boolean =
	if ( getRawAsil(first)=getRawAsil(second))then
		true
	else
		false
	endif
	
-- this function is checking val matches with any of these combinations QM(A|B|C|D) or A(A|B|C|D) or B(B|C|D) or C(C|D) or D(D)
def:isContextAsil(val:String):Boolean = if (val.trim().matches('QM\\((A|B|C|D)\\)') or val.trim().matches('A\\((A|B|C|D)\\)') or val.trim().matches('B\\((B|C|D)\\)') or val.trim().matches('C\\((C|D)\\)') or val.trim().matches('D\\((D)\\)') ) then
			true
		else
			false
		endif

-- checking asil is lower for source or target with context combinations; example ( QM(B),A(B) ) or ( D, A(B) )
def: isLowerWithContext(source:String,target:String):Boolean=
				if(isContextAsil(source)) then
					if(isContextAsil(target)) then						
						if(hasSameRawAsil(source,target)) then
							isLower(getAsilContext(source),getAsilContext(target))
						else 
							isLower(getRawAsil(source),getRawAsil(target))
						endif						
					else					
						isLower(getRawAsil(source),target)
					endif
				else
					if(isContextAsil(target)) then		
						 not isLower(getRawAsil(target),source)
					else
						isLower(source,target)
					endif
				endif

inv:
let
	reqContributions:Bag(entities::Relation)=self.sourceRelations->select(rel| rel.oclIsKindOf(SafetyReqRelation) and (rel.oclAsType(SafetyReqRelation).kind = SafetyReqRelationKind::UNSPECIFIED or rel.oclAsType(SafetyReqRelation).kind = SafetyReqRelationKind::INDEPENDENCY) and rel.target.oclIsKindOf(SafetyRequirement)),
	targets:Bag(SafetyRequirement)= reqContributions->collect(rel| rel.target),		
	MessageArg1:Bag(String)= targets->select(target| isLowerWithContext(self.asil,target.asil) ).identifier,
	MessageArg2:String= self.identifier

in
MessageArg1->isEmpty()


" mediniIdentifier="0029">
|
|
<target xmi:id="_gsAu5NUCEeKAJpTEiBQAAQ" class="safetygoals::SafetyRequirement"/>
|
|
</OCLConstraints:Constraint>
|
|
<OCLConstraints:Constraint xmi:id="_gsAu5tUCEeKAJpTEiBQAAQ" description="Checks if sub requirements have the same or higher ASIL than of its parent" message="Requirement {1} has an invalid ASIL. ASIL of sub requirement has to be the same or higher than of its parent." constraintExpression="def: isD(asil : String): Boolean = asil.trim().matches('D(\\((D)\\))?')
def: isC(asil : String): Boolean = asil.trim().matches('C(\\((C|D)\\))?')
def: isQM(asil : String): Boolean = asil.trim().matches('QM(\\((A|B|C|D)\\))?')
def: isA(asil : String): Boolean = asil.trim().matches('A(\\((A|B|C|D)\\))?')
def: isB(asil : String): Boolean = asil.trim().matches('B(\\((B|C|D)\\))?')
inv:
let
	parent:safetygoals::SafetyRequirement=self.container,
	MessageArg1:String= self.identifier
in
	if not self.decomposingRequirement and not parent.oclIsUndefined() and parent.oclIsKindOf(SafetyRequirement) then
			((isD(parent.oclAsType(SafetyRequirement).asil)) implies (isD(self.asil)))
		and
			((isC(parent.oclAsType(SafetyRequirement).asil)) implies ((isC(self.asil)) or (isD(self.asil))))
		and
			((isB(parent.oclAsType(SafetyRequirement).asil)) implies ((not isA(self.asil)) and (not isQM(self.asil))))
		and
			((isA(parent.oclAsType(SafetyRequirement).asil)) implies ((not isQM(self.asil))))
	else
		true
	endif

" mediniIdentifier="0030">
|
|
<target xmi:id="_gsAu59UCEeKAJpTEiBQAAQ" class="safetygoals::SafetyRequirement"/>
|
|
</OCLConstraints:Constraint>
|
|
<OCLConstraints:Constraint xmi:id="_gsAu6dUCEeKAJpTEiBQAAQ" description="Checks that ASIL of system model element is same or higher than required by its requirements (ISO 26262-4 7.4.2.2)" message="ASIL of {0} is lower than required by its requirements" constraintExpression="inv:
let
	info:safetyModel::SafetyInformation=self.safetyInformation,
	reqs:Sequence(traceability::Trace)=self.mediniGetTracedElements(safetygoals::SafetyRequirement)
in
	-- only parts, port usages, and functions/activities support ASIL
	if (self.oclIsKindOf(sysml::SysMLPart) or self.oclIsKindOf(sysml::SysMLFlowPortUsage) or self.oclIsKindOf(sysml::SysMLActivity)) and (not info.oclIsUndefined()) then
		not reqs->exists(req|info.compareAsil(req.oclAsType(safetygoals::SafetyRequirement).asil)<0)
	else
		true
	endif
" mediniIdentifier="0048">
|
|
<target xmi:id="_gsAu6tUCEeKAJpTEiBQAAQ" class="sysml::SysMLElement"/>
|
|
</OCLConstraints:Constraint>
|
|
<OCLConstraints:Constraint xmi:id="_gsAu7NUCEeKAJpTEiBQAAQ" description="Checks that metric target values fit to highest ASIL of worksheet's goals." message="Metric target values for {0} does not fit to highest ASIL of worksheet's goals." constraintExpression="inv:
let
	asils:OrderedSet(String)= self.safetyGoal->select(goal|goal.oclIsTypeOf(safetygoals::SafetyGoal))->collect(goal|goal.oclAsType(safetygoals::SafetyGoal).asil)
in
	-- for individual metrics we don't care the target values set at the worksheet
	 self.individualMetrics or asils->forAll(asil|
		((asil='B') implies self.spfTargetValue>=90.0 and self.lmpfTargetValue>=60.0) and		
		((asil='C') implies self.spfTargetValue>=97.0 and self.lmpfTargetValue>=80.0) and		
		((asil='D') implies self.spfTargetValue>=99.0 and self.lmpfTargetValue>=90.0)
	)" mediniIdentifier="0051">
|
|
<target xmi:id="_gsAu7dUCEeKAJpTEiBQAAQ" class="dc::DCWorksheet"/>
|
|
</OCLConstraints:Constraint>
|
|
<OCLConstraints:Constraint xmi:id="_gsAu79UCEeKAJpTEiBQAAQ" severity="WARNING" description="Checks that contribution does not increase ASIL" message="Requirement {2} increases ASIL. ASIL should be the same than of requirement(s): {1}" constraintExpression="def: isQM(asil : String): Boolean = asil.trim().matches('QM(\\((A|B|C|D)\\))?')
def: isA(asil : String): Boolean = asil.trim().matches('A(\\((A|B|C|D)\\))?')
def: isB(asil : String): Boolean = asil.trim().matches('B(\\((B|C|D)\\))?')
def: isC(asil : String): Boolean = asil.trim().matches('C(\\((C|D)\\))?')
def: isD(asil : String): Boolean = asil.trim().matches('D(\\((D)\\))?')

-- this function returns the asil context ; example ;QM(A) returns A, B(D) returns D
def: getAsilContext(asil : String): String = if
	asil.trim().matches('QM\\((A|B|C|D)\\)') then
			asil.trim().substring(4,4)
	else if ( asil.trim().matches('A\\((A|B|C|D)\\)') or asil.trim().matches('B\\((B|C|D)\\)') or asil.trim().matches('C\\((C|D)\\)') or asil.trim().matches('D\\((D)\\)') ) then
			asil.trim().substring(3,3)
		else
			'NONE'
		endif
	endif
	
-- this function checks which asil is lower ;if first is lower it returns true
def: isHigher(first : String,second: String): Boolean =
( (first = 'D') implies (second = 'C' or second = 'B' or second = 'A' or second = 'QM' or second = 'NONE') ) and
( (first = 'C') implies ( second = 'B' or second = 'A' or second = 'QM' or second = 'NONE') ) and
( (first = 'B') implies ( second = 'A' or second = 'QM' or second = 'NONE') ) and
( (first = 'A') implies ( second = 'QM' or second = 'NONE') ) and
( (first = 'QM') implies ( second = 'NONE') ) and
( (first = 'NONE') implies false)	
	
-- this function is resturns first asil example; QM(B) returns QM, A(D) return A
def: getRawAsil(asil : String): String = if
	asil.trim().matches('QM\\((A|B|C|D)\\)') then
		'QM'
	else if ( asil.trim().matches('A\\((A|B|C|D)\\)') or asil.trim().matches('B\\((B|C|D)\\)') or asil.trim().matches('C\\((C|D)\\)') or asil.trim().matches('D\\((D)\\)') ) then
			asil.trim().substring(1,1)
		else
			'NONE'
		endif
	endif
	
def: hasSameRawContext(first : String,second:String): Boolean =
	if ( getRawAsil(first)=getRawAsil(second))then
		true
	else
		false
	endif
	
-- this function is checking val matches with any of these combinations QM(A|B|C|D) or A(A|B|C|D) or B(B|C|D) or C(C|D) or D(D)
def:isConextAsil(val:String):Boolean = if (val.trim().matches('QM\\((A|B|C|D)\\)') or val.trim().matches('A\\((A|B|C|D)\\)') or val.trim().matches('B\\((B|C|D)\\)') or val.trim().matches('C\\((C|D)\\)') or val.trim().matches('D\\((D)\\)') ) then
			true
		else
			false
		endif

-- checking asil is lower for source or target with context combinations; example ( QM(B),A(B) ) or ( D, A(B) )
def: isASILIncreased(source:String,target:String):Boolean=
				if(isConextAsil(source)) then
					if(isConextAsil(target)) then						
						if(hasSameRawContext( source,target)) then
							isHigher(getAsilContext(source),getAsilContext(target))
						else 
							if	isHigher(getRawAsil(source),getRawAsil(target)) then
								true
							else
						 		isHigher(getAsilContext(source),getAsilContext(target))				
						 		endif					 
						endif						
					else					
						isHigher(getAsilContext(source),target)
					endif
				else
					if(isConextAsil(target)) then		
						isHigher(source,getAsilContext(target))	
					else
						isHigher(source,target)
					endif
				endif

inv:
let
	reqContributions:Bag(entities::Relation)=self.sourceRelations->select(rel| rel.oclIsKindOf(SafetyReqRelation) and (rel.oclAsType(SafetyReqRelation).kind = SafetyReqRelationKind::UNSPECIFIED or rel.oclAsType(SafetyReqRelation).kind = SafetyReqRelationKind::INDEPENDENCY) and rel.target.oclIsKindOf(SafetyRequirement)),
	targets:Bag(SafetyRequirement)= reqContributions->collect(rel| rel.target),		
	MessageArg1:Bag(String)= targets->select(target| isASILIncreased(self.asil,target.asil) ).identifier,
 MessageArg2:String= self.identifier
in
MessageArg1->isEmpty()


" mediniIdentifier="0052">
|
|
<target xmi:id="_gsAu8NUCEeKAJpTEiBQAAQ" class="safetygoals::SafetyRequirement"/>
|
|
</OCLConstraints:Constraint>
|
|
<OCLConstraints:Constraint xmi:id="_0WtFNDo2EeOmV9sq6aLt0Q" description="Checks that failure rate distributions add to 100.0% for each system model element" message="The failure rate distribution percentages for the failure modes of {0} do not add to 100.0%. Value is: {1}" constraintExpression="inv:
if self.oclIsTypeOf(sysml::SysMLPart) or self.oclIsTypeOf(sysml::SysMLFlowPort) or self.oclIsTypeOf(sysml::SysMLFlowPortUsage) or self.oclIsTypeOf(sysml::SysMLBlock) then
	let
		permanentFailures:Bag(safetyModel::FailureMode) = self.failures->collect(f|f.oclAsType(safetyModel::FailureMode))->select(f:safetyModel::FailureMode|f.failureType = safetyModel::FailureType::PERMANENT)
	in
	if not permanentFailures->isEmpty() and self.failureRateMode <> safetyModel::FailureRateMode::FROM_FAILURE_MODES and self.failureRate <> 0 then
		let
		 total :Real =permanentFailures.failureRateDistribution->iterate(p:Real; sum:Real=0.0|sum+p),
	 	 var :Real = 100 - total,	
		 MessageArg1 :Real = 
	 		if var.abs() <= 0.00001 then
		 		100
			else
			 total
			endif
		in
		MessageArg1=100.0		
	else 
		true
	endif
else
true
endif" mediniIdentifier="0024">
|
|
<target xmi:id="_0WtFNTo2EeOmV9sq6aLt0Q" class="sysml::SysMLElement"/>
|
|
</OCLConstraints:Constraint>
|
|
<OCLConstraints:Constraint xmi:id="_qISGAQIJEeqWudVttih-0g" severity="WARNING" description="Checks for events with zero probability due to a zero failure rate at an element" message="The ''{0}'' has zero probability due to a zero failure rate at an element" constraintExpression="inv:
if not self.probabilityData.oclIsUndefined() then
	-- probability is derived
	if self.probabilityData.oclIsKindOf(FTA::TimeDependentProbabilityModel) then
		let
			data:FTA::TimeDependentProbabilityModel = self.probabilityData.oclAsType(FTA::TimeDependentProbabilityModel)
		in
			if data.lambdaDerived then
				-- check failure rate provider
				if self.represents.oclIsUndefined() then
					false
				else
					if self.represents.oclIsKindOf(sysml::SysMLElement) then
						self.represents.oclAsType(sysml::SysMLElement).failureRate<>0.0
					else
						if self.represents.oclIsKindOf(FMEA::PlainFailureMode) then
							self.represents.oclAsType(FMEA::PlainFailureMode).failureRate<>0.0
						else
							if self.represents.oclIsKindOf(safetyModel::FailureMode) then
								self.represents.oclAsType(safetyModel::FailureMode).failureRate<>0.0
							else
								true
							endif
						endif
					endif
				endif
			else
				data.lambda<>0.0
			endif
	else
		true
	endif
else
	true
endif" mediniIdentifier="0044">
|
|
<target xmi:id="_qISGAgIJEeqWudVttih-0g" class="FTA::Event"/>
|
|
</OCLConstraints:Constraint>
|
|
<OCLConstraints:Constraint xmi:id="_T_3yjgwqEeSW27aUFfiZXA" description="FTA models should not contain loops" message="FTA connection is part of a loop" constraintExpression="inv:
not self.isInLoop()" mediniIdentifier="0015">
|
|
<target xmi:id="_T_3yjwwqEeSW27aUFfiZXA" class="FTA::Connection"/>
|
|
</OCLConstraints:Constraint>
|
|
<OCLConstraints:Constraint xmi:id="_T_3ykQwqEeSW27aUFfiZXA" severity="WARNING" description="Checks whether there are events with the same id." message="There are events with same id as ''{0}''." constraintExpression="inv:
-- ignore all events in Analysis model
if (not self.id.oclIsUndefined() and (self.id<>'')) and ( not self.eContainer().oclIsKindOf(AnalysisModel)) then
 	FTA::EventNode.allInstances()->select(event|not event.eContainer().oclIsKindOf(AnalysisModel))->select(event|event.id=self.id).event->asSet()->size()<=1
else
	true
endif" mediniIdentifier="0031">
|
|
<target xmi:id="_T_3ykgwqEeSW27aUFfiZXA" class="FTA::EventNode"/>
|
|
</OCLConstraints:Constraint>
|
|
<OCLConstraints:Constraint xmi:id="_FKlSkLOJEeSmb_XB5NxHYg" description="Check whether each event in the fault tree is connected to a gate or another event" message="{0} is an unconnected event" constraintExpression="inv: self.outputs->size()>0 or self.transferGates->size() >0 or self.effectiveKind = FTA::EventType::TOP_LEVEL" mediniIdentifier="0102">
|
|
<target xmi:id="_FKlSkrOJEeSmb_XB5NxHYg" class="FTA::EventNode"/>
|
|
</OCLConstraints:Constraint>
|
|
<OCLConstraints:Constraint xmi:id="_mNpjgLOMEeSmb_XB5NxHYg" description="Checks that either all failure modes of a FMEDA component have category 'no part' or none" message="{0} has failure mode with category 'no part' and failure modes with other categories." constraintExpression="inv:
if self.failureModes->isEmpty() then
 	true
else
 	if self.oclIsTypeOf(FMEA::Component) then -- detached FMEA
		-- either all or no failure mode with category 'no part'
 		if self.failureModes->exists(fm|fm.oclAsType(FMEA::PlainFailureMode).failureCategory = safetyModel::FailureCategory::NoPart) then 
	 		self.failureModes->forAll(fm| fm.oclAsType(FMEA::PlainFailureMode).failureCategory = safetyModel::FailureCategory::NoPart)
		else
			true
		endif 
	else -- derived FMEA
		let
			-- only interested in failure modes
			effectiveFailureModes:Sequence(safetyModel::FailureMode) = self.failureModes->select(entry|entry.element.oclIsKindOf(safetyModel::FailureMode))->collect(entry|entry.element.oclAsType(safetyModel::FailureMode))
		in
			-- either all or no failure mode with category 'no part'
			if effectiveFailureModes->exists(fm|fm.failureCategory = safetyModel::FailureCategory::NoPart) then
	 			effectiveFailureModes->forAll(fm|fm.failureCategory = safetyModel::FailureCategory::NoPart)
			else
				true
			endif 
		endif
endif
" mediniIdentifier="0011">
|
|
<target xmi:id="_mNpjgbOMEeSmb_XB5NxHYg" class="FMEA::ComponentEntry"/>
|
|
</OCLConstraints:Constraint>
|
|
<OCLConstraints:Constraint xmi:id="_Qjat4LObEeSmb_XB5NxHYg" description="Check that each gate has at least one input" message="Gate {0} has no input" constraintExpression="inv: self.inputs->size()>0" mediniIdentifier="0103">
|
|
<target xmi:id="_Qjat4bObEeSmb_XB5NxHYg" class="FTA::LogicalGate"/>
|
|
</OCLConstraints:Constraint>
|
|
<OCLConstraints:Constraint xmi:id="_4Zz-sLOcEeSmb_XB5NxHYg" description="Check whether each gate in the FTA is connected towards the top-level event" message="{0} is unconnected " constraintExpression="inv: self.outputs->size()>0" mediniIdentifier="0101">
|
|
<target xmi:id="_4Zz-sbOcEeSmb_XB5NxHYg" class="FTA::Gate"/>
|
|
</OCLConstraints:Constraint>
|
|
<OCLConstraints:Constraint xmi:id="_Eq2DILjaEeS27qiRpL-hCQ" description="Checks that ASIL of system model element is same or higher than ASIL of parent unless system model element has independence flag set (ISO 26262-4 7.4.2.3)" message="ASIL for {0} is lower than required by its parent " constraintExpression="inv:
let
	info:safetyModel::SafetyInformation=self.safetyInformation,
	container:de::ikv::medini::kernel::MediniObject=self.mediniGetContainer()
	
in
	-- only parts, port usages, and functions/activities support ASIL
	if ((self.oclIsKindOf(sysml::SysMLPart) or self.oclIsKindOf(sysml::SysMLFlowPortUsage) or self.oclIsKindOf(sysml::SysMLActivity)) and self.typeCode<>'Characteristic' and not info.oclIsUndefined()) then
		if (not info.independent) and (not container.oclIsUndefined()) then
			if container.oclIsKindOf(sysml::SysMLElement) and not container.mediniGetContainer().oclIsUndefined() then
				-- model does not have ASIL
				if not container.oclAsType(sysml::SysMLElement).safetyInformation.oclIsUndefined() then
					info.compareAsil(container.oclAsType(sysml::SysMLElement).safetyInformation)>=0
				else
					true
				endif
			else
				true
			endif
		else
			true
		endif
	else
		true
	endif
" mediniIdentifier="0046">
|
|
<target xmi:id="_Eq2DIbjaEeS27qiRpL-hCQ" class="sysml::SysMLElement"/>
|
|
</OCLConstraints:Constraint>
|
|
<OCLConstraints:Constraint xmi:id="_5CxcQBaGEeazA6MyomEVow" description="Checks that all hardware metrics worksheets which calculate individual metrics have at least one safety goal assigned" message="''{0}'' calculates individual metrics but has no goal assigned" constraintExpression="inv:
(not self.individualMetrics) or (self.safetyGoal->notEmpty())" mediniIdentifier="0053">
|
|
<target xmi:id="_5CxcQRaGEeazA6MyomEVow" class="dc::DCWorksheet"/>
|
|
</OCLConstraints:Constraint>
|
|
<OCLConstraints:Constraint xmi:id="_5CyqYBaGEeazA6MyomEVow" description="Checks that sibling failure entries for the same failure modes have disjoint evaluated goal selections" message="''{0}'' has safety goals selected for evaluation which are also selected for sibling for same failure mode" constraintExpression="-- returns all siblings for the same element (including self)
def: getSiblings(): Collection(dc::DCFailureModeEntry)
	= self.component.failureModes->select(fe|fe.oclIsKindOf(dc::DCFailureModeEntry) and fe.element = self.element)->collect(fe|fe.oclAsType(dc::DCFailureModeEntry))

inv:
	-- selected goals must be disjoint, empty selection means all
	getSiblings()->forAll(first, second|(first <> second) implies (
		let
			firstSelectedGoals:Set(ecore::EObject) = first.evaluatedFor,
			secondSelectedGoals:Set(ecore::EObject) = second.evaluatedFor
		in
			firstSelectedGoals->notEmpty() and secondSelectedGoals->notEmpty() and firstSelectedGoals->intersection(secondSelectedGoals)->isEmpty()
		)
	)" mediniIdentifier="0054">
|
|
<target xmi:id="_5CyqYRaGEeazA6MyomEVow" class="dc::DCFailureModeEntry"/>
|
|
</OCLConstraints:Constraint>
|
|
<OCLConstraints:Constraint xmi:id="_5Cz4gBaGEeazA6MyomEVow" description="Checks that component entries are marked as safety related only for safety goals the worksheet is analyzing" message="''{0}'' is safety related for safety goals which are not configured for the hardware metrics worksheet" constraintExpression="inv:
	self.safetyRelated or self.worksheet.oclAsType(dc::DCWorksheet).safetyGoal->includesAll(self.safetyRelatedFor)" mediniIdentifier="0055">
|
|
<target xmi:id="_5Cz4gRaGEeazA6MyomEVow" class="dc::DCComponentEntry"/>
|
|
</OCLConstraints:Constraint>
|
|
<OCLConstraints:Constraint xmi:id="_5C0fkBaGEeazA6MyomEVow" description="Checks that failure entries are evaluated only for safety goals the component is safety related for" message="''{0}'' is evaluated for safety goals which are not configured safety related for the component" constraintExpression="inv:
	self.evaluatedFor->isEmpty() or 
		let
			component:dc::DCComponentEntry = self.component.oclAsType(dc::DCComponentEntry)
		in
			if component.safetyRelated then
				component.worksheet.oclAsType(dc::DCWorksheet).safetyGoal->includesAll(self.evaluatedFor)
			else
				component.safetyRelatedFor->includesAll(self.evaluatedFor)
			endif" mediniIdentifier="0056">
|
|
<target xmi:id="_5C0fkRaGEeazA6MyomEVow" class="dc::DCFailureModeEntry"/>
|
|
</OCLConstraints:Constraint>
|
|
<OCLConstraints:Constraint xmi:id="_5C1tsBaGEeazA6MyomEVow" description="Checks that failure entries have only safety mechanisms selected which are also configured for the corresponding failure mode" message="''{0}'' has safety mechanisms selected which are not configured for the corresponding failure mode" constraintExpression="inv:
		self.element.oclAsType(safetyModel::FailureMode).spfSafetyMechanisms->includesAll(self.spfSafetyMechanisms)
	and
		self.element.oclAsType(safetyModel::FailureMode).mpfSafetyMechanisms->includesAll(self.lmpfSafetyMechanisms)" mediniIdentifier="0057">
|
|
<target xmi:id="_5C1tsRaGEeazA6MyomEVow" class="dc::DCFailureModeEntry"/>
|
|
</OCLConstraints:Constraint>
|
|
<OCLConstraints:Constraint xmi:id="_PkIWwKprEea2d5K9aLHs9Q" description="Checks if each safety goal with ASIL C or ASIL D has a FTA traced (ISO 26262-4 7.4.3.1)" message="Safety Goal {1} has no FTA traced" constraintExpression="inv:
let
MessageArg1:String= self.identifier
in
if (self.asil='C' or self.asil='D') then
 -- any FTA model, event (node), gate, connection traced?
 not (self.mediniGetTracedElements(FTA::FTAElement)->isEmpty() and self.mediniGetTracedElements(FTA::EventNode)->isEmpty())
else
	true
endif
" mediniIdentifier="0004">
|
|
<target xmi:id="_PkIWwaprEea2d5K9aLHs9Q" class="safetygoals::SafetyGoal"/>
|
|
</OCLConstraints:Constraint>
|
|
<OCLConstraints:Constraint xmi:id="_SWQgIKprEea2d5K9aLHs9Q" severity="WARNING" description="Checks for valid failure mode detection coverage wrt. safety mechanisms." message="Too high failure mode coverage for {2} given for ''{0}'' wrt. its safety mechanisms." constraintExpression="--context dc::DCFailureModeEntry

	
def:
	doGetMaxDC(maxDC:Real, mechanisms: Sequence(safetyModel::SafetyMechanism)):Real
	= 	if maxDC >= 99.0 or mechanisms->isEmpty() then
			maxDC
		else
			let
				mechanism:safetyModel::SafetyMechanism= mechanisms->first(),
				dcValue:Real=
					if mechanism.oclIsKindOf(safetyModel::SafetyMechanism) then
						let
							theDC:safetyModel::DCCoverage= mechanism.oclAsType(safetyModel::SafetyMechanism).maxDC
						in
							if theDC=safetyModel::DCCoverage::LOW then
								60.0
							else
								if theDC=safetyModel::DCCoverage::MEDIUM then
									90.0
								else
									if theDC=safetyModel::DCCoverage::HIGH then
										99.0
									else
										100.0 -- case NONE
									endif	
								endif					
							endif
					else
						100.0
					endif
				in
					if mechanisms->size()>=2 then
						doGetMaxDC(maxDC.max(dcValue), mechanisms->subSequence(2,mechanisms->size()))
					else
						maxDC.max(dcValue)
					endif
		endif
		
def:
	getMaxDC(mechanisms:Sequence(safetyModel::SafetyMechanism)):Real
	= doGetMaxDC(0.0, mechanisms)

inv:
let
	failureMode:safetyModel::FailureMode= self.element.oclAsType(safetyModel::FailureMode)
in
 if failureMode.failureType = safetyModel::FailureType::TRANSIENT
 then
 true
 else
	let
		maxSPFDC:Real= self.getMaxDC(failureMode.spfSafetyMechanisms->asSequence()),
		maxLFDC:Real= self.getMaxDC(failureMode.mpfSafetyMechanisms->asSequence()),
		MessageArg1:String= if maxSPFDC<self.spfCoverage then 'single-point failure' else '' endif,
		MessageArg2:String= if maxLFDC<self.lmpfCoverage then
						if MessageArg1<>'' then
							MessageArg1.concat(' and latent failure') -- append
						else
							'latent failure'
						endif
					 else
						MessageArg1
					 endif
	in
	MessageArg2=''
endif" mediniIdentifier="0040">
|
|
<target xmi:id="_SWQgIaprEea2d5K9aLHs9Q" class="dc::DCFailureModeEntry"/>
|
|
</OCLConstraints:Constraint>
|
|
<OCLConstraints:Constraint xmi:id="_XEgX8KprEea2d5K9aLHs9Q" description="Checks that for every checked task in a checklist a check date is set." message="A checked task in checklist {1} misses a properly set checking date." constraintExpression="-- determine the checklist
def: getChecklist(item:ChecklistItem):Checklist
	= if item.eContainer().oclIsUndefined() then
			null -- not in a resource
		else
			if item.eContainer().oclIsKindOf(Checklist) then
				item.eContainer().oclAsType(Checklist) -- found the containing checklist
			else
				if item.eContainer().oclIsKindOf(ChecklistItem) then
					getChecklist(item.eContainer().oclAsType(ChecklistItem))
				else
					null -- unknown container type
				endif
			endif
		endif

inv:
let
	checklist:Checklist = getChecklist(self),
	MessageArg1:String = if checklist.oclIsUndefined() then 'unknown' else checklist.name endif
in
if (self.checked) then
	self.isDateValid()
else 
	true
endif" mediniIdentifier="0027">
|
|
<target xmi:id="_XEgX8aprEea2d5K9aLHs9Q" class="checklist::ChecklistItem"/>
|
|
</OCLConstraints:Constraint>
|
|
<OCLConstraints:Constraint xmi:id="_bqXIwKprEea2d5K9aLHs9Q" severity="INFO" description="Checks that checklist tasks have model artifact assigned in case the corresponding checklist template has assigned artifact types for this task." message="There is a checked task in checklist {1} which has no model artifacts assigned although the corresponding checklist template says so." constraintExpression="-- determine the checklist
def: getChecklist(item:ChecklistItem):Checklist
	= if item.eContainer().oclIsUndefined() then
			null -- not in a resource
		else
			if item.eContainer().oclIsKindOf(Checklist) then
				item.eContainer().oclAsType(Checklist) -- found the containing checklist
			else
				if item.eContainer().oclIsKindOf(ChecklistItem) then
					getChecklist(item.eContainer().oclAsType(ChecklistItem))
				else
					null -- unknown container type
				endif
			endif
		endif

inv:
let
	checklist:Checklist = getChecklist(self),
	MessageArg1:String = if checklist.oclIsUndefined() then 'unknown' else checklist.name endif
in
if (self.checked and not self.artifactTypes->isEmpty()) then
	not (self.artifacts->isEmpty())
else
	true
endif" mediniIdentifier="0028">
|
|
<target xmi:id="_bqXIwaprEea2d5K9aLHs9Q" class="checklist::ChecklistItem"/>
|
|
</OCLConstraints:Constraint>
|
|
<OCLConstraints:Constraint xmi:id="_Kg0yUMGBEeimSKDM1drJhw" severity="WARNING" description="Checks for parts with part number but no type assigned" message="{0} has a part number but no type is assigned" constraintExpression="inv:
if not ( self.partNumber = '' or self.partNumber.oclIsUndefined())
then 
 	not self.theType.oclIsUndefined()
 else
 true
 endif" mediniIdentifier="0108">
|
|
<target xmi:id="_Kg0yUcGBEeimSKDM1drJhw" class="sysml::SysMLPart"/>
|
|
</OCLConstraints:Constraint>
|
|
<OCLConstraints:Constraint xmi:id="_Lsla0MGBEeimSKDM1drJhw" description="Check that each HW Element Type has at least one failure mode" message="{0} has no failure modes defined." constraintExpression="inv:
self.failures->size() >0" mediniIdentifier="0109">
|
|
<target xmi:id="_Lsla0cGBEeimSKDM1drJhw" class="sysml::SysMLBlock"/>
|
|
</OCLConstraints:Constraint>
|
|
<OCLConstraints:Constraint xmi:id="_RXDDQMGBEeimSKDM1drJhw" description="Checks whether each part number is uniquely allocated to a single type" message="The partnumber {1} is duplicated." constraintExpression="inv:
let
MessageArg1:String= self.partNumber
in
if ((not self.partNumber.oclIsUndefined()) and (self.partNumber<>'')) then	
		sysml::SysMLBlock.allInstances()->one(element|element.partNumber = self.partNumber)
else
	true
endif" mediniIdentifier="0107">
|
|
<target xmi:id="_RXDDQcGBEeimSKDM1drJhw" class="sysml::SysMLBlock"/>
|
|
</OCLConstraints:Constraint>
|
|
<OCLConstraints:Constraint xmi:id="_bElfkMGBEeimSKDM1drJhw" severity="INFO" description="Checks whether each safety requirement is shown on a diagram" message="Requirement {1} is not shown on any diagram" constraintExpression="inv: 
let
MessageArg1:String= self.identifier
in
self.mediniGetOpposites('element')->exists(o|o.oclIsKindOf(notation::Node))" mediniIdentifier="0105">
|
|
<target xmi:id="_bElfkcGBEeimSKDM1drJhw" class="safetygoals::SafetyRequirement"/>
|
|
</OCLConstraints:Constraint>
|
|
<OCLConstraints:Constraint xmi:id="_cMlpcMGBEeimSKDM1drJhw" severity="INFO" description="Checks whether each SysML element is shown on a diagram" message="{0} is not shown on any diagram" constraintExpression="inv:
if (self.oclIsKindOf(SysMLFailable) and not (self.oclIsKindOf(SysMLConnector))
	and (self.failureRateMode <> safetyModel::FailureRateMode::FROM_CATALOG) -- to exclude HW parts from a BOM
	)
then 
	self.mediniGetOpposites('element')->exists(o|o.oclIsKindOf(notation::Node)) 
else
 	true
endif" mediniIdentifier="0106">
|
|
<target xmi:id="_cMlpccGBEeimSKDM1drJhw" class="sysml::SysMLElement"/>
|
|
</OCLConstraints:Constraint>
|
|
<OCLConstraints:Constraint xmi:id="_zikkkALAEem9sJSEURFe6A" description="Check whether each hazardous event with a safety goal also is associated to a malfunction" message="{0} has a safety goal but no associated malfunction" constraintExpression="inv:
let
	safetyGoal:safetygoals::SafetyGoal = self.getProfilePropertyValue('ISO26262_safetyGoal')->first().oclAsType(safetygoals::SafetyGoal)
in

(not (safetyGoal.oclIsUndefined())) implies self.malfunctions->size()>0" mediniIdentifier="0113">
|
|
<target xmi:id="_zikkkQLAEem9sJSEURFe6A" class="hazard::HazardousEvent"/>
|
|
</OCLConstraints:Constraint>
|
|
<OCLConstraints:Constraint xmi:id="_1lbNIALAEem9sJSEURFe6A" description="Check whether each hazardous event with a safety goal also is associated to a hazard " message="{0} has a safety goal but no associated hazard" constraintExpression="inv:
let
	safetyGoal:safetygoals::SafetyGoal = self.getProfilePropertyValue('ISO26262_safetyGoal')->first().oclAsType(safetygoals::SafetyGoal)
in

(not (safetyGoal.oclIsUndefined())) implies not self.hazard.oclIsUndefined()" mediniIdentifier="0112">
|
|
<target xmi:id="_1lbNIQLAEem9sJSEURFe6A" class="hazard::HazardousEvent"/>
|
|
</OCLConstraints:Constraint>
|
|
<OCLConstraints:Constraint xmi:id="_mIfIkALBEem9sJSEURFe6A" severity="WARNING" description="Check whether the hazard of this situation is used in the failure net of the related malfunction" message="{2}: Hazard "{3}" does not occur as top level effect in failure net for malfunction {1}" constraintExpression="inv:
let
 MessageArg1 : String = if self.malfunctions->size() > 0 then self.malfunctions->first().id else '' endif,
 MessageArg2 : String = self.id,
 MessageArg3 : String = self.hazard.name,
 tle:Sequence(safetyModel::Hazard) = self.malfunctions->first().oclAsType(safetyModel::Malfunction).getProfilePropertyValue('top_level_effect')
in
		not(self.hazard.oclIsUndefined()) implies tle->includes(self.hazard)

" mediniIdentifier="0111">
|
|
<target xmi:id="_mIfIkQLBEem9sJSEURFe6A" class="hazard::HazardousEvent"/>
|
|
</OCLConstraints:Constraint>
|
|
<OCLConstraints:Constraint xmi:id="_eDGfIMGBEeimSKDM1drJhw" description="Checks wether FTA element is shown on diagram" message="{0} is not shown on any diagram" constraintExpression="inv: self.mediniGetOpposites('element')->exists(o|o.oclIsKindOf(notation::Node))" mediniIdentifier="0104">
|
|
<target xmi:id="_eDGfIcGBEeimSKDM1drJhw" class="FTA::Node"/>
|
|
</OCLConstraints:Constraint>
|
|
<OCLConstraints:Constraint xmi:id="_j2eL8MGBEeimSKDM1drJhw" severity="INFO" description="Check whether there exists for each functional safety requirement a technical safety requirement." message="There is no technical safety requirement allocated to functional requirement {1}." constraintExpression="inv:
let
MessageArg1:String= self.identifier
in
if self.kind= safetygoals::SafetyReqKind::FUNCTIONAL
then
self.targetRelations->exists(rel|rel.source.oclIsTypeOf(SafetyRequirement) and rel.source.oclAsType(SafetyRequirement).kind= safetygoals::SafetyReqKind::TECHNICAL)
else
true
endif" mediniIdentifier="0100">
|
|
<target xmi:id="_j2eL8cGBEeimSKDM1drJhw" class="safetygoals::SafetyRequirement"/>
|
|
</OCLConstraints:Constraint>
|
|
<OCLConstraints:Constraint xmi:id="_M1IHIMibEeiciPcxq-kTYA" severity="WARNING" description="Check whether failure rate catalogs are used for the determination of failure rates" message="{0} is not using a failure rate catalog for the failure rate prediction" constraintExpression="inv:
 	self.partNumber<>'' implies self.failureRateMode = safetyModel::FailureRateMode::FROM_CATALOG

" mediniIdentifier="0110">
|
|
<target xmi:id="_M1IHIcibEeiciPcxq-kTYA" class="sysml::SysMLBlock"/>
|
|
</OCLConstraints:Constraint>
|
|
<OCLConstraints:Constraint xmi:id="_Y5wT4BiuEemhPYKw8yONPA" description="Checks that failure modes have unique names within the same scope" message="The ''{0}'' has no unique name" constraintExpression="def: uniqueFailureModeName(failure:FMEA::PlainFailureMode):Boolean = 
-- apply to failure modes that have a name set only
if ((not failure.name.oclIsUndefined()) and (failure.name <> '')) then
	-- apply to failure modes in detached FMEA sheets
	if (failure.mediniGetContainer().oclIsKindOf(FMEA::Component)) then
		let
			container:FMEA::Component = self.mediniGetContainer().oclAsType(FMEA::Component)
		in
			-- there must be only one failure mode with that name
			container.failureModes->one(element|
				if element.oclIsKindOf(FMEA::PlainFailureMode) then
					element.oclAsType(FMEA::PlainFailureMode).name = failure.name
				else
					false
				endif
			)
	else
		true
	endif
else
	true
endif

def: uniqueFailureModeName(failure:safetyModel::FailureMode):Boolean = 
-- apply to failure modes that have a name set only
if ((not failure.name.oclIsUndefined()) and (failure.name <> '')) then
	-- apply to failure modes in SysMLelements containers
	if (failure.mediniGetContainer().oclIsKindOf(sysml::SysMLElement)) then
		let
			container :sysml::SysMLElement= failure.mediniGetContainer().oclAsType(sysml::SysMLElement)
		in
			-- there must be only one failure mode with that name
			container.failures->one(element|element.name = failure.name)
	else
		true
	endif
else
	true
endif

inv:
if self.oclIsKindOf(FMEA::PlainFailureMode) then
	-- failure mode in detached FMEA
	uniqueFailureModeName(self.oclAsType(FMEA::PlainFailureMode))
else if self.element.oclIsKindOf(safetyModel::FailureMode) then
		-- failure mode refered from derived FMEA
		uniqueFailureModeName(self.element.oclAsType(safetyModel::FailureMode))
	else
		true		
	endif
endif

" mediniIdentifier="0041">
|
|
<target xmi:id="_Y5wT4RiuEemhPYKw8yONPA" class="FMEA::FailureEntry"/>
|
|
</OCLConstraints:Constraint>
|
|
<OCLConstraints:Constraint xmi:id="_ljkUEBiuEemhPYKw8yONPA" severity="WARNING" description="Checks for failure modes with failure rate 0.0" message="The ''{0}'' has failure rate 0.0" constraintExpression="inv:
if self.oclIsKindOf(FMEA::PlainFailureMode) then
	-- failure mode in detached FMEA 
		self.oclAsType(FMEA::PlainFailureMode).failureRate<>0.0
else if self.element.oclIsKindOf(safetyModel::FailureMode) then
		-- failure mode in derived FMEA
		if self.component.failureRate >0
		then
			self.element.oclAsType(safetyModel::FailureMode).failureRate<>0.0
		else
			true
		endif
	 else
	 	true
	 endif
endif" mediniIdentifier="0045">
|
|
<target xmi:id="_ljkUERiuEemhPYKw8yONPA" class="FMEA::FailureEntry"/>
|
|
</OCLConstraints:Constraint>
|
|
<OCLConstraints:Constraint xmi:id="_ekTegCR4Eem7IbokExUh5g" description="Check for consistency in direction and type of connected ports" message="Connector {0} between ports {1} and {2}: Mismatch in port direction and/or port type" constraintExpression="
def: parents(element:sysml::SysMLElement):Set(sysml::SysMLElement) =
	if not element.oclIsUndefined()
	then
		parents(element.the_owner.oclAsType(sysml::SysMLElement))->including(element)
	else
		Set{}
	endif
	
def: matches(dir1 : sysml::SysMLFlowPortUsage, dir2 :sysml::SysMLFlowPortUsage): Boolean = 
	if dir1.direction = sysml::SysMLFlowDirection::inout or dir2.direction = sysml::SysMLFlowDirection::inout
	then true 
	else 
	if not(dir2.the_owner = dir1.the_owner) and (parents(dir2.the_owner.oclAsType(sysml::SysMLElement))->includes(dir1.the_owner.oclAsType(sysml::SysMLElement))
	or parents(dir1.the_owner.oclAsType(sysml::SysMLElement))->includes(dir2.the_owner.oclAsType(sysml::SysMLElement)))
	then 
			dir1.direction = dir2.direction -- going inward
		else 
			dir1.direction <> dir2.direction 
		endif
	endif	
		
inv:
let
	source: sysml::SysMLFlowPortUsage = self.theConnectorEnd->first().role,
	target : sysml::SysMLFlowPortUsage = self.theConnectorEnd->last().role,
	MessageArg1 : String = source.name, 
	MessageArg2 : String = target.name 

in 
if
	source.oclIsTypeOf(sysml::SysMLFlowPortUsage) and target.oclIsTypeOf(sysml::SysMLFlowPortUsage)
then
	if
		not source.direction.oclIsUndefined() and not target.direction.oclIsUndefined()
		then 
			matches(source, target) and ((source.type = target.type) or (source.type.oclIsUndefined() or target.type.oclIsUndefined()) or (source.type ='' or target.type ='')) -- add also for oclUndefined and ''
		else
			true
		endif
else
	true
endif" mediniIdentifier="0114">
|
|
<target xmi:id="_ekTegSR4Eem7IbokExUh5g" class="sysml::SysMLConnector"/>
|
|
</OCLConstraints:Constraint>
|
|
<OCLConstraints:Constraint xmi:id="_Zhk4sPAREemxD416Z3DJbQ" severity="WARNING" description="Checks that the severity has been set or been derived." message="Invalid severity value 0 or no efffect for failure mode "{0}" constraintExpression="inv:
not self.element.oclIsTypeOf(dc::DCFailureModeEntry) implies
		if self.failureEffects->size()>0 
			then self.element.oclAsType(safetyModel::Failure).effectiveSeverity >0
		else
			true
		endif" mediniIdentifier="0115">
|
|
<target xmi:id="_Zhk4sfAREemxD416Z3DJbQ" class="FMEA::FailureEntry"/>
|
|
</OCLConstraints:Constraint>
|
|
<OCLConstraints:Constraint xmi:id="_98Yo0AuwEeqjYeKjV-7wuQ" description="Checks whether correct detection/occurence values are set" message="Invalid occurence/detection value of 0 for failure cause "{1}" " constraintExpression="inv:
let 
	mg:safetyModel::MeasureGroup = self.element.oclAsType(safetyModel::MeasureGroup),
 	MessageArg1 : String =self.failureCause.element.oclAsType(safetyModel::Failure).name
in
(not self.detection.oclIsUndefined() ) and (not self.occurrence.oclIsUndefined()) and (self.detection >0 ) and (self.occurrence>0)" mediniIdentifier="0116">
|
|
<target xmi:id="_98Yo0QuwEeqjYeKjV-7wuQ" class="FMEA::MeasureEntry"/>
|
|
</OCLConstraints:Constraint>
|
|
<OCLConstraints:Constraint xmi:id="_ClvZkAuxEeqjYeKjV-7wuQ" description="Check whether each requirement is allocated to an architecture element" message="Requirement {1} is not allocated to any architecture element" constraintExpression="inv:
let
MessageArg1:String= self.identifier
in
self.mediniGetTracedElements(sysml::SysMLElement)->size() >0" mediniIdentifier="0117">
|
|
<target xmi:id="_ClvZkQuxEeqjYeKjV-7wuQ" class="safetygoals::SafetyRequirement"/>
|
|
</OCLConstraints:Constraint>
|
|
<OCLConstraints:Constraint xmi:id="_XUBTwLbJEeq4nLYb_uFa7w" severity="WARNING" description="Check consistency for probability derivation" message="Event {0} is not using failure rate of represented component/failure mode" constraintExpression="inv:
if self.event.probabilityData.oclIsTypeOf(FTA::ExponentialProbabilityModel) 
then 
not self.represents.oclIsUndefined() implies self.event.probabilityData.oclAsType(FTA::ExponentialProbabilityModel).lambdaDerived =true
else true
endif
" mediniIdentifier="0118">
|
|
<target xmi:id="_XUBTwbbJEeq4nLYb_uFa7w" class="FTA::EventNode"/>
|
|
</OCLConstraints:Constraint>
|
|
<OCLConstraints:Constraint xmi:id="_SVCMMMtMEeqMld0pKRt16Q" description="Checks for duplicate failure modes within the same context element" message="{0} has duplicated failure mode(s): {1}" constraintExpression="inv:
let MessageArg1:Set(String) = self.failures.name->select(n:String|not self.failures.name->one(t:String|t=n)) ->asSet()

in
MessageArg1->size()= 0" mediniIdentifier="0119">
|
|
<target xmi:id="_SVCMMctMEeqMld0pKRt16Q" class="sysml::SysMLElement"/>
|
|
</OCLConstraints:Constraint>
|
|
<OCLConstraints:Constraint xmi:id="_7YDHUBRuEeukRuldB7DbTA" severity="INFO" description="Checks if each safety goal is associated to a hazardous event" message="The safety goal ''{1}'' is not associated to a hazardous event" constraintExpression="inv:
let
	hardousEvents:Set(hazard::HazardousEvent)=self.getCrossReferencedElements()->select(e| e.oclIsKindOf(hazard::HazardousEvent))->collect(oclAsType(hazard::HazardousEvent)),
	MessageArg1:String= self.identifier
in
if hardousEvents->any(e|e.getProfilePropertyValue('ISO26262_safetyGoal')->first() = self)
.oclIsUndefined() then
	false
else 
	true
endif
" mediniIdentifier="0006">
|
|
<target xmi:id="_7YDHURRuEeukRuldB7DbTA" class="safetygoals::SafetyGoal"/>
|
|
</OCLConstraints:Constraint>
|
|
<OCLConstraints:Constraint xmi:id="_Po4GMNnCEeuX-ICPw3dJ4g" severity="WARNING" description="Check for Severity Override" message="{0} overides inherited severity" constraintExpression="inv:
self.effects->size() > 0 implies self.severity = 0

-- in order to prevent overriding the inherited at all, this constraint can also be set to seveity error and switched to live mode" mediniIdentifier="0120">
|
|
<target xmi:id="_Po4GMdnCEeuX-ICPw3dJ4g" class="safetyModel::CauseEffect"/>
|
|
</OCLConstraints:Constraint>
|
|
</xmi:XMI>
|