/// <summary> /// Merges all nodes so that no two nodes are within the given tolerance. /// </summary> public void MergeNodes(double mergeTolerance) { Dictionary <Node, List <Node> > toMerge = new Dictionary <Node, List <Node> >(); Dictionary <Node, Node> toRemove = new Dictionary <Node, Node>(); foreach (Node n1 in Nodes) { if (toMerge.ContainsKey(n1)) { continue; } if (toRemove.ContainsKey(n1)) { continue; } foreach (Node n2 in Nodes) { if (ReferenceEquals(n1, n2)) { continue; } if (toMerge.ContainsKey(n1)) { continue; } if (toRemove.ContainsKey(n1)) { continue; } if (Node.Distance(n1, n2) < mergeTolerance) { List <Node> removeList; if (toMerge.TryGetValue(n1, out removeList)) { removeList.Add(n2); } else { toMerge[n1] = new List <Node>() { n2 }; } toRemove[n2] = n1; } } } // Arrange frame nodes foreach (Frame f in Frames) { Node n1; Node n2; if (toRemove.TryGetValue(f.NodeI, out n1)) { f.NodeI = n1; } if (toRemove.TryGetValue(f.NodeJ, out n2)) { f.NodeJ = n2; } } // Assemble node loads foreach (KeyValuePair <Node, List <Node> > pair in toMerge) { Node master = pair.Key; List <Node> removed = pair.Value; foreach (AnalysisCase analysisCase in AnalysisCases) { // Assemble point loads NodePointLoad assembledPointLoad = new NodePointLoad(analysisCase, 0, 0, 0); foreach (NodeLoad masterLoad in master.Loads.FindAll((e) => e.AnalysisCase == analysisCase && e is NodePointLoad)) { NodePointLoad masterPointLoad = masterLoad as NodePointLoad; assembledPointLoad.FX += masterPointLoad.FX; assembledPointLoad.FZ += masterPointLoad.FZ; assembledPointLoad.MY += masterPointLoad.MY; } foreach (Node slave in removed) { foreach (NodeLoad slaveLoad in slave.Loads.FindAll((e) => e.AnalysisCase == analysisCase && e is NodePointLoad)) { NodePointLoad slavePointLoad = slaveLoad as NodePointLoad; assembledPointLoad.FX += slavePointLoad.FX; assembledPointLoad.FZ += slavePointLoad.FZ; assembledPointLoad.MY += slavePointLoad.MY; } } master.Loads.RemoveAll((e) => e.AnalysisCase == analysisCase && e is NodePointLoad); if (!MathNet.Numerics.Precision.AlmostEqual(assembledPointLoad.FX + assembledPointLoad.FZ + assembledPointLoad.MY, 0)) { master.AddPointLoad(analysisCase, assembledPointLoad.FX, assembledPointLoad.FZ, assembledPointLoad.MY); } } } // Remove nodes foreach (Node n in toRemove.Keys) { Nodes.Remove(n); } }
/// <summary> /// Merges all nodes so that no two nodes are within the given tolerance. /// </summary> public void MergeNodes(double mergeTolerance) { Dictionary<Node, List<Node>> toMerge = new Dictionary<Node, List<Node>>(); Dictionary<Node, Node> toRemove = new Dictionary<Node, Node>(); foreach (Node n1 in Nodes) { if (toMerge.ContainsKey(n1)) continue; if (toRemove.ContainsKey(n1)) continue; foreach (Node n2 in Nodes) { if (ReferenceEquals(n1, n2)) continue; if (toMerge.ContainsKey(n1)) continue; if (toRemove.ContainsKey(n1)) continue; if (Node.Distance(n1, n2) < mergeTolerance) { List<Node> removeList; if (toMerge.TryGetValue(n1, out removeList)) { removeList.Add(n2); } else { toMerge[n1] = new List<Node>() { n2 }; } toRemove[n2] = n1; } } } // Arrange frame nodes foreach (Frame f in Frames) { Node n1; Node n2; if (toRemove.TryGetValue(f.NodeI, out n1)) { f.NodeI = n1; } if (toRemove.TryGetValue(f.NodeJ, out n2)) { f.NodeJ = n2; } } // Assemble node loads foreach (KeyValuePair<Node, List<Node>> pair in toMerge) { Node master = pair.Key; List<Node> removed = pair.Value; foreach (AnalysisCase analysisCase in AnalysisCases) { // Assemble point loads NodePointLoad assembledPointLoad = new NodePointLoad(analysisCase, 0, 0, 0); foreach (NodeLoad masterLoad in master.Loads.FindAll((e) => e.AnalysisCase == analysisCase && e is NodePointLoad)) { NodePointLoad masterPointLoad = masterLoad as NodePointLoad; assembledPointLoad.FX += masterPointLoad.FX; assembledPointLoad.FZ += masterPointLoad.FZ; assembledPointLoad.MY += masterPointLoad.MY; } foreach (Node slave in removed) { foreach (NodeLoad slaveLoad in slave.Loads.FindAll((e) => e.AnalysisCase == analysisCase && e is NodePointLoad)) { NodePointLoad slavePointLoad = slaveLoad as NodePointLoad; assembledPointLoad.FX += slavePointLoad.FX; assembledPointLoad.FZ += slavePointLoad.FZ; assembledPointLoad.MY += slavePointLoad.MY; } } master.Loads.RemoveAll((e) => e.AnalysisCase == analysisCase && e is NodePointLoad); if (!MathNet.Numerics.Precision.AlmostEqual(assembledPointLoad.FX + assembledPointLoad.FZ + assembledPointLoad.MY, 0)) { master.AddPointLoad(analysisCase, assembledPointLoad.FX, assembledPointLoad.FZ, assembledPointLoad.MY); } } } // Remove nodes foreach (Node n in toRemove.Keys) { Nodes.Remove(n); } }
/// <summary> /// Returns the load vector for the given load case. /// </summary> private Vector <double> GetLoadVector(AnalysisCase analysisCase) { Vector <double> p = Vector <double> .Build.Dense(nodes.Count * 3, 0); // Node loads foreach (Node node in nodes) { foreach (NodeLoad load in node.Loads.FindAll((e) => e.AnalysisCase == analysisCase)) { if (load is NodePointLoad) { // Applied point loads NodePointLoad pl = (NodePointLoad)load; int i = node.Index; p[i * 3 + 0] += pl.FX; p[i * 3 + 1] += pl.FZ; p[i * 3 + 2] += pl.MY; } } } // Frame loads foreach (Frame frame in Frames) { double l = frame.Length; int i = frame.NodeI.Index; int j = frame.NodeJ.Index; foreach (FrameLoad load in frame.Loads.FindAll((e) => e.AnalysisCase == analysisCase)) { if (load is FrameUniformLoad) { // Frame fixed-end reactions from frame uniform loads FrameUniformLoad pl = (FrameUniformLoad)load; double fx = pl.FX * l / 2.0; double fz = pl.FZ * l / 2.0; p[i * 3 + 0] += fx; p[i * 3 + 1] += fz; p[i * 3 + 2] += 0; // End moment p[j * 3 + 0] += fx; p[j * 3 + 1] += fz; p[j * 3 + 2] += 0; // End moment } else if (load is FrameTrapezoidalLoad) { // Frame fixed-end reactions from frame trapezoidal loads FrameTrapezoidalLoad pl = (FrameTrapezoidalLoad)load; double fx = (pl.FXI + pl.FXJ) / 2.0 * l / 2.0; double fz = (pl.FZI + pl.FZJ) / 2.0 * l / 2.0; p[i * 3 + 0] += fx; p[i * 3 + 1] += fz; p[i * 3 + 2] += 0; // End moment p[j * 3 + 0] += fx; p[j * 3 + 1] += fz; p[j * 3 + 2] += 0; // End moment } } } // Set restrained node coefficients to 0 foreach (Node n in nodes) { if ((n.Restraints & DOF.UX) != DOF.Free) { p[n.Index * 3 + 0] = 0; } if ((n.Restraints & DOF.UZ) != DOF.Free) { p[n.Index * 3 + 1] = 0; } if ((n.Restraints & DOF.RY) != DOF.Free) { p[n.Index * 3 + 2] = 0; } } return(p); }