/// <summary> /// This procedure contains the user code. Input parameters are provided as regular arguments, /// Output parameters as ref arguments. You don't have to assign output parameters, /// they will have a default value. /// </summary> private void RunScript(List <object> Goals, bool Reset, bool Step, ref object A, ref object B, ref object C, ref object D, ref object E, ref object F) { // <Custom code> if (Reset) { PS = new KangarooSolver.PhysicalSystem(); counter = 0; GoalList.Clear(); foreach (IGoal G in Goals) //Assign indexes to the particles in each Goal: { PS.AssignPIndex(G, 0.0001); // the second argument is the tolerance distance below which points combine into a single particle GoalList.Add(G); } } if (Step) { PS.SimpleStep(GoalList); counter++; } A = PS.GetOutput(GoalList); B = counter; C = PS.GetAllMoves(GoalList); D = PS.GetAllWeightings(GoalList); E = PS.GetPositionArray(); var Names = new List <String> [PS.ParticleCount()]; for (int i = 0; i < PS.ParticleCount(); i++) { Names[i] = new List <String>(); } for (int i = 0; i < GoalList.Count; i++) { var FullName = GoalList[i].ToString(); Char splitter = '.'; var Name = FullName.Split(splitter); if (Name[0] != "KangarooSolver") { Name = FullName.Split('_', '+'); } var G = GoalList[i] as IGoal; for (int j = 0; j < G.PIndex.Count(); j++) { Names[G.PIndex[j]].Add(Name[2]); } } F = Names; // </Custom code> }
/// <summary> /// This procedure contains the user code. Input parameters are provided as regular arguments, /// Output parameters as ref arguments. You don't have to assign output parameters, /// they will have a default value. /// </summary> private void RunScript(List <object> Goals, bool Reset, bool Step, ref object A, ref object B) { if (Reset) { PS = new KangarooSolver.PhysicalSystem(); counter = 0; GoalList.Clear(); foreach (IGoal G in Goals) //Assign indexes to the particles in each Goal: { PS.AssignPIndex(G, 0.0001); // the second argument is the tolerance distance below which points combine into a single particle GoalList.Add(G); } } if (Step) { PS.Step(GoalList, true, 1); counter++; } A = PS.GetOutput(GoalList); B = counter; }
/// <summary> /// This is the method that actually does the work. /// </summary> /// <param name="DA">The DA object is used to retrieve from inputs and store in outputs.</param> protected override void SolveInstance(IGH_DataAccess DA) { //-----------------------------------------------------------------INPUT----------------------------------------------------------------------------// List<IGoal> permanentGoals = new List<IGoal>(); DA.GetDataList(0, permanentGoals); List<IGoal> loadGoals = new List<IGoal>(); DA.GetDataList(1, loadGoals); double fStart = 1.0; DA.GetData(2, ref fStart); double fStep = 0.1; DA.GetData(3, ref fStep); double angle = 15.0; DA.GetData(4, ref angle); angle *= Math.PI / 180.0; double displ = 2.0; DA.GetData(5, ref displ); double threshold = 1e-15; DA.GetData(6, ref threshold); int equilibriumIter = 100; DA.GetData(7, ref equilibriumIter); bool opt = false; DA.GetData(8, ref opt); int maxIterations = 1000; //--------------------------------------------------------------CALCULATE----------------------------------------------------------------------------// //-------------------VALUES TO STORE----------------------------// //Position lists List<Point3d> initialPositions = new List<Point3d>(); List<Point3d> previousPositions = new List<Point3d>(); List<Point3d> currentPositions = new List<Point3d>(); DataTree<Point3d> vertexPositions = new DataTree<Point3d>(); //Goal output lists List<object> previousGOutput = new List<object>(); List<object> currentGOutput = new List<object>(); DataTree<object> outputGoals = new DataTree<object>(); //Load factors and displacements List<double> loadfactors = new List<double>(); List<double> displacementsRMS = new List<double>(); //-------------------K2 PHYSICAL SYSTEM----------------------------// //Initialise Kangaroo solver var PS = new KangarooSolver.PhysicalSystem(); var GoalList = new List<IGoal>(); //Assign indexes to the particles in each Goal foreach (IGoal pG in permanentGoals) { PS.AssignPIndex(pG, 0.01); GoalList.Add(pG); } foreach (IGoal lG in loadGoals) { PS.AssignPIndex(lG, 0.01); GoalList.Add(lG); } //Store initial loads List<Vector3d> initialLoads = new List<Vector3d>(); for (int i = 0; i < loadGoals.Count; i++) { initialLoads.Add(loadGoals[i].Move[0]); } //-------------------INITIALISE VALUE LISTS----------------------------// //Initial vertex positions Point3d[] initPos = PS.GetPositionArray(); foreach (Point3d pt in initPos) { initialPositions.Add(pt); previousPositions.Add(pt); currentPositions.Add(pt); } //Initial goal output List<object> initGOutput = PS.GetOutput(GoalList); for (int i = 0; i < permanentGoals.Count; i++) { previousGOutput.Add(initGOutput[i]); currentGOutput.Add(initGOutput[i]); } //-------------------LOAD INCREMENT LOOP----------------------------// bool run = true; int iter = 0; double LF; double BLF = 0.0; double preRMS = 0.0; while (run && iter < maxIterations) { LF = fStart + (fStep * iter); loadfactors.Add(LF); //Scale load goals in each iteration for (int i = 0; i < loadGoals.Count; i++) { int index = GoalList.Count - loadGoals.Count + i; Vector3d scaledLoad = initialLoads[i] * LF; GoalList[index] = new KangarooSolver.Goals.Unary(GoalList[index].PIndex[0], scaledLoad); } //Solve equilibrium for given load increment int counter = 0; do { PS.Step(GoalList, true, threshold); counter++; } while (PS.GetvSum() > threshold && counter < equilibriumIter); //Update value lists GH_Path path = new GH_Path(iter); //Get new equilibrium positions and update position lists Point3d[] newPositions = PS.GetPositionArray(); for (int k = 0; k < initialPositions.Count; k++) { previousPositions[k] = currentPositions[k]; currentPositions[k] = newPositions[k]; if (opt) { vertexPositions.Add(newPositions[k], path); } } //Get new goal output and update goal output lists List<object> newGOutput = PS.GetOutput(GoalList); for (int m = 0; m < permanentGoals.Count; m++) { previousGOutput[m] = currentGOutput[m]; currentGOutput[m] = newGOutput[m]; if (opt) { outputGoals.Add(newGOutput[m], path); } } //Does buckling occur? List<Vector3d> nodalDisplacements = calcDisplacement(currentPositions, initialPositions); double curRMS = calcDisplacementsRMS(nodalDisplacements); displacementsRMS.Add(curRMS); bool buckled = isBuckled(curRMS, preRMS, iter, fStart, fStep, angle); bool deflected = isDeflectionTooBig(nodalDisplacements, displ); if (buckled || deflected) { run = false; BLF = LF - fStep; } //Update preRMS = curRMS; iter++; } //-----------------------FLAG BUCKLED STATE----------------------------// if (BLF >= 1.0) { this.Message = "Works!"; } else { this.Message = "Buckles!"; } //-----------------------WARNING----------------------------// //If the maximum number of iterations has been reached if (iter == maxIterations) { this.AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, "Buckling did not occur within " + maxIterations + " load increments. Adjust load-step"); } //-----------------------UPDATE VALUE LISTS----------------------------// //If opt is false then add results from last two iterations if (!opt) { for (int i = 0; i < currentPositions.Count; i++) { vertexPositions.Add(previousPositions[i], new GH_Path(0)); vertexPositions.Add(currentPositions[i], new GH_Path(1)); } for (int j = 0; j < currentGOutput.Count; j++) { outputGoals.Add(previousGOutput[j], new GH_Path(0)); outputGoals.Add(currentGOutput[j], new GH_Path(1)); } } //---------------------------------------------------------------OUTPUT-------------------------------------------------------------------------------// DA.SetData(0, BLF); DA.SetDataList(1, loadfactors); DA.SetDataList(2, displacementsRMS); DA.SetDataTree(3, vertexPositions); DA.SetDataTree(4, outputGoals); }
/// <summary> /// This is the method that actually does the work. /// </summary> /// <param name="DA">The DA object can be used to retrieve data from input parameters and /// to store data in output parameters.</param> protected override void SolveInstance(IGH_DataAccess DA) { bool reset = false; List <Point3d> FixedPoint = new List <Point3d>(); List <Curve> BoundaryCurves = new List <Curve>(); double SpringStrength = 1, PullStrengthM = 1, PullStrengthC = 1; DA.GetData <Mesh>(0, ref M); //获取第0个输入值 DA.GetData <Mesh>(1, ref TargetMesh); //获取第0个输入值 //DA.GetDataList<Point3d>(1, FV); DA.GetDataList <Curve>(2, BoundaryCurves); //DA.GetDataList<Line>(1, FL); // DA.GetData<int>(2, ref restLength); DA.GetData <double>(3, ref PullStrengthM); DA.GetData <double>(4, ref PullStrengthC); DA.GetData <double>(5, ref SpringStrength); DA.GetData <bool>(6, ref reset); DA.GetDataList <Point3d>(7, FixedPoint); //内部计算过程start //initialize the solver if (reset || initialized == false) { #region reset counter = 0; PS = new KangarooSolver.PhysicalSystem(); Goals = new List <IGoal>(); initialized = true; //get the Mesh points and boundary status //数组转列表 List <Point3d> Pts = new List <Point3d>(M.Vertices.ToPoint3dArray()); List <Point3d> NakedPts = new List <Point3d>(); //var IndexList = Enumerable.Range(0, PS.ParticleCount()).ToList(); List <int> Is = new List <int>(); List <int> NakedIs = new List <int>(); bool[] Naked = M.GetNakedEdgePointStatus(); for (int i = 0; i < M.Vertices.Count; i++) { PS.AddParticle(Pts[i], 1); //add a particle for every mesh vertex Is.Add(i); if (Naked[i]) //{ Goals.Add(new KangarooSolver.Goals.Anchor(i, Pts[i], 10000)); }// fix the boundaries strongly in place { NakedPts.Add(Pts[i]); NakedIs.Add(i); } } //Goals.Add(new KangarooSolver.Goals.OnCurve(NakedPts, BoundaryCurves[0], PullStrengthC)); Goals.Add(new KangarooSolver.Goals.OnCurve(NakedIs, BoundaryCurves[0], PullStrengthC)); //Goals.Add(new KangarooSolver.Goals.OnMesh(Pts, TargetMesh, 1)); Goals.Add(new KangarooSolver.Goals.OnMesh(Is, TargetMesh, PullStrengthM)); double sum_length = 0; for (int i = 0; i < M.TopologyEdges.Count; i++) { Line line = M.TopologyEdges.EdgeLine(i); double length = line.Length; sum_length += length; } double average_length = sum_length / M.TopologyEdges.Count; for (int i = 0; i < M.TopologyEdges.Count; i++) { var Ends = M.TopologyEdges.GetTopologyVertices(i); int Start = M.TopologyVertices.MeshVertexIndices(Ends.I)[0]; int End = M.TopologyVertices.MeshVertexIndices(Ends.J)[0]; //for each edge, a spring with rest length average_length, and strength 1 //Goals.Add(new KangarooSolver.Goals.Spring(Pts[Start], Pts[End], average_length, 1)); Goals.Add(new KangarooSolver.Goals.Spring(Start, End, average_length, SpringStrength)); } for (int j = 0; j < FixedPoint.Count; j++) { int index = PS.FindParticleIndex(FixedPoint[j], threshold, true); Goals.Add(new KangarooSolver.Goals.Anchor(index, FixedPoint[j], 10000)); }// fix the boundaries strongly in place // foreach (IGoal G in Goals) // { // PS.AssignPIndex(G, 0.01); // } //GH_ObjectWrapper ow=new GH_ObjectWrapper(M); //var gl = new KangarooSolver.Goals.Locator(ow); // Goals.Add(gl); //foreach (IGoal G in Goals) //Assign indexes to the particles in each Goal: //{ // PS.AssignPIndex(G, 0.0001); // the second argument is the tolerance distance below which points combine into a single particle // GoalList.Add(G); //} #endregion } else { /* * else * { * int count = Springs.Count; * * for (int i = 0; i < count; i++) * { * Spring S = Springs[i] as Spring; * Point3d Start = PS.GetPosition(S.PIndex[0]); * Point3d End = PS.GetPosition(S.PIndex[1]); * * double LineLength = Start.DistanceTo(End); * if (LineLength > splitLength) * { * Point3d MidPt = 0.5 * (Start + End); * PS.AddParticle(MidPt, 1); * int newParticleIndex = PS.ParticleCount() - 1; * int endIndex = S.PIndex[1]; * //set the end of the original spring to be the newly created midpoint * //and make a new spring from the midpoint to the original endpoint * S.PIndex[1] = newParticleIndex; * S.RestLength = 0.5 * LineLength; * Spring otherHalf = new Spring(newParticleIndex, endIndex, 0.5 * LineLength, 1); * Springs[i] = S; * Springs.Add(otherHalf); * } * else * { * S.RestLength += increment; * Springs[i] = S; * } * } */ //Step forward, using these goals, with multi-threading on, and stopping if the threshold is reached if (counter == 0 || (PS.GetvSum() > threshold && counter < 100)) { PS.Step(Goals, true, threshold); double sum = PS.GetvSum(); counter++; } //内部计算过程end //Output the mesh, and how many iterations it took to converge //object Out = PS.GetOutput(GoalList); //DA.SetData(0, Out); M.Vertices.Clear(); M.Vertices.AddVertices(PS.GetPositions()); } DA.SetData(0, M); List <Point3d> pout = new List <Point3d>(); pout = PS.GetPositions().ToList(); DA.SetDataList(1, pout); //输出第一个输出值 DA.SetData(2, counter); }
/// <summary> /// This is the method that actually does the work. /// </summary> /// <param name="DA">The DA object can be used to retrieve data from input parameters and /// to store data in output parameters.</param> protected override void SolveInstance(IGH_DataAccess DA) { Mesh TargetMesh = new Mesh(); List <Point3d> Points = new List <Point3d>(); double PullStrengthM = 100, CollideStrength = 1; double radius = 1; bool reset = true; double k_SpecialPoint = 1, g_SpecialPoint = 1, k_SpecialCurve = 1, g_SpecialCurve = 1, k_ReferCurve = 1, g_ReferCurve = 1, k_ReferSurface = 1, g_ReferSurface = 1; List <Point3d> SpecialPoints = new List <Point3d>(); List <Curve> SpecialCurves = new List <Curve>(); List <Curve> ReferCurves = new List <Curve>(); List <Point3d> ReferCurvePoints = new List <Point3d>(); List <Surface> ReferSurfaces = new List <Surface>(); List <Point3d> ReferSurfacePoints = new List <Point3d>(); DA.GetData <Mesh>(0, ref TargetMesh); //获取第0个输入值 DA.GetDataList <Point3d>(1, Points); DA.GetData <double>(2, ref PullStrengthM); DA.GetData <double>(3, ref CollideStrength); DA.GetData <double>(4, ref radius); //暂无 DA.GetData <double>(6, ref threshold); DA.GetData <double>(7, ref subIteration); DA.GetData <double>(8, ref maxIteration); DA.GetData <bool>(9, ref reset); DA.GetDataList <Point3d>(10, SpecialPoints); DA.GetData <double>(11, ref k_SpecialPoint); DA.GetData <double>(12, ref g_SpecialPoint); DA.GetDataList <Curve>(13, SpecialCurves); DA.GetData <double>(14, ref k_SpecialCurve); DA.GetData <double>(15, ref g_SpecialCurve); DA.GetDataList <Curve>(16, ReferCurves); DA.GetDataList <Point3d>(17, ReferCurvePoints); DA.GetData <double>(18, ref k_ReferCurve); DA.GetData <double>(19, ref g_ReferCurve); DA.GetDataList <Surface>(20, ReferSurfaces); DA.GetDataList <Point3d>(21, ReferSurfacePoints); DA.GetData <double>(22, ref k_ReferSurface); DA.GetData <double>(23, ref g_ReferSurface); //内部计算过程start //initialize the solver if (reset || initialized == false) { #region reset counter = 0; PS = new KangarooSolver.PhysicalSystem(); Goals = new List <IGoal>(); initialized = true; //var IndexList = Enumerable.Range(0, PS.ParticleCount()).ToList(); //Goals.Add(new KangarooSolver.Goals.OnCurve(NakedPts, BoundaryCurves[0], PullStrengthC)); //Goals.Add(new KangarooSolver.Goals.OnMesh(Pts, TargetMesh, 1)); Goals.Add(new KangarooSolver.Goals.OnMesh(Points, TargetMesh, PullStrengthM)); Goals.Add(new KangarooSolver.Goals.SphereCollide_wqs(Points, radius, CollideStrength, SpecialPoints, k_SpecialPoint, g_SpecialPoint, SpecialCurves, k_SpecialCurve, g_SpecialCurve, ReferCurves, ReferCurvePoints, k_ReferCurve, g_ReferCurve, ReferSurfaces, ReferSurfacePoints, k_ReferSurface, g_ReferSurface )); //public SphereCollide_wqs(List<Point3d> V, List<Point3d> SV, double radius, double k, double kSV0, double gSV0) //GoalList = new List<IGoal>(); foreach (IGoal G in Goals) //Assign indexes to the particles in each Goal: { PS.AssignPIndex(G, 0.0001); // the second argument is the tolerance distance below which points combine into a single particle //GoalList.Add(G); } #endregion } else { //Step forward, using these goals, with multi-threading on, and stopping if the threshold is reached if (counter == 0 || (PS.GetvSum() > threshold && counter < 100)) { for (int i = 0; i < subIteration; i += 1) { PS.Step(Goals, true, threshold); counter++; } double sum = PS.GetvSum(); } //内部计算过程end //Output the mesh, and how many iterations it took to converge } List <Point3d> pout = new List <Point3d>(); pout = PS.GetPositions().ToList(); DA.SetDataList(0, pout); //输出第一个输出值 DA.SetData(1, counter); List <double> brs = SphereCollide_wqs.brs; DA.SetDataList(2, brs); //输出气泡半径 List <Point3d> pp = Goals[1].PPos.ToList(); DA.SetDataList(3, pp); //输出第一个输出值 }
/// <summary> /// This is the method that actually does the work. /// </summary> /// <param name="DA">The DA object can be used to retrieve data from input parameters and /// to store data in output parameters.</param> protected override void SolveInstance(IGH_DataAccess DA) { double threshold = 1e-3, subIteration = 10, maxIteration = 100; Mesh TargetMesh = new Mesh(); List <Point3d> Points = new List <Point3d>(); List <Curve> BoundaryCurves = new List <Curve>(); List <IGoal> CurvePull = new List <IGoal>(); List <IGoal> MeshSpring = new List <IGoal>(); double PullStrengthM = 1, SpringStiffness = 1, PullStrengthC = 1; int row = 1, column = 1; bool reset = false, bRing = false; DA.GetData <Mesh>(0, ref TargetMesh); //获取第0个输入值 DA.GetDataList <Point3d>(1, Points); //DA.GetDataList<Curve >(2, BoundaryCurves); DA.GetDataList <IGoal>(2, MeshSpring); DA.GetDataList <IGoal>(3, CurvePull); DA.GetData <double>(4, ref SpringStiffness); DA.GetData <double>(5, ref PullStrengthM); //DA.GetData<double>(5, ref PullStrengthC); DA.GetData <int>(6, ref row); column = Points.Count / row; DA.GetData <double>(7, ref threshold); DA.GetData <double>(8, ref subIteration); DA.GetData <double>(9, ref maxIteration); DA.GetData <bool>(10, ref reset); DA.GetData <bool>(11, ref bRing); //内部计算过程start //initialize the solver if (reset || initialized == false) { counter = 0; PS = new KangarooSolver.PhysicalSystem(); Goals = new List <IGoal>(); initialized = true; //grids = new List<List<Point3d>>(); //indexs = new List<int>(); for (int i = 0; i < row; i++) { //List<Point3d> ps = new List<Point3d>(); for (int j = 0; j < column; j++) { PS.AddParticle(Points[i * column + j], 1); } } //拉取到目标mesh Goals.Add(new KangarooSolver.Goals.OnMesh(Points, TargetMesh, PullStrengthM)); //裸露点拉到边界线 Goals.AddRange(CurvePull); Goals.AddRange(MeshSpring); //List<IGoal> GoalList = new List<IGoal>(); foreach (IGoal G in Goals) //Assign indexes to the particles in each Goal: { PS.AssignPIndex(G, 0.0001); // the second argument is the tolerance distance below which points combine into a single particle } numIGoal_in = 1 + CurvePull.Count + MeshSpring.Count; } else { //前numIGoal_in个目标不变,而杆长弹簧力跟节点位置有关 Goals = Goals.GetRange(0, numIGoal_in); Points = PS.GetPositions().ToList(); grids = new List <List <Point3d> >(); for (int i = 0; i < row; i++) { List <Point3d> ps = new List <Point3d>(); for (int j = 0; j < column; j++) { ps.Add(Points[(i * column + j)]); PS.AddParticle(Points[i * column + j], 1); if (bRing && j == column - 1) { ps.Add(Points[(i * column)]); } } grids.Add(ps); } List <double> length_row = new List <double>(); List <double> length_column = new List <double>(); List <List <double> > gridLengths = new List <List <double> >(); //计算各条多线段的长度 for (int i = 0; i < row; i++) { double sumLength = 0; List <double> lengths = new List <double>(); for (int j = 0; j < grids[i].Count - 1; j++) { double length = grids[i][j].DistanceTo(grids[i][j + 1]);; lengths.Add(length); sumLength += length; } //边界线上的多线段长度之和直接固定为首次的结果就好了,避免重叠后导致长度边长 gridLengths.Add(lengths); if (counter == 0) { if (i == 0) { length_row_start = sumLength; } if (i == row - 1) { length_row_end = sumLength; } } else { if (i == 0) { sumLength = length_row_start; } if (i == row - 1) { sumLength = length_row_end; } } length_row.Add(sumLength); } List <double> length_row2 = length_row.GetRange(1, row - 2); double length_row_sum = (length_row.Sum() + length_row2.Sum()) / 2; for (int j = 0; j < grids[0].Count; j++) { double sumLength = 0; for (int i = 0; i < row - 1; i++) { double length = grids[i][j].DistanceTo(grids[i + 1][j]); sumLength += length; } if (counter == 0) { if (j == 0) { length_column_start = sumLength; } if (j == column - 1) { length_column_end = sumLength; } } else { if (j == 0) { sumLength = length_column_start; } if (j == row - 1) { sumLength = length_column_end; } } length_column.Add(sumLength); } List <double> length_column2 = length_column.GetRange(1, column - 2); double length_column_sum = (length_column.Sum() + length_column2.Sum()) / 2; //弹簧 for (int i = 0; i < row; i++) { for (int j = 0; j < grids[i].Count - 1; j++) { double relativeLength = (length_column[j] + length_column[j + 1]) / 2 / length_column_sum; if (bRing && j == grids[i].Count - 2) { Goals.Add(new KangarooSolver.Goals.Spring( i * column + j, i * column, relativeLength * length_row[i] * factor, SpringStiffness * length_row.Sum() / row / length_row[i])); } else { Goals.Add(new KangarooSolver.Goals.Spring( i * column + j, i * column + j + 1, relativeLength * length_row[i] * factor, SpringStiffness * length_row.Sum() / row / length_row[i])); } } } //弹簧 for (int j = 0; j < column; j++) { for (int i = 0; i < row - 1; i++) { double relativeLength = (length_row[i] + length_row[i + 1]) / 2 / length_row_sum; Goals.Add(new KangarooSolver.Goals.Spring( (i + 1) * column + j, i * column + j, relativeLength * length_column[j] * factor, SpringStiffness * length_column.Sum() / column / length_column[j])); } } //Step forward, using these goals, with multi-threading on, and stopping if the threshold is reached PS = new KangarooSolver.PhysicalSystem(); for (int i = 0; i < row; i++) { //List<Point3d> ps = new List<Point3d>(); for (int j = 0; j < column; j++) { PS.AddParticle(Points[i * column + j], 1); } } if (counter == 0 || (vSum > threshold && counter < maxIteration)) { for (int i = 0; i < subIteration; i += 1) { PS.Step(Goals, true, threshold); counter++; } vSum = PS.GetvSum(); } //内部计算过程end //Output the mesh, and how many iterations it took to converge } List <Point3d> pout = PS.GetPositions().ToList(); DA.SetDataList(0, pout); //输出第一个输出值 DA.SetData(1, counter); //List<double> ars = SphereCollide_wqs.ars; //DA.SetDataList(2, ars); //输出第一个输出值 //List<Point3d> pp = Goals[1].PPos.ToList(); // DA.SetDataList(3, pout); //输出第一个输出值 }
/// <summary> /// This is the method that actually does the work. /// </summary> /// <param name="DA">The DA object is used to retrieve from inputs and store in outputs.</param> protected override void SolveInstance(IGH_DataAccess DA) { //-----------------------------------------------------------------INPUT----------------------------------------------------------------------------// List <IGoal> permanentGoals = new List <IGoal>(); DA.GetDataList(0, permanentGoals); List <IGoal> loadGoals = new List <IGoal>(); DA.GetDataList(1, loadGoals); double fStart = 1.0; DA.GetData(2, ref fStart); double fStep = 0.1; DA.GetData(3, ref fStep); double angle = 15.0; DA.GetData(4, ref angle); angle *= Math.PI / 180.0; double displ = 2.0; DA.GetData(5, ref displ); double threshold = 1e-15; DA.GetData(6, ref threshold); int equilibriumIter = 100; DA.GetData(7, ref equilibriumIter); bool opt = false; DA.GetData(8, ref opt); int maxIterations = 1000; //--------------------------------------------------------------CALCULATE----------------------------------------------------------------------------// //-------------------VALUES TO STORE----------------------------// //Position lists List <Point3d> initialPositions = new List <Point3d>(); List <Point3d> previousPositions = new List <Point3d>(); List <Point3d> currentPositions = new List <Point3d>(); DataTree <Point3d> vertexPositions = new DataTree <Point3d>(); //Goal output lists List <object> previousGOutput = new List <object>(); List <object> currentGOutput = new List <object>(); DataTree <object> outputGoals = new DataTree <object>(); //Load factors and displacements List <double> loadfactors = new List <double>(); List <double> displacementsRMS = new List <double>(); //-------------------K2 PHYSICAL SYSTEM----------------------------// //Initialise Kangaroo solver var PS = new KangarooSolver.PhysicalSystem(); var GoalList = new List <IGoal>(); //Assign indexes to the particles in each Goal foreach (IGoal pG in permanentGoals) { PS.AssignPIndex(pG, 0.01); GoalList.Add(pG); } foreach (IGoal lG in loadGoals) { PS.AssignPIndex(lG, 0.01); GoalList.Add(lG); } //Store initial loads List <Vector3d> initialLoads = new List <Vector3d>(); for (int i = 0; i < loadGoals.Count; i++) { initialLoads.Add(loadGoals[i].Move[0]); } //-------------------INITIALISE VALUE LISTS----------------------------// //Initial vertex positions Point3d[] initPos = PS.GetPositionArray(); foreach (Point3d pt in initPos) { initialPositions.Add(pt); previousPositions.Add(pt); currentPositions.Add(pt); } //Initial goal output List <object> initGOutput = PS.GetOutput(GoalList); for (int i = 0; i < permanentGoals.Count; i++) { previousGOutput.Add(initGOutput[i]); currentGOutput.Add(initGOutput[i]); } //-------------------LOAD INCREMENT LOOP----------------------------// bool run = true; int iter = 0; double LF; double BLF = 0.0; double preRMS = 0.0; while (run && iter < maxIterations) { LF = fStart + (fStep * iter); loadfactors.Add(LF); //Scale load goals in each iteration for (int i = 0; i < loadGoals.Count; i++) { int index = GoalList.Count - loadGoals.Count + i; Vector3d scaledLoad = initialLoads[i] * LF; GoalList[index] = new KangarooSolver.Goals.Unary(GoalList[index].PIndex[0], scaledLoad); } //Solve equilibrium for given load increment int counter = 0; do { PS.Step(GoalList, true, threshold); counter++; } while (PS.GetvSum() > threshold && counter < equilibriumIter); //Update value lists GH_Path path = new GH_Path(iter); //Get new equilibrium positions and update position lists Point3d[] newPositions = PS.GetPositionArray(); for (int k = 0; k < initialPositions.Count; k++) { previousPositions[k] = currentPositions[k]; currentPositions[k] = newPositions[k]; if (opt) { vertexPositions.Add(newPositions[k], path); } } //Get new goal output and update goal output lists List <object> newGOutput = PS.GetOutput(GoalList); for (int m = 0; m < permanentGoals.Count; m++) { previousGOutput[m] = currentGOutput[m]; currentGOutput[m] = newGOutput[m]; if (opt) { outputGoals.Add(newGOutput[m], path); } } //Does buckling occur? List <Vector3d> nodalDisplacements = calcDisplacement(currentPositions, initialPositions); double curRMS = calcDisplacementsRMS(nodalDisplacements); displacementsRMS.Add(curRMS); bool buckled = isBuckled(curRMS, preRMS, iter, fStart, fStep, angle); bool deflected = isDeflectionTooBig(nodalDisplacements, displ); if (buckled || deflected) { run = false; BLF = LF - fStep; } //Update preRMS = curRMS; iter++; } //-----------------------FLAG BUCKLED STATE----------------------------// if (BLF >= 1.0) { this.Message = "Works!"; } else { this.Message = "Buckles!"; } //-----------------------WARNING----------------------------// //If the maximum number of iterations has been reached if (iter == maxIterations) { this.AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, "Buckling did not occur within " + maxIterations + " load increments. Adjust load-step"); } //-----------------------UPDATE VALUE LISTS----------------------------// //If opt is false then add results from last two iterations if (!opt) { for (int i = 0; i < currentPositions.Count; i++) { vertexPositions.Add(previousPositions[i], new GH_Path(0)); vertexPositions.Add(currentPositions[i], new GH_Path(1)); } for (int j = 0; j < currentGOutput.Count; j++) { outputGoals.Add(previousGOutput[j], new GH_Path(0)); outputGoals.Add(currentGOutput[j], new GH_Path(1)); } } //---------------------------------------------------------------OUTPUT-------------------------------------------------------------------------------// DA.SetData(0, BLF); DA.SetDataList(1, loadfactors); DA.SetDataList(2, displacementsRMS); DA.SetDataTree(3, vertexPositions); DA.SetDataTree(4, outputGoals); }