Usage of units in python code with automator

Hi,

How would you go about using (accessing) units in python?
If I have a model like this:

package MechanicalObjectExample {
  abstract item def MechanicalObject {
  attribute mass :> ISQ::mass;
  assert constraint {
   (mass > 0) and (shape != null)
  }
}


abstract item mechanicalObjects[*] : MechanicalObject;

metadata def <mec> MechanicalObjectMetadata :> Metaobjects::SemanticMetadata {
    :>> baseType = mechanicalObjects meta SysML::Usage;
}

part def DroneSystem {
    part def Drone {
        #mec part battery {
            attribute :>> mass = 2.5 [SI::kg];
            item shape[1] : ShapeItems::Box :>> shape { 
                attribute :>> length = 10 [SI::cm];
                attribute :>> width = 4 [SI::cm];
                attribute :>> height = 3 [SI::cm];
            }
        }
        #mec part propulsionUnit {
            attribute :>> mass = 0.5 [SI::kg];
            item shape[1] : ShapeItems::Cylinder :>> shape;
        }            
    }
}

}

Can you provide a code snippet showing how you access and use the units so I can do calculations in python space?

Thanks,
Robert

Hi,

quantity expressions are just regular operator expressions, typically of the form of <expr> [<unit ref>]. The left-hand side expr is the first argument, right-hand side unit expression - the second argument. In a valid model, this is accessible via Python sequence unpacking expr, units = op_expr.arguments.collect().

The simplest case is when unit expression is just a reference - the unit is a referent of FeatureReferenceExpression.

Thanks @Daumantas ,

I have reduced the model and made some example code.
I still don’t see how I can get to the units themselves.

thissrc="""

package MechanicalObjectExample {
    private import ScalarValues::*;
    part def DroneSystem {
        part def Drone {
            part battery {
                /*attribute mass:ISQ::MassValue = 2.5 [SI::kg];*/
                attribute m:Real=2.5;
            }
            part propulsionUnit {
                attribute mass:ISQ::MassValue = 0.5 [SI::kg];
            }            
        }
    }
}"""

model, diagnostics = syside.load_model(sysml_source=thissrc)

def find_attribute_values(element: syside.Element, level: int = 0) -> None:

    if element.try_cast(syside.AttributeUsage):
        #if element.name is not None: print("  " * level, element.name)
        attr  = element.cast(syside.AttributeUsage)
        expression = next(iter(attr.owned_elements), None)
        if expression is not None and isinstance(expression, syside.OperatorExpression):
            expression, units = expression.arguments.collect()
            print (f"units = {units}")
        if expression is not None and isinstance(expression, syside.LiteralRational):
            print(f"{attr.declared_name}: {expression.value}")
    
    for child in element.owned_elements.collect():
       find_attribute_values(child, level + 1)

  
for document_resource in model.documents:
    with document_resource.lock() as document:
        find_attribute_values(document.root_node)

This gives me:
m: 2.5
units = MechanicalObjectExample::DroneSystem::Drone::propulsionUnit::mass::(anonymous OperatorExpression)::(anonymous Feature)::(anonymous FeatureReferenceExpression)
mass: 0.5

How can I get to “[SI::kg]”?

Thanks,

Robert

How can I get to “[SI::kg]”?

That would be units.referent, or units.cast(syside.FeatureReferenceExpression).referent for type-checked code.

v0.8.2 added experimental_quantities option to Compiler, see Compiler.evaluate