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 @JacobSmall 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.

just to be sure of what the problem is.

you have 3665 formulas in some families you want to change, but you are only able to set 93!?

I am at the moment recoding all my nodes into zerotouch nodes, which means that I recode everything in csharp. While doing that I have encountered some problems, one of these is that a family must hold a valid type. It is possible to have a family in Revit which has a default type, meaning the type field is grayed out.

Coding in Python doesnt see this as a problem, and will in some cases accept this “error” and set a formula… in csharp is this not possible… It is an error every time!

Could you try to see that where the algorithm fails it is families where there isnt any type present (they have only a “default” type that is not set). If that is the case, then I think that this could be the problem.

I am at the moment considering several options to hand this problem in csharp and hope I will have something that can solve this problem asap.

deleting both the formula and parameter value will be an option in the next release :slight_smile:

@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.

To “get” something is not the same as to “set” something. However, I was also suprised that it should be a problem to set a formula, since it is only dependent on the parameter in the family and has no connection with the types as such.

My solution so far is to make a default type named the same as the family, but it is 2nd best solution…

@dfernandez

did you solve this issue?

If not, could I suggest you test these nodes in my new package? I am deprecating the DanEDU package when I finish coding all my present nodes in the DanEDU package as ZeroTouch nodes. I am half way now. I hope to be ready with all nodes before dynamo is released as version 2. Some nodes in the DanEDU package will not work in dynamo ver. 2. and I will not upgrade them, the entire package will be deprecated.

The new package can be found as “Orchid”. This package works both in Dynamo 1.3.x and in Dynamo 2.0

@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)

Thanks for testing, I will take a look at it.

But as the first error, I can see that families with a default type was the problem.

concerning the FamilyDocument.GetFormulaByName node… that should be the same order. Can you share a revit file I can test on, for in my test is the order correct!?

@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

I have now been trying, and I end up in the same problem no matter how I try. The problem is opening families as documents from a project in the background. Then documents only exist in the memory, and then I can’t make a transaction for the document somehow.

However, if I save the families I want to work on to a folder, and then run whatever process I want, then I don’t run into problems.

So I am afraid that this is the answer for now… save your families and then run what you need to do.

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:

Agree, but I took the challenge to see if I could work on background open documents. I didn’t win that game :slight_smile:

I have now deprecated the “DanEDU Dynamo” package in favor of the new package “Orchid”. I had a hope to finish all nodes before Revit 2019 and Dynamo 1.3.3 was released, but I didn’t succeed doing that. Therefore is the old nodes existing side by side with new nodes. New ‘ZeroTouch’ nodes will replace the old nodes regularly until all nodes have been transferred… under the new package name “Orchid”

Family nodes present now…

2 Likes