-- -- Copyright 2014 Alessandro Gerlinger Romero -- -- This file is part of Hybrid fUML. -- -- Hybrid fUML is free software: you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by -- the Free Software Foundation, either version 3 of the License, or -- (at your option) any later version. -- -- Hybrid fUML is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU General Public License for more details. -- -- You should have received a copy of the GNU General Public License -- along with Hybrid fUML. If not, see . -- ------------------------------------------------------------------------------------------------------------------------------------------------------------ -- CONTINUOUS DOMAIN -- -- APPROACH ------------------------------------------------------------------------------------------------------------------------------------------------------------ -- RULES -- -- DEFINING EQUATIONS -- -- rule called from the main block to define the system of equations for each active object rule_fUML_defineEquations :: Rule() rule_fUML_defineEquations = -- (CB) checking if it is at right edge if not (function_fUML_isOnEdgePhysicalClock pc) then -- checking: exist continuous domain and not discrete domain if function_fUML_existsContinuousDomainEnabled && not function_fUML_existsDiscreteDomainEnabled then -- clearing equations forall se <- (expr2list (dom function_SystemOfEquations_object)) do function_SystemOfEquations_object(se):= FUML_Semantics_Classes_Kernel_ValueEmpty function_SystemOfEquations_constraint(se):= {} `seq` -- creating new equations forall ao <- (expr2list function_fUML_activeObjects) do if length (function_fUML_retrieveContinuousObjectAndConstraintEnabledForActive ao) > 0 then create sofe do function_SystemOfEquations_object(sofe) := ao function_SystemOfEquations_constraint(sofe) := mkSet((function_fUML_retrieveEquationsForConnectors ao) ++ (function_fUML_retrieveEquationsForPortsNotConnected ao FUML_Semantics_Classes_Kernel_ValueEmpty FUML_Syntax_Classes_Kernel_FeatureEmpty) ++ (function_fUML_retrieveEquationsForEnabledObjects ao)) else skip else skip else skip where l = function_fUML_locus pclk = function_Locus_physicalClock l pc = function_Clock_timeBase pclk -- -- COMPUTING EQUATIONS -- -- rule called from the main block to check all modelica equations and compute them rule_fUML_computeEquations :: Rule() rule_fUML_computeEquations = -- (CB) checking if it is at right edge if not (function_fUML_isOnEdgePhysicalClock pc) then -- checking: exist continuous domain and not discrete domain if function_fUML_existsContinuousDomainEnabled && not function_fUML_existsDiscreteDomainEnabled then if not $ emptyDom function_SystemOfEquations_constraint then do -- for all systems of equations evaluate all constraints forall s <- (expr2list $ dom function_SystemOfEquations_constraint) do forall c <- (expr2list $ function_SystemOfEquations_constraint s) do rule_fUML_computeEquation (function_SystemOfEquations_object s) (function_ValueSpecification_LiteralString_value (function_Constraint_specification c)) -- advance physicalClock function_TimeBase_currentInstant(pc) := ni else skip else skip else skip where l = function_fUML_locus pclk = function_Locus_physicalClock l pc = function_Clock_timeBase pclk pcis = function_TimeBase_instants pc -- -- finding current index ci = function_TimeBase_currentInstant(pc) (_,cii) = head $ filter (\(is,i) -> is==ci) $ zip pcis [0..(length pcis)] -- next instant is the next in the list (precomputed) ni = function_TimeBase_instants(pc)!!(cii+1) ------------------------------------------------------------------------------------------------------------------------------------------------------------ -- FUNCTIONS -- CONTINUOUS DOMAIN -- look in all extensionals values of type object, classifier behavior running and it has continuous domain -- look in a specific active object for all its enabled continuous domains function_fUML_retrieveContinuousObjectAndConstraintEnabledForActive :: FUML_Semantics_Classes_Kernel_Value -> [(FUML_Semantics_Classes_Kernel_Value,FUML_Syntax_Extensions_Classes_Kernel_Constraint)] function_fUML_retrieveContinuousObjectAndConstraintEnabledForActive v = [(ao,c)| ao <- (expr2list $ function_fUML_objectsWithStereotypeForEvaluation ContinuousDomain), c <- (expr2list $ function_fUML_objectStereotypeConstraint ao ContinuousDomain), (function_fUML_continuousDomainIsEnabled ao c), if v == FUML_Semantics_Classes_Kernel_ValueEmpty then True else (function_fUML_parentActiveObject ao == v || ao == v)] -- look in all extensionals values of type object, classifier behavior running and it has continuous domain function_fUML_existsContinuousDomainEnabled :: Bool function_fUML_existsContinuousDomainEnabled = length (function_fUML_retrieveContinuousObjectAndConstraintEnabledForActive FUML_Semantics_Classes_Kernel_ValueEmpty) /= 0 -- verify if a continuous domain is enabled function_fUML_continuousDomainIsEnabled :: FUML_Semantics_Classes_Kernel_Value -> FUML_Syntax_Extensions_Classes_Kernel_Constraint -> Bool function_fUML_continuousDomainIsEnabled vl c = (length el) /= 0 && (function_fUML_evaluateBooleanExpression vl strspec) where f = (function_Locus_factory (function_Value_ExtensionalValue_locus vl)) spec = function_Constraint_specification c strspec = function_ValueSpecification_LiteralString_value spec el = expr2list $ function_Constraint_constrainedElement_Constraint(c) ------------------------------------------------------------------------------------------------------------------------------------------------------------ -- -- EQUATIONS -- -- retrieve all connectors and equations not guarded by domains as well as generate equation for connector -- Checking connector, only 2 ends, only two objects (one in each end) -- TODO MEDIUM PRIORITY - deal with delegation function_fUML_retrieveEquationsForConnectors :: FUML_Semantics_Classes_Kernel_Value -> [FUML_Syntax_Extensions_Classes_Kernel_Constraint] function_fUML_retrieveEquationsForConnectors ao = (concat const) ++ constC ++ (concat $ map(\o -> (function_fUML_retrieveEquationsForConnectors o)) (expr2list $ function_fUML_getAllPassiveObjectChilds ao)) where cl = function_fUML_oneClassifierType (ao) cos = function_Classifier_StructuredClassifier_ownedConnector cl mcos = filter (\c -> function_Feature_AppliedStereotype(c) `intersect` {ModelicaConnection} /= {} ) $ expr2list cos -- -- connector must -- have two ends, -- both ends with an object (partWithPort and role), -- roles must be ports without operation or reception -- connector should be of type assembly (DELEGATION IS NOT SUPPORTED - at the moment) mcos2 = filter (\c -> length ( expr2list (function_Feature_Connector_end c)) == 2 && (readPart ao (fConnectorEnd c)) /= FUML_Semantics_Classes_Kernel_ValueEmpty && (readPart ao (lConnectorEnd c)) /= FUML_Semantics_Classes_Kernel_ValueEmpty && (readRole (readPart ao (fConnectorEnd c)) (fConnectorEnd c)) /= FUML_Semantics_Classes_Kernel_ValueEmpty && (readRole (readPart ao (lConnectorEnd c)) (lConnectorEnd c)) /= FUML_Semantics_Classes_Kernel_ValueEmpty && function_fUML_portIsOkForContinuousBehavior (function_ConnectorEnd_role (fConnectorEnd c)) && function_fUML_portIsOkForContinuousBehavior (function_ConnectorEnd_role (lConnectorEnd c)) && function_Feature_Connector_kind c == FUML_Syntax_Extensions_CompositeStructures_ConnectorKind_assembly ) $ expr2list mcos -- abbreviations fConnectorEnd c = head $ expr2list (function_Feature_Connector_end c) lConnectorEnd c = last $ expr2list (function_Feature_Connector_end c) readPart o ce = function_fUML_readStructuralFeature o (function_ConnectorEnd_partWithPort ce) readRole r ce = function_fUML_readStructuralFeature (function_Value_Reference_referent r) (function_ConnectorEnd_role ce) -- -- loading the PAIRS attribute/port pap = [[((function_ConnectorEnd_partWithPort (fConnectorEnd c)), (function_ConnectorEnd_role (fConnectorEnd c))), ((function_ConnectorEnd_partWithPort (lConnectorEnd c)), (function_ConnectorEnd_role (lConnectorEnd c)))] | c <- mcos2] -- checking more than one connector with the same attribute/port papM2 = mkSet [ mkSet (merge cc1 cc2) | cc1 <- pap, cc2 <- pap, (cc1!!0 `elem` cc2 || cc1!!1 `elem` cc2) && cc1 /= cc2] -- checking elements with more than one connector (excluding elements with more than two attribute/port) papE2 = mkSet [ mkSet (cc1) | cc1 <- pap, cc1!!0 `notElem` (expr2list $ bigUnion papM2) && cc1!!1 `notElem` (expr2list $ bigUnion papM2)] -- creating the result of the computation - sets of attribute/port to create the equations cpa = papM2 `union` papE2 -- -- checking type for the defined sets (MUST BE THE SAME) -- creating a list of (portType, [attributes,port]) : [(A,P)] -> (PT,[(A,P)]) fptat = map (\s -> foldl (\(pt,al) (a,p) -> ( if pt == FUML_Syntax_Classes_Kernel_ClassifierEmpty then (function_StructuralFeature_TypedElement_type p) else if (function_StructuralFeature_TypedElement_type p) /= pt then error("function_fUML_retrieveEquationsForConnectors. Invalid connection between ports of different types. " ++ show s) else pt , al++[(a,p)])) (FUML_Syntax_Classes_Kernel_ClassifierEmpty,[]) (expr2list s) ) $ expr2list cpa -- -- selecting constraints that have no continuous domain, but they are connected in some way base on [(A,P)] const = expr2list $ mkSet $ map (\(a,p)-> map (\c -> function_fUML_refineConstraint (show a ++ " IN PASSIVE OBJECT WITHOUT DOMAIN") c) $ filter (\c -> -- it is an equation (function_Constraint_AppliedStereotype(c) `intersect` {ModelicaEquation}) /= {} && -- has no continuous domain length (filter (\c2 -> function_Constraint_constrainedElement_Constraint(c2) `intersect` {c} /= {}) (expr2list $ function_Namespace_ownedRule $ one (function_Feature_featuringClassifier p))) == 0 ) (expr2list $ function_Namespace_ownedRule ( one (function_Feature_featuringClassifier p))) ) $ expr2list $ bigUnion cpa -- -- generating constraint for connectors -- managing the creation of equations constC = concat $ map (\(pt,al) -> map (\atp -> if (function_Feature_EnumerationValueForAppliedStereotype atp ModelicaValueProperty FlowFlag) == Flow then (generateConstraint . generateFlowEquation') [(c,f,atp) | (c,f) <- al] else (generateConstraint . generatePotentialEquations') [(c,f,atp) | (c,f) <- al] ) $ expr2list (function_Classifier_StructuredClassifier_ownedAttribute pt) ) fptat -- -- supporting functions for the creation of equations generateConstraint s = FUML_Syntax_Extensions_Classes_Kernel_Constraint ("GENERATED " ++ s) (FUML_Syntax_Classes_Kernel_ValueSpecification ("generated") FUML_Syntax_Classes_Kernel_InstanceSpecificationEmpty False 0 0.0 -- equation s 0 ("generated") FUML_Syntax_Classes_Kernel_VisibilityKind_public FUML_Syntax_Classes_Kernel_ClassifierEmpty FUML_Syntax_Classes_Kernel_LiteralString) ("GENERATED " ++ s) FUML_Syntax_Classes_Kernel_VisibilityKind_public FUML_Syntax_Classes_Kernel_VisibilityKind_public generatePotentialEquations' [(c,f,a)] = "" generatePotentialEquations' ((c,f,a):(c1,f1,a1):s) = (function_Feature_NamedElement_name c) ++ "." ++ (function_Feature_NamedElement_name f) ++ "." ++ (function_Feature_NamedElement_name a) ++ " = " ++ (function_Feature_NamedElement_name c1) ++ "." ++ (function_Feature_NamedElement_name f1) ++ "." ++ (function_Feature_NamedElement_name a1) ++ ";" ++ generatePotentialEquations' ([(c1,f1,a1)] ++s) generateFlowEquation' [] = " = 0;" generateFlowEquation' ((c,f,a):s) = (function_Feature_NamedElement_name c) ++ "." ++ (function_Feature_NamedElement_name f) ++ "." ++ (function_Feature_NamedElement_name a) ++ (if length s > 0 then " + " else "") ++ generateFlowEquation' s -- -- checking if exists port (instance) without connector -- -- compute equation only for flows, making their equals to 0 -- function_fUML_retrieveEquationsForPortsNotConnected :: FUML_Semantics_Classes_Kernel_Value -> FUML_Semantics_Classes_Kernel_Value -> FUML_Syntax_Classes_Kernel_Feature -> [FUML_Syntax_Extensions_Classes_Kernel_Constraint] function_fUML_retrieveEquationsForPortsNotConnected o po pf = constP ++ (concat $ map(\(co, f) -> (function_fUML_retrieveEquationsForPortsNotConnected co o f)) (expr2list $ function_fUML_getAllPassiveObjectChildsWithFeature o)) where cl = function_fUML_oneClassifierType (o) pcl = if po /= FUML_Semantics_Classes_Kernel_ValueEmpty then function_fUML_oneClassifierType (po) else FUML_Syntax_Classes_Kernel_ClassifierEmpty pcos = if pcl /= FUML_Syntax_Classes_Kernel_ClassifierEmpty then (function_Classifier_StructuredClassifier_ownedConnector pcl) else {} pmcos = filter (\c -> function_Feature_AppliedStereotype(c) `intersect` {ModelicaConnection} /= {} ) $ expr2list pcos pts = function_Classifier_EncapsulatedClassifier_ownedPort cl -- port exists, is marked as ModelicaConnector, is not connected (Connector in the parent object), and does not have operation or reception ptsN = filter (\p -> p /= FUML_Syntax_Classes_Kernel_FeatureEmpty && (function_fUML_readStructuralFeature o p /= FUML_Semantics_Classes_Kernel_ValueEmpty ) && function_Classifier_AppliedStereotype(function_StructuralFeature_TypedElement_type p) `intersect` {ModelicaConnector} /= {} && length ( filter (\c -> (function_ConnectorEnd_role $ head $ expr2list (function_Feature_Connector_end c)) == p || (function_ConnectorEnd_role $ last $ expr2list (function_Feature_Connector_end c)) == p ) pmcos ) == 0 && function_fUML_portIsOkForContinuousBehavior p ) $ expr2list pts -- generating constraints for ports ps = [(p, at) | p <- ptsN, at <- expr2list $ function_Class_ownedAttribute (function_StructuralFeature_TypedElement_type p)] constP = if length ps == 0 then [] else [FUML_Syntax_Extensions_Classes_Kernel_Constraint ("generated") (FUML_Syntax_Classes_Kernel_ValueSpecification ("generated") FUML_Syntax_Classes_Kernel_InstanceSpecificationEmpty False 0 0.0 -- equation (generateEquationForPort ps) 0 ("generated") FUML_Syntax_Classes_Kernel_VisibilityKind_public FUML_Syntax_Classes_Kernel_ClassifierEmpty FUML_Syntax_Classes_Kernel_LiteralString) ("generated for PORTS " ++ show cl) FUML_Syntax_Classes_Kernel_VisibilityKind_public FUML_Syntax_Classes_Kernel_VisibilityKind_public] generateEquationForPort [] = "" generateEquationForPort ((f,a):s) = if (function_Feature_EnumerationValueForAppliedStereotype a ModelicaValueProperty FlowFlag) == Flow then (function_Feature_NamedElement_name pf) ++ "." ++ (function_Feature_NamedElement_name f) ++ "." ++ (function_Feature_NamedElement_name a) ++ " = 0" ++ ";" ++ generateEquationForPort s else "" ++ generateEquationForPort s -- retrieve all equations for enabled objects function_fUML_retrieveEquationsForEnabledObjects :: FUML_Semantics_Classes_Kernel_Value -> [FUML_Syntax_Extensions_Classes_Kernel_Constraint] function_fUML_retrieveEquationsForEnabledObjects ao = -- enabled equations reConstFil ++ -- equations without continuous domain for the active object rewDomain where eActiveObject = expr2list (function_fUML_objectStereotypeConstraint ao ModelicaEquation) ePDActiveObject = map (\c -> one $ function_Constraint_constrainedElement_Constraint(c)) $ expr2list (function_fUML_objectStereotypeConstraint ao ContinuousDomain) ewDomain = filter (\c -> c `notElem` ePDActiveObject ) eActiveObject eConsActiveObject = map (\(o,c) -> expr2list (function_Constraint_constrainedElement_Constraint c)) (function_fUML_retrieveContinuousObjectAndConstraintEnabledForActive ao) eConstFil = filter (\c -> function_Constraint_AppliedStereotype(c) `intersect` {ModelicaEquation} /= {}) $ concat eConsActiveObject -- refining constraints rewDomain = map (\c -> function_fUML_refineConstraint " IN ACTIVE OBJECT WITHOUT DOMAIN" c) ewDomain reConstFil = map (\c -> function_fUML_refineConstraint " ENABLED" c) eConstFil ------------------------------------------------------------------------------------------------------------------------------------------------------------ -- -- SUPPORT -- -- -- checks if a port used for continuous behavior has operations or receptions function_fUML_portIsOkForContinuousBehavior :: FUML_Syntax_Classes_Kernel_Feature -> Bool function_fUML_portIsOkForContinuousBehavior p | function_Feature_type(p) == FUML_Syntax_Extensions_CompositeStructures_Port = if hasOperRecep then False else True | otherwise = error( "function_fUML_portIsOkForContinuousBehavior. Unsupported feature type " ++ show p) where cl = function_StructuralFeature_TypedElement_type p hasOperRecep = length (filter (\f -> function_Feature_type(f) == FUML_Syntax_CommonBehaviors_Communications_Reception || function_Feature_type(f) == FUML_Syntax_Classes_Kernel_Operation) $ expr2list (function_Classifier_feature cl)) > 0 -- -- add as comment the attribute owner of this constraint function_fUML_refineConstraint :: String -> FUML_Syntax_Extensions_Classes_Kernel_Constraint -> FUML_Syntax_Extensions_Classes_Kernel_Constraint function_fUML_refineConstraint str (FUML_Syntax_Extensions_Classes_Kernel_Constraint axmiId (FUML_Syntax_Classes_Kernel_ValueSpecification axmiId2 ainstancespecification avalue1 avalue2 avalue3 avalue4 avalue5 aname6 avisibility7 atype8 afUML_Syntax_Classes_Kernel_ValueSpecificationType) aname2 avisibility3 avisibility4) = FUML_Syntax_Extensions_Classes_Kernel_Constraint (axmiId ++ str) (FUML_Syntax_Classes_Kernel_ValueSpecification (axmiId2 ++ str) ainstancespecification avalue1 avalue2 avalue3 avalue4 avalue5 aname6 avisibility7 atype8 afUML_Syntax_Classes_Kernel_ValueSpecificationType) (aname2 ++ str) avisibility3 avisibility4 -- -- check if there is computation to be done function_fUML_isOnEdgePhysicalClock :: FUML_Semantics_Extensions_Clock_TimeBase -> Bool function_fUML_isOnEdgePhysicalClock ptb = last (function_TimeBase_instants ptb) == function_TimeBase_currentInstant ptb