Get Structural properties of a material

Hi everyone,

I’m trying to get the structural properties of the material of my revit elements through a Dynamo script (eg. Unit weight, poisson ratio, Young Modulus etc. ). I first thought of using GetParameterByName nodes but the values of the structural parameters are strangely all equal to zero…

On the REVIT API documentation site, I found a code in C# that seems to do what I want to. However I have troubles to translate this code into python in order to insert it in my Dynamo script and everytime I try something I got a different Warning over my Python Script… (Attribute error, “Read only” parameter, “object is not callable”…)

If anyone knows how to translate this C# script into a Python node and could explain me how to do it, that would be awesome!

Thanks in advance for any help :pray:

Arthur

Here is the C# code:

private void ReadMaterialProps(Document document, Material material)
{
   ElementId strucAssetId = material.StructuralAssetId;
   if (strucAssetId != ElementId.InvalidElementId)
   {
      PropertySetElement pse = document.GetElement(strucAssetId) as PropertySetElement;
      if (pse != null)
      {
         StructuralAsset asset = pse.GetStructuralAsset();

         // Check the material behavior and only read if Isotropic
         if (asset.Behavior == StructuralBehavior.Isotropic)
         {
            // Get the class of material
            StructuralAssetClass assetClass = asset.StructuralAssetClass;

            // Get other material properties
            double poisson = asset.PoissonRatio.X;
            double youngMod = asset.YoungModulus.X;
            double thermCoeff = asset.ThermalExpansionCoefficient.X;
            double unitweight = asset.Density;
            double shearMod = asset.ShearModulus.X;
            double dampingRatio = asset.DampingRatio;

            if (assetClass == StructuralAssetClass.Metal)
            {
               double dMinStress = asset.MinimumYieldStress;
            }
            else if (assetClass == StructuralAssetClass.Concrete)
            {
               double dConcComp = asset.ConcreteCompression;
            }
         }
      }
   }
}

Hi @Arthur1, here is a python version of the C# code…

import clr

clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript import Geometry as geom

clr.AddReference("RevitServices")
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
doc =  DocumentManager.Instance.CurrentDBDocument
app = DocumentManager.Instance.CurrentUIApplication.Application

clr.AddReference("RevitNodes")
import Revit
clr.ImportExtensions(Revit.Elements)
clr.ImportExtensions(Revit.GeometryConversion)

clr.AddReference("RevitAPI")
from Autodesk.Revit.DB import *

def tolist(obj1):
	if hasattr(obj1,"__iter__"): return obj1
	else: return [obj1]

def ReadMaterialProps(mat):
	arr = []
	assId = mat.StructuralAssetId
	
	if not assId == ElementId.InvalidElementId:
		pse = doc.GetElement(assId)
		if not pse == None:
			ass = pse.GetStructuralAsset()
			if ass.Behavior == StructuralBehavior.Isotropic:
				assClass = ass.StructuralAssetClass	

				arr.append(ass.Name)
				arr.append(ass.PoissonRatio.X)
				arr.append(ass.YoungModulus.X)
				arr.append(ass.ThermalExpansionCoefficient.X)
				arr.append(ass.Density)
				arr.append(ass.ShearModulus.X)
				arr.append(ass.DampingRatio)
			
				if assClass == StructuralAssetClass.Metal:
					arr.append(ass.MinimumYieldStress)
				elif assClass == StructuralAssetClass.Concrete:
					arr.append(ass.ConcreteCompression)
	if not arr == None and len(arr) > 0:					
		return arr

#mats = tolist(UnwrapElement(IN[0]))

# getting all materials in the document... remove this and uncomment the line above to use the IN[0] port...
mats = FilteredElementCollector(doc).OfClass(Material).ToElements()

outList = []

for m in mats:
	outList.append(ReadMaterialProps(m))
	
OUT = outList

Take time to look at the similarities and differences between the C# and python code… they are very similar, but syntax is slightly different. Also, the C# version doesn’t return anything, in my example I am returning an Array with the values (as I assume you want these?)

Cheers,
Dan

2 Likes

@Daniel_Woodcock1 you’re awesome! Thank you so much for answering so quickly!

I think I get the idea of the way to convert it now

Could you also just explain me what is the goal of the tolist function?

Thanks again,

Arthur

@Arthur1, no problem. I know it can be a little confusing at first when most of the examples are written in C# and you need to convert to python! :slight_smile:

Yup, the tolist() function is there to ensure that your input is always a list of objects even if you pass in a single object. For instance, if you plugged in just a single object (material in your case), the for loop would fail as the material is not an iterable object (meaning it’s not a list and you can’t loop through it), the tolist() function checks if the object is not an iterable object and wraps it in a list so it is a list with a single object and we can now loop through it (even though the list length is 1).

Hope that makes sense!

Cheers,
Dan

@Daniel_Woodcock1, yes it makes totally sense now

Thank you a lot for the explanations and for the script :slight_smile:

Arthur

No problem @Arthur1, don’t forget to mark as Solved using the checkbox button. :slight_smile: