Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve performances for computational intensive loops #391

Open
cesarecaoduro opened this issue Dec 29, 2022 · 3 comments
Open

Improve performances for computational intensive loops #391

cesarecaoduro opened this issue Dec 29, 2022 · 3 comments
Labels
enhancement 📢 Issues describing an enhancement or pull requests adding an enhancement.

Comments

@cesarecaoduro
Copy link
Collaborator

We have to think on a strategy to improve performances when we have an high number of computations to be performed (i.e. PointAt, PointAtLenght, etc.) along a curve.

@cesarecaoduro cesarecaoduro added the enhancement 📢 Issues describing an enhancement or pull requests adding an enhancement. label Dec 29, 2022
@d3ssy
Copy link
Collaborator

d3ssy commented Jan 6, 2023

Performance hasn't seemed to be an issue in typical use cases. What performance bottlenecks are affecting users, for which particular methods, with what inputs?

@cesarecaoduro
Copy link
Collaborator Author

This is the code where I have performances issues (don't worry about how I get to the curves construction)

increment = 1.0;

/// Create the alignment
foreach (var entity in alignment.Entities)
{
    switch (entity.EntityType)
    {
        case EntityType.Tangent:
            crvs.Add(new Line(
                entity.StartPoint.ToGShark(),
                entity.EndPoint.ToGShark()
                ));
            break;

        case EntityType.Arc:
            crvs.Add(new Arc(
                entity.StartPoint.ToGShark(),
                entity.MidPoint.ToGShark(),
                entity.EndPoint.ToGShark()
                ));
            break;
        case EntityType.Spiral:
            var prev = alignment.Entities.Where(w => w.Id == entity.Prev).First();
            var next = alignment.Entities.Where(w => w.Id == entity.Next).First();
            crvs.Add(entity.ToSpiral(prev, next, increment));
            break;
    }
}
var alCurve = new PolyCurve(crvs);
Console.WriteLine("-------- Alignment --------");
Console.WriteLine($"Point at 0.0: ${alCurve.PointAtNormalizedLength(0.0)}");
Console.WriteLine($"Point at 0.5: ${alCurve.PointAtNormalizedLength(0.5)}");
Console.WriteLine($"Point at 1.0: ${alCurve.PointAtNormalizedLength(1.0)}");
Console.WriteLine($"Alignment 2D Length: ${alCurve.Length}");

///Create the profile
var profile = alignment.Profiles.First();
List<Point3> crvPts = new List<Point3>();
int paraCurveSub = 2;
foreach (var entity in profile.Entities)
{
    switch (entity.EntityType)
    {
        case EntityType.PVI:
            crvPts.Add(entity.PVI.ToGShark());
            break;
        case EntityType.Tangent:
            crvPts.AddRange(new List<Point3> {entity.StartPoint.ToGShark(), entity.EndPoint.ToGShark()});
            break;
        case EntityType.ParabolaAsymmetric:
            throw new NotImplementedException("Parabola Asymmetryc not implemented!");
        case EntityType.ParabolaSymmetric:
            var pts = entity.GetParabolaSymmetricPoints(paraCurveSub);
            crvPts.AddRange(entity.GetParabolaSymmetricPoints(paraCurveSub).Select(pt => pt.ToGShark()).ToList());
            break;
    }
}
var prCurve = new PolyLine(crvPts);
Console.WriteLine("\n-------- Profile --------");
Console.WriteLine($"Point at 0.0: {prCurve.PointAtNormalizedLength(0.0)}");
Console.WriteLine($"Point at 0.5: {prCurve.PointAtNormalizedLength(0.5)}");
Console.WriteLine($"Point at 1.0: {prCurve.PointAtNormalizedLength(1.0)}");
Console.WriteLine($"Profile 2D Length: {prCurve.Length}");


/// Generate 3D alignment curve
List<double> allStations = new List<double>();

Stopwatch sw = new Stopwatch();
sw.Start();

double alEndSStation = alignment.Stations.Last();
double prStartStation = profile.Stations.First();
double prEndStation = profile.Stations.Last();

var profileStations = profile.Stations.Select(s => s -= alignment.StartStation).ToList();
var alignmentStations = alignment.Stations.Select(s => s -= alignment.StartStation).ToList();

double start = profileStations.First() > alignmentStations.First() ? profileStations.First() : alignmentStations.First();
double end = profileStations.Last() > alignmentStations.Last() ? alignmentStations.Last() : profileStations.Last();

allStations.AddRange(alignmentStations);
allStations.AddRange(profileStations);

double xs = start;
while (xs <= end)
{
    allStations.Add(xs);
    xs += increment;
}

allStations = allStations.Distinct().ToList(); /// remove duplicates
allStations.Sort(); // order list

List<Point3> pts3d = new List<Point3>();
Console.WriteLine("\n-------- 3D Curve --------");
Console.WriteLine($"{allStations.Count} points to be evaluated evaluated...");
Console.WriteLine($"Start evaluation...");
sw.Reset();
sw.Start();
foreach (double s in allStations)
{
    var ptOnAl = alCurve.PointAtLength(s);
    var pl = new Plane(new Point3(s + alignment.StartStation, 0, 0), GShark.Geometry.Vector3.XAxis);
    var inters = Intersect.CurvePlane(prCurve, pl);
    if (inters.Count > 0 ){
        pts3d.Add(new Point3(ptOnAl.X, ptOnAl.Y, inters.First().Point.Y));   
    }
}
Console.WriteLine($"{pts3d.Count} points evaluated in {sw.Elapsed.TotalSeconds} seconds");
var crv3d = new PolyLine(pts3d);

Console.WriteLine("\n-------- 3D Curve point test--------");
Console.WriteLine($"Curve 3D Length: {crv3d.Length}");
sw.Reset();
Console.WriteLine($"Point at 0.0: {crv3d.PointAtLength(0.0)} evaluated in {sw.Elapsed.TotalMilliseconds} ms");
sw.Reset();
Console.WriteLine($"Point at 0.5: {crv3d.PointAtLength(crv3d.Length/2.0)} evaluated in {sw.Elapsed.TotalMilliseconds} ms");
sw.Reset();
Console.WriteLine($"Point at 1.0: {crv3d.PointAtLength(crv3d.Length)} evaluated in {sw.Elapsed.TotalMilliseconds} ms");
Console.ReadLine();

Now this basically takes XY from one curve (this curve is the alignment and is located on the XY plane) and the Z from another curve (this curve is the vertical profile and is a curve on XY plane). The resultant point is a 3D point that is then used to create a 3D curve.

-------- Alignment --------
Point at 0.0: $Point3: (0,0,0)
Point at 0.5: $Point3: (671.578471,56.569064,0)
Point at 1.0: $Point3: (1399.209450,99.964765,0)
Alignment 2D Length: $1470.8006366277389

-------- Profile --------
Point at 0.0: Point3: (0,-7.225,0)
Point at 0.5: Point3: (735.414472,-15.070705,0)
Point at 1.0: Point3: (1470.8,-4,0)
Profile 2D Length: 1470.937737872652

-------- 3D Curve --------
1483 points to be evaluated evaluated...
Start evaluation...
1483 points evaluated in 120.2286311 seconds

As you can see 120'' (sometimes even more) to calculate 1500 points are probably not ideal (Dynamo takes a fraction of second)

@d3ssy
Copy link
Collaborator

d3ssy commented Jan 11, 2023

We can write individual performance tests to benchmark some of the more computationally intensive methods.

I set up a quick test with a similar use case to check and I'm not getting the same results as you, so there's something else going on here... Not that 1.8s is fast in terms of performance, but it's certainly not 120s!

image

image

Possible causes that come to mind are:

  • Very long curves? Does length affect the intersection algo?
  • A particular intersection that is causing some local optimum in the intersection algo or it's getting stuck with particular inputs?
  • Accessing list via Linq (inters.First())?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement 📢 Issues describing an enhancement or pull requests adding an enhancement.
Projects
None yet
Development

No branches or pull requests

2 participants