The Building Coder

UnitUtils Converting Units for Unit Weight

Here comes a quick clarification of the units used for the UnitWeight built-in parameter PHY_MATERIAL_PARAM_UNIT_WEIGHT.

One example usage is to calculate the total weight of rebars in a project.

A developer encountered the following issue in that process:

Question

My Revit add-in calculates total weight of rebars in the document using the UnitWeight parameter from the material.

Displayed in Revit, I write a value of 7850 Kg/m3 (kg/cubicmeters).

When using this parameter in code, I assume that the value I get from the parameter is in internal units, which I assume to be kiloNewton / cubic feet.

So when I use this, I expect to be able to use the UnitUtils.

This snapshot from the values displayed by the Visual Studio debugger immediate window show the original value and the converted ones:

  var parameterVaule = Parameter.AsDouble();
  7154.4631104000009

  var converted = UnitUtils.ConvertFromInternalUnits(parameterVaule ,Autodesk.Revit.DB.DisplayUnitType.DUT_KILONEWTONS_PER_CUBIC_METER);
  77.01 => This is a correct value.

  var converted2 = UnitUtils.ConvertFromInternalUnits(parameterVaule ,Autodesk.Revit.DB.DisplayUnitType.DUT_KILOGRAMS_PER_CUBIC_METER);
  252657.48031496062 => ??? this not correct!

The value string shows 77 kN/cubicmeters, which by manual calculation is 7849.13 Kg/cubicmeters.

Why doesn't the UnitUtils class return this value?

I assume that the method ConvertFromInternalUnits should be able to convert from the default internal units to the wanted unit?

Is this a case where I can't trust the UnitUtils?

Sample Code and Workaround

Here is a snippet from the calculation of unit weight from a material.

/// <summary>
/// Get the unit weight of a material.
/// </summary>
internal static double GetMaterialEgenvekt( 
  Document doc, 
  ref string material, 
  Element rebarelement )
{
  var rType = rebarelement.Document.GetElement( 
    rebarelement.GetTypeId() ) as ElementType;

  var paramMaterial = rType.get_Parameter( 
    BuiltInParameter.MATERIAL_ID_PARAM );

  var mat = doc.GetElement( paramMaterial
    .AsElementId() ) as Material;

  double egenvekt = 0;
  if( mat == null ) return egenvekt;

  var property = doc.GetElement(
    mat.StructuralAssetId ) as PropertySetElement;

  if( property != null )
  {
    var unitWeightParam = property.get_Parameter(
      BuiltInParameter.PHY_MATERIAL_PARAM_UNIT_WEIGHT );

    // Not In Use - gives wrong value in metric unit.

    var unitWeight = UnitUtils.ConvertFromInternalUnits( 
      unitWeightParam.AsDouble(), 
      DisplayUnitType.DUT_KILOGRAMS_PER_CUBIC_METER );

    // Manual calculation. In use, and calculates correct.

    var egenvektFraMaterial 
      = EgenVektFraNewtonPerSquareFootMeter( 
        unitWeightParam.AsDouble() );

    if( !( egenvekt > 0 ) )
      egenvekt = egenvektFraMaterial;
  }
  material = mat.Name;
  return egenvekt;
}

The manual calculation in EgenVektFraNewtonPerSquareFootMeter is implemented like this:

/// <summary>
/// Calculate the unit weight from NewtonPerSquareFootMeter
/// </summary>
double EgenVektFraNewtonPerSquareFootMeter( 
  double unitweight )
{
  double egenvekt = unitweight / 9.81F;

  double meterPerFot = 1000 
    / GeoHelper.FootMillimeterKonstant;

  egenvekt = egenvekt * Math.Pow( meterPerFot, 2 );

  return egenvekt;
}

The constant GeoHelper.FootMillimeterKonstant is defined thus;

public static double FootMillimeterKonstant
  = Math.Round( 304.8, 1 );

Hope we can sort out the problem =)

I use the manual way today, after a heads up from a customer who ordered about 900 Kg too little rebars in a project!

Explanation

The development team took a look at this issue and provided the following explanation:

UnitUtils.ConvertFromInternalUnits does not convert from UnitWeight (77 kN/cubicmeters) to Density (7849.13 Kg/cubicmeters).

UnitUtils.ConvertFromInternalUnits displays a value from Revit internal units (kg/(ft²·s²) for UnitWeight and kg/ft³ for Density) to a compatible unit (kN/cubicmeters for UnitWeight and Kg/cubicmeters for Density).

In detail:

UnitWeight and Density are two different units. So it does not make sense to display some UnitWeight values in kg/m3 – there are different units.

Therefore:

  // Does not work (different units: value in
  // UnitWeight units kg/(ft²·s²) displayed as
  // value in Density units kg/m³)

  var unitWeight = UnitUtils.ConvertFromInternalUnits(
    unitWeightParam.AsDouble(),
    DisplayUnitType.DUT_KILOGRAMS_PER_CUBIC_METER);

and

  // Works (same units: value in UnitWeight units
  // kg/(ft²·s²) displayed as value in UnitWeight
  // units kN/m3)

  var converted2 = UnitUtils.ConvertFromInternalUnits(
    unitWeightParam.AsDouble(),
    DisplayUnitType.DUT_KILONEWTONS_PER_CUBIC_METER);

If you want to obtain the density in kg/m3 you can use the PHY_MATERIAL_PARAM_STRUCTURAL_DENSITY built-in parameter:

var densityParam = property.get_Parameter(
  BuiltInParameter.PHY_MATERIAL_PARAM_STRUCTURAL_DENSITY );

// Works (same units: value in Density units kg/ft³
// displayed as value in Density units kg/m³)

var converted = UnitUtils.ConvertFromInternalUnits(
  densityParam.AsDouble(),
  DisplayUnitType.DUT_KILOGRAMS_PER_CUBIC_METER );

--> converted = 7849.04687 double

Or use the formula as you did:

  UnitWeight = Density * g

I hope this clarifies.

Happily, you already solved this properly yourself.