PDA

View Full Version : 2014 Very Slow: Advice to Speed up SiteSubRegion Generation



sam.zielke437771
2014-01-08, 11:43 PM
Hello

I am importing roads and terrain from a CAD program into Revit. My addin creates 1 large TopographySurface and uses SiteSubRegions to represent a road/terrain/football field/etc in Revit. So when I import this data I create many SiteSubRegions (the number of SiteSubRegions is usually 100>x<1000) and add them all to the same TopographySurface (1 large surface).

As my addin starts to add many SiteSubRegions to the 1 TopographySurface is slows down the addin very seriously. Do you know of a way I could overcome this issue or how I can achieve some sort of efficiency?

I have created a very simple test that demonstrates that the bottleneck is speed is Revit's fault and not my code. My test below performs 2 different operations:

- Creates 1 large TopographySurface (1500 by 1500) and adds 500 SiteSubRegions (2 by 1998) to that TopographySurface. This operation takes 12 MINUTES to execute. Its crazy! Can you suggest any way I could speed this up, overcome the timing issue or just anything.
- Creates 500 TopographySurfaces (4 by 1500) & each TopographySurface has 1 SiteSubRegion (2 by 1998) added to it. This operation takes 3 minutes to execute - still far too long for my liking. So essentially I have the exact same terrain outcome as the above operation but it takes far less time to produce in my addin. The problem is that the user ends up with lots and lots of (unnecessary) TopographySurfaces in their project which is not what I want.
*Relevant information: The test is run in an empty (new) Revit Construction Project. The test is run in Revit 2014.

Any advice on how to speed up my addin when generating TopographySurfaces & SiteSubRegions would be greatly appreciated. Maybe if I made my Addin non-modal? Is it possible to create CoRoutines in Revit - where the addin will create a small part of a SiteSubRegion then pause the addin operation and wait till the next clock step to continue the operation again. That will allow the user to continue using Revit whilst the addin is running - but it wont necessarily speed up generation. Is that possible?


Here's my test that I encourage you to run so you can see just how slow it is:

[TransactionAttribute(TransactionMode.Manual)]
[RegenerationAttribute(RegenerationOption.Manual)]
public class MyGroup : IExternalCommand
{
public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
{
UIApplication uiApp = commandData.Application;
Document doc = uiApp.ActiveUIDocument.Document;
Transaction trans = new Transaction(doc);
trans.Start("Lab");

int LOOPS = 500;

#region Create 1 Topogrpahy Surface w 500 SiteSubRegions: Takes 12 minutes to execute
DateTime start = DateTime.Now;
List<XYZ> pnts = new List<XYZ>();
pnts.Add(new XYZ(0, 0, 0));
pnts.Add(new XYZ(LOOPS * 3, LOOPS * 3, 0));
pnts.Add(new XYZ(0, LOOPS * 3, 0));
pnts.Add(new XYZ(LOOPS * 3, 0, 0));
TopographySurface surface = TopographySurface.Create(doc, pnts);

// Create 500 SiteSubRegions to test efficiency
for (int i = 0; i < LOOPS; i++)
{
double x = (i * 3) + 1;
double y = 1;
double w = 2;
double h = 1998;

List<Curve> curves = new List<Curve>();
curves.Add(doc.Application.Create.NewLine(new XYZ(x, y, 0), new XYZ(x + w, y, 0), true));
curves.Add(doc.Application.Create.NewLine(new XYZ(x + w, y, 0), new XYZ(x + w, y + h, 0), true));
curves.Add(doc.Application.Create.NewLine(new XYZ(x + w, y + h, 0), new XYZ(x, y + h, 0), true));
curves.Add(doc.Application.Create.NewLine(new XYZ(x, y + h, 0), new XYZ(x, y, 0), true));

CurveLoop cLoop = CurveLoop.Create(curves);
List<CurveLoop> curveLoops = new List<CurveLoop>();
curveLoops.Add(cLoop);
SiteSubRegion reg = SiteSubRegion.Create(doc, curveLoops, surface.Id);
}

DateTime end = DateTime.Now;
TaskDialog.Show("Duration: ", "Duration 1: " + (end - start).TotalSeconds);
#endregion

//trans.RollBack();

#region Create 1 Topogrpahy Surface for every SiteSubRegion created (500 in total): Takes 3 minutes to execute
start = DateTime.Now;

for (int i = 0; i < LOOPS; i++)
{
double space = 1;
double x = (i * 5) + 1;
double y = 1;
double w = 2;
double h = 1998;

List<XYZ> pnts2 = new List<XYZ>();
pnts2.Add(new XYZ(x-space, y-space, 0));
pnts2.Add(new XYZ(x+w+space, y+h+space, 0));
pnts2.Add(new XYZ(x-space, y + h + space, 0));
pnts2.Add(new XYZ(x + w + space, y - space, 0));
TopographySurface surface2 = TopographySurface.Create(doc, pnts2);

List<Curve> curves = new List<Curve>();
curves.Add(doc.Application.Create.NewLine(new XYZ(x, y, 0), new XYZ(x + w, y, 0), true));
curves.Add(doc.Application.Create.NewLine(new XYZ(x + w, y, 0), new XYZ(x + w, y + h, 0), true));
curves.Add(doc.Application.Create.NewLine(new XYZ(x + w, y + h, 0), new XYZ(x, y + h, 0), true));
curves.Add(doc.Application.Create.NewLine(new XYZ(x, y + h, 0), new XYZ(x, y, 0), true));

CurveLoop cLoop = CurveLoop.Create(curves);
List<CurveLoop> curveLoops = new List<CurveLoop>();
curveLoops.Add(cLoop);
SiteSubRegion reg = SiteSubRegion.Create(doc, curveLoops, surface2.Id);
}

end = DateTime.Now;
TaskDialog.Show("Duration: ", "Duration 2: " + (end - start).TotalSeconds);
#endregion

trans.Commit();

return Result.Succeeded;
}
}

Maxence DELANNOY
2014-01-09, 08:40 AM
I don't think you can speed up a lot this kind of task. But I will first use Stopwatch (http://msdn.microsoft.com/fr-fr/library/system.diagnostics.stopwatch(v=vs.110).aspx) to measure the time because it is more accurate. Measure time for each sub operation in your loop to find what is slow.

When you create your lists in your loop, pass the capacity to the constructor and maybe you can use an array instead of a list:


List<XYZ> pnts2 = new List<XYZ>(4);

Reuse your XYZ instead of recreating one :



var p0 = new XYZ(x, y, 0);
var p1 = new XYZ(x + w, y, 0);
var p2 = new XYZ(x + w, y + h, 0);
var p3 = new XYZ(x, y + h, 0);
curves.Add(doc.Application.Create.NewLine(p0, p1 , true));
curves.Add(doc.Application.Create.NewLine(p1 , p2, true));
curves.Add(doc.Application.Create.NewLine(p2, , true));
curves.Add(doc.Application.Create.NewLine(p3 , p0, true));


Try using Line.CreateBound() instead of doc.Application.Create.NewLine which is obsolete.

But the first thing to do is to find exactly the line which takes a long of time

sam.zielke437771
2014-01-10, 01:27 AM
Thanks for the reply :)

It turns out you can speed up FamilyInstance (beam) generation/re-rendering by disabling Automatic Joining - see link. So this is a way to drastically increase the speed of beam creation.

Does anyone know of something similar I could do for TopographySurfaces and SiteSubRegions?

http://www.revitcity.com/forums.php?action=viewthread&thread_id=29248