Trouble with Setting Formulas using parameter values for Revit Families (HELP with Family Parametric Purge Graph)

I would first like to say hello! This would be my first post so bare with me…

Graph Purpose: The purpose of the graph I am writing is to get the values of all of the parameters from all of the families in the given category that live in the model and override their respective formulas. Essentially I want the families in the model to exist but delete the parametric capabilities so I can give our client the Revit model directly. Reason for this is because I don’t want the client to have our families we developed in house, but still be able to give the Revit file as it was designed, instead of exporting to 3D AutoCAD where they can’t use any of the model at all.

Problem: I am having issues using DanEDU custom node Family.SetFormulaByName. From what I can see when I use the Family.GetForulaByName to test and see if I am getting everything I want to override (I used it as a test to see that I was getting the families I wanted and their respective Formulas based on their parameter names); I know I did that part correctly as far as document and parameterName are concerned. The problem I am having is when I get the list of values from DanEDU custom node Family.SetFormulaByName, it only has writes to 93 formulas and not the 3665 I want to write too.

I need help with this one because I am at a dead end.

Attached below is the graph and the .dyn file
Edit: I cleaned up the graph so you can follow the node connections better and added the file I wrote as well now.


Nuke.dyn (37.7 KB)

I believe that you have to be in the family environment to set these values, though @erfajo would know better and may weigh in later. This mimics what you would have to do in real Revit as well - reading a formula is doable in the project via edit type, setting the formula requires opening the family in th family editor.

For now (until someone more familiar weighs in), try saving out the families as a library, and editing them via background open processing (Rhythm package), loading them into the document overriding the family but not parameter values, and then closing the family document.

Be sure to experiment on a contained data set (not the client model, small family library to start with).

Take your time I’m not in a rush, I still have a couple of weeks before they want the model file.

I’ll look into what you suggested @jacob.small as far as opening them up separately. Thank you for the suggestion, and the referral.

I have a feeling I’m on the right track, I just need someone with scripting experience to hopefully tie it together.

I have been able to remove the formula reference from a family within a project file using python/API script but cannot seem to be able to change the value afterwords. The formula is gone but the value is the same. And the changes are saved to the families within the project.

The script works from the project and can iterate over multiple families/familytypes/instances but still working on it to fix the value setting and to make it iterate more intuitively. For now, if you have the time, could you test it and see if it works for you? Code is below:

import clr

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

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

# class for overwriting loaded families in the project
class FamOpt1(IFamilyLoadOptions):
    def __init__(self): pass
    def OnFamilyFound(self,familyInUse, overwriteParameterValues): return True
    def OnSharedFamilyFound(self,familyInUse, source, overwriteParameterValues): return True

def changeParam(f1,name,result):
	famdoc = doc.EditFamily(f1)
	try:
	    trans1.EnsureInTransaction(famdoc)
	    famMan = famdoc.FamilyManager
	    par_name = [a for a in famMan.Parameters if a.Definition.Name==name][0]
	    temp = []
	    temp.append(par_name.Formula)
	    famMan.SetFormula(par_name,None)
	    #famMan.Set(par_name,val)
	    temp.append(par_name.Formula)
	    temp.append(par_name.IsDeterminedByFormula)
	    #pars = [a.AsString() for a in par_name.AssociatedParameters]
	    #temp.append(pars)
	    trans1.ForceCloseTransaction()
	    famdoc.LoadFamily(doc, FamOpt1())
	    result.append(temp)
	except Exception, e:
	    result.append([False,e])
	    trans1.ForceCloseTransaction()  
	famdoc.Close(False)

def unwrapping(ele):
	if type(ele).__name__ == "Family":
		f1 = UnwrapElement(ele)
	elif type(ele).__name__ == "FamilyType":
		f1 = UnwrapElement(ele.Family)
	else:
		f1 = UnwrapElement(ele.Type.Family)
	return f1

Note that this is only the function definition to call within Python (changeParam()) so that you can set it up how you want with your own for loops. One example would be:

trans1 = TransactionManager.Instance
trans1.ForceCloseTransaction() #just to make sure everything is closed down
result = []
if hasattr(IN[0], "__iter__") == True and hasattr(IN[1][0], "__iter__") == True:
	for i,j in zip(IN[0],IN[1]):
		f1 = unwrapping(i)
		for y in j:
			changeParam(f1,y,result)
elif hasattr(IN[1], "__iter__") == True and hasattr(IN[1], "__iter__") == True:
	for i,j in zip(IN[0],IN[1]):
		f1 = unwrapping(i)
		changeParam(f1,j,result)
elif hasattr(IN[1], "__iter__") == False and hasattr(IN[1], "__iter__") == True:
	f1 = unwrapping(IN[0])
	for j in IN[1]:
		changeParam(f1,j,result)
elif hasattr(IN[1], "__iter__") == False and hasattr(IN[1], "__iter__") == False:
	f1 = unwrapping(IN[0])
	changeParam(f1,IN[1],result)

The first 3 lines are required before running. This set of if/elif statements allow you to determine how you want to iterate through lists. In this case, it can handle:

  • a list of elements and nested list, where each element has a list of parameters to change
  • a list of elements and single list of parameters, in this case each element is matched in order to a single parameter
  • a single element and a list of parameters to change on it
  • a single element and a single parameter to change

The if statements are up to you to change if you want a certain outcome. OUT = result, where result has a list for each element containing: formula that was used before the script, formula after (should be null), and IsDeterminedByFormula (a boolean).

Edit: I guess you could just use a SetParameterValueByName node afterwards and it would change the value in the family doc as well.

@erfajo Exactly, I want to set 3665 formulas but it keeps pulling up 93 which is weird considering I was able to pull up all 3665 formula values with the Family.GetFormulaByName node. You would think it would work the same way for setting them as it does in getting the values for the formulas.

Awesome to hear that a new release is coming out soon!

I should’ve mentioned earlier that I am not a programmer by any means, I just tend to copy functionality with code other’s write from time to time. So with that in mind…I have no problem running the script for you so long as you spoon feed me how to run it.

@erfajo I used the FamilyDocument.SetFormulaByName and I am still getting the same result as the Family.SetFormulaByName|DanEDU.

On a side note, I did notice that the FamilyDocument.GetFormulaByName node got the same number of parameters 3665 but it wasn’t in the same order as the Family.GetFormulaByName|DanEDU, where the formulas matched the order for the parameter names it listed.

What’s new about the FamilyDocument.GetFormulaByName node is that it’s not in the same order as the list for the parameter names, whereas Family.GetFormulaByName|DanEDU got the correct number of parameters 3665 and the order in which they come as listed by the parameter names, as you can see in the image below.

Nuke%20(Using%20Orchid%20and%20DanEDU%20side%20by%20side)

Nuke (Using Orchid and DanEDU side by side).dyn (38.7 KB)

1 Like

@erfajo The file is too large for the forum, so the link to download it is below! Essentially if you go to the 3D space or also sheet ZS-001 on the template file you will see the families I want to override the formulas with…We’ll see what happens! Thank you for checking this out for me!

https://drive.google.com/file/d/1u2q3ICSMpRubR6FkXzQtyqiMBeIEuLTF/view?usp=sharing

Saving your families as a library periodically is a beat practice to avoid data loss in the event of a corrupt family anyway, so this shouldn’t be an issue @erfajo. :smiley: