Ok… hope you’re sitting down for this one as I got a bit wordy… Sorry in advance.
First up, this is all likely a VERY bad idea. Revit is an extremely complex system and iterating over a wide set of options so you can find an optimal value when you could just do similar iterations in an external database and find the resulting optimal via multi-objective optimization is likely a more stable and complete way to go. That said, you and others have asked for it, so I unleash this onto the world. Use this at your own risk and with great caution.
Onto the ‘how to’ for transaction based testing of results.
Because you’re trying to work with the computed volume, the usual methods for Revit interaction via Dynamo are invalidated. This is because Dynamo wraps all results in a single transaction (This post by @Konrad_K_Sobon is my goto for explaining this - he breaks down the why as well as I ever could), and as you noticed Revit can’t compute the volume until the transaction is done. So since you were using a single transaction (even inside the loop that is the result), you only ever saw the ‘last’ volume value which was returned as that was the state the parameter was in when you closed the transaction.
Side note: Calculated built-in parameters are the Schrödinger’s cat of Revit. When you open the box (close the transaction) the cat (parameter) will report whatever it’s status is, but while the box is closed (transaction is open) the cat (parameter) exists in all possible states (values).
So since you need to get multiple transactions inside one event, but likely don’t want to clutter your undo menu and risk corrupting your data set with so many ‘set, get, start again’ transactions we have to leverage transaction’s big brother: Transaction Groups. The psudo code is something like this:
First close the transaction that is likely open - sorry to say you’ll likely suffer with other aspects of Dynamo-Revit interaction as a result of this, but you’re stuck going full python build up on much (all?) of this anyway so that shouldn’t be too much of an issue.
Create a transaction group which we’ll eventually roll back, and start the transaction group.
For each value you want to iterate over, create a new named transaction, perform the stuff you want to perform, append the data results, and commit the transaction to the database.
When you’re done with the list you want to iterate over, roll-back the transaction group so it’s like you were never there.
Overall a case like yours looks something like this:
And the Revit model starts and finishes looking like this (note the complete lack of undo capability):
And the graph which does this looks like this:
So… if all of that sounded scary, it’s because it is. This is a VERY big dive into completely code based exploration, in a way which doesn’t even attempt to parse out any errors which will likely occur (wall joins, elements no longer connected after modification, host not within a wall, etc.).
So what would I recommend instead? Look hard at moving to a Refinery based workflow. If you’re curious give it a shot and post back, I’ll try and help out there as well (though perhaps in not as in depth of a dive - there is less confusion there after all).
Edit: Added the graph in the example
calcVolume with transactions.dyn (10.2 KB)