Dealing with "Flexible" Units

In SMTK, units information can be associated with Attribute Value Items (via their Definitions) and is used make sure that users are setting the Item’s value using units that are comparable with those in its Definition. So for example one can specify “K” (for Kelvin) in an item’s Definition which in turn identifies it as representing a temperature. It would allow the user to set its value to “100 F” (100 degrees Fahrenheit ) and when asked for its value it would return 310.928 K but it would not allow the user to specify “100 mph” since a velocity unit is not a Temperature unit.

But what if the Item’s units depended on information not contained within its Definition? What if the user wanted to have the Item’s units depend on an Attribute (perhaps contains a String Item representing the desired units) similar to how expressions are supported. You couldn’t simply edit the Item’s Definition since this would change the units for all Items related to that Definition.

There are two possible approaches:

Using a Group and Custom UI Code

You could model the Item as a Group Item with the following children:

  • Double Item (without any units)
  • Reference Item to an Attribute (possibly restricted to a specific type of Attribute) that holds an item containing the units string
  • String Item that refers to an ItemPath (set as a default in its Definition and forced to be constant)

You would then create a special ItemView to allow the user to interact with the Group Item that would provide the following functionality:

  • The Widget used to display the Double Item’s value would act as if the Double Item’s Definition contained the units specified by the referenced Attribute which would also allow for auto completion of compatible units.
  • Setting the Reference Item and Item Path would need to check to see if the new units are compatible with the current units. If they are, nothing needs to be done but if they are not, the current value would be separated from its units and the units replaced.

The main issue with this approach is that all of the maintenance would be in application logic - including converting the user specified value into the desired units - since the double item has no idea there are units associated with it. It would also require the current Double Item UI code to be refactored in order to avoid code duplication.

Expanding Double Item Definition and Double Item (SMTK Core Change)

Alternatively we could expand Double Item Definition to contain the following data members:

  • Reference Item Definition - this would indicate the type of Attribute the Double Item refers to in order to determine the units it uses
  • std::string - this string would represent the item path used w/r to the referenced Attribute to access the units information represented as a string

There would be one method to set both pieces of information since then it can check to make sure the item being pointed to is a String Item.

Double Item would provide an interface to set/get the units deferred Attribute. Changing the Item’s units deferred Attribute would replace the units being used in the Double Item’s current value if they are not compatible to the newly referenced Attribute (else it would be left alone). The method that sets the referenced Attribute would also check to make sure there are units specified by the indicated String Item - else the method would fail.

What if the Units Deferred Attribute is not set (or unset) and What about Default Values?

My knee-jerk reaction would be using the units deferred attribute mechanism would clear out the default value (and vice versa) though in theory we could use the Default Value in the case that the referenced Attribute is not set.

@Aaron @rohith @justin.2.wilson @dcthomp @johnt @C_Wetterer-Nelson FYI

For the “SMTK Core Change” version, you could consider inheriting DoubleItemDefinition to make a DelegatedUnitsDoubleItemDefinition; it would keep the unit changes isolated to some degree but it would also require more code in the XML IO layer to deal with the new subclass.

1 Like

Is the reason for this feature so that the StringItem value (unit) can be applied to multiple DoubleItem instances? I am presuming so, but want to make sure I understand the use case.

Later…
Hmmm. My presumption about sharing is probably wrong, because the GroupItem wouldn’t be relevant. Can you provide an example use case or two? It’s not clear to me why editing a separate StringItem to set the untis is different than editing the unit in the DoubleItem itself.

Say you have a set of attributes where each one represents a physical aspect such as Temperature, Pressure, and Velocity. These attribute represents the concept (such as desired units) but do not explicitly contain any numerical values… Now lets assume that the simulation you are creating allows you to create an Attribute that contains a double value that by itself does not have units directly associated with it but its units depends on referencing one the above “Physical Aspects” Attributes.

For example a Static Field Attribute could have the following structure:

  • Volume of Interest
  • Temporal Range
  • Constant Value

I could have a temperature field, a pressure field or a velocity field. In each case the units associated with the Constant Value would be different.

Now you could say - why not structure the Attribute Definition for Field so that Volume of Interest and Temporal Range would be in a BaseField Definition and then derive TemporalField, Pressure Field and Velocity Field Definitions for it?

This would be a valid approach and is supported by SMTK.

But what if we have other Attributes that also want to have the ability of have Items that depend on these same “Physical Aspects”. In the current system the designer would do the same thing and create 4 more Definitions for that set of Attributes and so one. And this is just for 3 “Physical Aspects”, in some simulations there could be a lot more.

The above approaches would allow the designer to model the “Physical Aspects” separately and then have them influence an Attribute’s item’s units by reference; thereby, dramatically reducing the number of Definitions required.

Thanks for the example.

  • Like David and Aron, I am inclined to consider this a specialization of DoubleItem and DoubleItemDefinition, so I would vote for subclassing them (unless the incremental code is more straightforward than I envision).
  • Either way, I presume we’ll want a new Qt editor class to display both the reference item (dropdown) and the value side by side.
  • In terms of the file syntax, I presume we will use a new xml element to contain the specs for the delegate/indirect units. Maybe something like the <DelegatedUnits> element below?
<Double Name="example" ...>
  <DelegatedUnits>
    <Component Name="Field">
      <Accepts>...</Accepts>
    </Component>
    <UnitsPath>/value</UnitsPath>
  </DelegatedUnits>
</Double>

In the process of moving forward I came across a relatively serious issue with the suggested approaches that put a Reference Item inside of DoubleItem (or a class derived from it).

The issue is related to reading in Attribute Resources that contain these types of Items. A long time ago (before Resource Links), reading in references required a 2 pass approach. In the first pass, setting Items that held references were skipped. This was to make sure the Attributes they referenced were loading in memory prior to setting them. They would be set in the second pass.

With Resource Links, there was no need for doing 2 passes, since the link mechanism deferred accessing the referenced Persistent Object until after everything was read into memory since the Input operation never needed to access the referenced Object.

If we were to add a Reference Item to DoubleItem (or to a class derived from it), we will need to access the Attribute it is referencing when setting the value of the Item; since it needs to determine that the value is valid and should be set. This would bring back the old issue of making sure the referenced Attribute is loaded in memory before the Attribute that contains the DoubleItem referencing it is processed.

Alternative Approach

This may have been suggested in a previous conversation but we could simply give DoubleItem a method to override the units constraint specified by its Definition. We could be even more restrictive by only allowing the Item’s override units to be set only if its Definition’s doesn’t specify them.

From the Alternative Approach:
By “override units constraints” do you mean that the units will not be constrained to just Length and allow both Length and Mass? Or do you mean that the unit can be overwritten during runtime by adopting the constraints from the item that is “really” controlling them?

It’s more in line with your second interpretation Aaron.
What I was thinking is the following:

  • Assume that a DoubleItem (di)'s Definition did not specify any units.
  • Lets also assume that DoubleItem now has a method called either bool setUnitsOverride(const std::string& newUnits) or bool setUnits(const std::string& newUnits) - I’m open to suggestions with regards to the name. This method will succeed only if the Definition does not specify units itself.

Now the developers does the following:

  • di->setValue(10) // di is set to unitless value of 10
  • di->setUnits(“ft”) // di now represents 10 feet
  • di->setValueAsString(“20 yards”) // di now has the value of 60 feet
  • di->setUnits(“C”) // di now has the value of 20 degrees Celsius

Thanks for the example, that sounds good for all the use cases that I know about.