How to evaluate satisfy relationships

Hi,

The following model evaluates satisfy and requirements.

package parts {
private import ScalarValues::;
private import SI::;
private import ISQ::*;
package ‘base parts’ {
part def CadRepresentedPart {
attribute mass :> ISQ::mass;
}
}

part def Chassis :> 'base parts'::CadRepresentedPart {
    attribute wheelbase : LengthValue default 1 [cm];
}

part def MOA_Crawler {
    part chassis : Chassis {
       :>> mass default 0.1 [kg];
    }
    attribute vehicleMass : MassValue = chassis.mass;
}

}

package CrawlerAnalysis {
private import ISQ::;
private import SI::;
private import parts::*;
requirement def VehicleMassRequirement {
subject ;
in attribute actualMass : ISQ::MassValue;
in attribute requiredMass : ISQ::MassValue;
require constraint  {
actualMass < requiredMass
}
}

requirement def VehicleMassRequirementWithSubject {
    subject crawler : MOA_Crawler; 
    attribute requiredMass : ISQ::MassValue = 0.5 [kg];
    require constraint  {
        VehicleMassAnalysis(crawler) < requiredMass
    }
}

analysis def VehicleMassAnalysis {
    subject crawler : MOA_Crawler;
    return calculatedMass : ISQ::MassValue = crawler.vehicleMass;
}

part tinycrawler : MOA_Crawler {
        part  :>> chassis {
            attribute  :>> mass = 0.4 [kg];
        }
    }

part medcrawler : MOA_Crawler {
    part  :>> chassis {
        attribute  :>> mass = 2.5 [kg];
    }
}
 
part analysisContext {
    satisfy requirement reqTiny : VehicleMassRequirementWithSubject by tinycrawler;
    satisfy requirement reqMed : VehicleMassRequirementWithSubject by medcrawler;
    attribute checkTiny = VehicleMassRequirement(actualMass = VehicleMassAnalysis(tinycrawler), requiredMass = 0.5 [kg]);
    attribute checkMed = VehicleMassRequirement(actualMass = VehicleMassAnalysis(medcrawler), requiredMass = 0.5 [kg]);
}

}


However, the following code that uses evaluate expressions does not produce outputs for the satisfy and the atttributes checkMed, checkTiny. How can it be made working?

`def find_expression_attribute_values(element, syside_mod, level: int = 0) → None:
“”"
One expression per AttributeUsage — no duplicate lines.

Prefer feature.feature_value_expression (Sensmetry / rollups). If missing, use the CTO
rule: first owned child if it is an Expression (matches jl_sysmlv2_api).
"""
indent = "  " * level
compiler = syside_mod.Compiler()
lib = syside_mod.Environment.get_default().lib

if hasattr(element, "try_cast") and element.try_cast(syside_mod.AttributeUsage):
    attr = element.cast(syside_mod.AttributeUsage)
    owner_scope = getattr(attr, "owner", attr)

    expr = getattr(attr, "feature_value_expression", None) or getattr(
        attr, "featureValueExpression", None
    )
    if expr is None:
        try:
            expression_a1 = next(iter(attr.owned_elements), None)
        except Exception:
            expression_a1 = None
        if expression_a1 is not None and isinstance(
            expression_a1, syside_mod.Expression
        ):
            expr = expression_a1

    if expr is not None and isinstance(expr, syside_mod.Expression):
        try:
            value, report = compiler.evaluate(
                expr,
                scope=owner_scope,
                stdlib=lib,
                experimental_quantities=True,
            )
        except TypeError:
            value, report = compiler.evaluate(expr)
        if not getattr(report, "fatal", False):
            name = (
                getattr(attr, "qualified_name", None)
                or getattr(attr, "declared_name", None)
                or getattr(attr, "name", None)
                or "<unnamed>"
            )
            print(f"{indent}{name}: {value}")

try:
    element.owned_elements.for_each(
        lambda owned_element: find_expression_attribute_values(
            owned_element, syside_mod, level + 1
        )
    )
except Exception:
    try:
        for owned_element in element.owned_elements:
            find_expression_attribute_values(owned_element, syside_mod, level + 1)
    except Exception:
        pass

def run(model, syside_mod) → None:
attr_iter = None
if hasattr(model, “elements”) and callable(model.elements):
try:
attr_iter = model.elements(syside_mod.AttributeUsage) # type: ignore[arg-type]
except TypeError:
attr_iter = model.elements()
elif hasattr(model, “nodes”) and callable(model.nodes):
try:
attr_iter = model.nodes(syside_mod.AttributeUsage) # type: ignore[arg-type]
except TypeError:
attr_iter = model.nodes()
if attr_iter is None:
print(“Model exposes neither elements() nor nodes()”, file=sys.stderr)
return

for el in attr_iter:
    try:
        if hasattr(el, "try_cast") and el.try_cast(syside_mod.AttributeUsage):
            find_expression_attribute_values(el, syside_mod)
    except Exception:
        pass`

Hi,

Special handling of requirement expressions is not yet implemented.

Thank you @Daumantas

Do you some roadmap when it could be available?

Other tools implemented that already.

No promises but I would say soon-ish. Interpreter currently has the most gaps (rationals, complex numbers, quantities, units etc.) so it would be a part of that. As it is also less intrusive and smaller in scope, it might be implemented before any of the bigger changes.