Upcoming SlideShare
×

# Network Problems in Civil Engineering

882 views

Published on

0 Likes
Statistics
Notes
• Full Name
Comment goes here.

Are you sure you want to Yes No
• Be the first to comment

• Be the first to like this

Views
Total views
882
On SlideShare
0
From Embeds
0
Number of Embeds
1
Actions
Shares
0
13
0
Likes
0
Embeds 0
No embeds

No notes for slide

### Network Problems in Civil Engineering

1. 1. Network Problems 8 in Civil Engineering ABSTRACT This chapter provides an introduction to some fairly gen- eral network techniques that are common to many Civil Engineering problems. Implementation is discussed two diﬀerent ways: ﬁrst a vec- tor/matrix technique that is suitable for implementation in older program- ming languages such as Fortran and C, then an object-centered technique for use in more modern languages such as Python, Java and C++. 8.1 Introduction Many physical objects and processes in engineering can be modelled using graphs and networks. Even though networks are inherently discrete objects, this remains true whether the system being modelled is discrete or continuous; there are many techniques for reducing continuous problems to discrete ones. Intuitively, we usually think of network problems in terms of the diagrams engineers often use to model their problems. These diagrams, such as a line dia- gram representing a building frame, or a piping layout, or a surveying network, or a CPM project, represent the inter-relationships or connectedness of the var- ious objects involved. That is, they represent the structure of the problem or object. The purpose of this chapter is to introduce the concepts and terminology of graphs and networks, to show how many outwardly disimilar problems are in fact very similar, and to study in some depth appropriate computer techniques for processing network representations of problems. It is this last item that is perhaps the most important here; we will study programming techniques in which the manipulation of structured data and data relationships (as opposed to numerical computations) forms a very large part of real application programs. 8–1
2. 2. Terminology 8–2 8.2 Terminology The following terminology is adapted from a branch of mathematics called graph theory.1 A graph is deﬁned as a set of nodes connected by branches. When all the deﬁned nodes and branches are connected together (i.e., when it is impossible to divide the graph into two disjoint portions), the resulting graph is called connected. A planar graph is one which can be drawn on a plane without any of the branches crossing other branches. A branch (alternate names are edge, line or arc) is deﬁned as a line segment of a graph that connects two nodes. The branch is identiﬁed by its associated nodes. For our purposes, we will require the nodes at either end of any branch be diﬀerent (thus, we will not allow for the possibility of a branch forming a self-loop, although that is often allowed in graph theory). A node (alternate names are vertex, point, junction or terminal) is deﬁned as the endpoint of a branch. A single node may be the endpoint of many branches, in which case it is said to connect the branches together. The degree of a node is the number of branches connected to it – therefore the degree of an isolated node is 0. A directed graph or digraph is a graph in which the branches are given direc- tions, shown by arrows on the diagram. In a digraph a positive sign is associated with the incidence of a branch on its initial node and a negative sign given to the branch incidence on its ﬁnal node (this sign convention will be clariﬁed below). The branch arrow is shown directed from the initial to the ﬁnal node. It turns out that many engineering applications can be formulated using directed graphs. In some cases, the direction of a branch has a physical meaning (for example, time ﬂow in a CPM network is uni-directional). In other cases, the direction of a branch is a convenience to establish a reference point (i.e., ﬂow in a pipe is positive if it is in the same direction as the branch, and negative otherwise; in structural analysis the direction of a branch serves to establish a sign convention for the interpretation of member forces and distortions). The in-degree of a node in a directed graph is the number of branches directed into the node, and the out-degree is the number of branches directed out of the node. The sum of the in-degree and out-degree is of course the degree of the node. A path is a continuous sequence of branches and nodes between two terminal nodes, such that the ﬁnal node of one branch in the sequence is the initial node of the next branch in the same sequence. - In an open path, no node occurs more than once in the path. - In a closed path (alternate names are circuit, loop or mesh), the initial and ﬁnal nodes are the same. 1 Most of the discussion in this section has been taken from lecture notes developed by Prof. S. J. Fenves at Carnegie–Mellon University. Draft (net/intro1.tex) March 23, 2005
3. 3. Examples of Networks 8–3 - A mesh is any closed path of three or more branches. In some problems it is useful to establish a sign convention (direction) for a mesh. - An oriented circuit is a mesh that can be traversed entirely by following the postive direction of all included branches In a connected graph there is always at least one path between any two nodes. If a graph has a circuit, then there will be more than one path between some pairs of nodes. Networks are deﬁned as graphs with variables associated with the branches and nodes; in these the topology (i.e., connectedness or structure) imposes re- lations or constraints on the variables. Network variables are of two kinds: a) across variables such pressure changes, voltage changes, distortions, dis- tances, time, and elevations that are constrained by the mesh law (the sum of the values around any mesh is 0); and b) through variables such as currents, forces, and ﬂuid ﬂow that are con- strained by the node law (the sum of values at any node is 0). Across variables usually contain the diﬀerence in a quantity (such as pres- sure) from one end of a branch to the other. Through variables usually contain a quantity (such as internal bending-moment) that has an absolute value. Processing of network variables will be discussed later in this chapter. 8.3 Examples of Networks Someday we will have Signiﬁcance of complete examples here, with a table Domain Branch Mesh Node showing domain, Framed Structures member — joints signiﬁcance of branches Hydraulic Systems pipe loop junctions and nodes, and the appropriate network Surveying traverse Side traverse turning point/BM variables. Transportation path/road — load points/intersect. Project Scheduling activity — events Project Scheduling dependency — activities F.E. Analysis element — node Resistance Network wire/resistor circuit junction 8.4 Data Relationships in Networks Many engineering problems are conveniently represented using networks. The network formulation can also form the basis of applications programs. Therefore we need to understand how networks can be represented in the computer, and how the necessary network operations can be performed. In almost all network processing, it is necessary to represent one or more of the following relationships. Any individual program may need only one or two of these, but in general all are important. In addition, as network problems Draft (net/intro1.tex) March 23, 2005
4. 4. Matrix Representation 8–4 tend to get large, it is advisable that the relationships be represented eﬃciently in both space and time. The relationships are: 1. Those nodes that are incident on a given branch (the branch-node rela- tionship). In most network problems, it is sensible to make the restriction that there must be exactly two nodes on each branch. 2. Those branches that are incident on a given node (the node-branch re- lationship). There is no inherent upper limit to the number of branches that are incident on a given node – that number may be 1 or more. 3. Those branches that are included in a given mesh (the mesh-branch rela- tionship). There is no inherent upper limit to the number of branches in a mesh – that number may be 2 or 3 or more. 4. Those meshes that contain a given branch (the branch-mesh relationship). There is a theory that states that for planar graphs, things can be arranged so that no branch is included in more than two meshes (see Section 8.6 for a bit more information). In the following few sections, we will look at several network representation schemes. We will start with the simplest, but most ineﬃcient, and proceed to more eﬃcient, but more complex, schemes. 8.5 Matrix Representation The four relationships of Section 8.4, above, can be represented most simply by constructing two fundamental connectivity matrices. The ﬁrst speciﬁes the relationships among branches and nodes, and is called an incidence matrix, A. The second speciﬁes the relationships among branches and meshes, and is called the circuit matrix, C. Given the following deﬁnitions for a digraph: nb – number of branches nn – number of nodes nm – number of meshes then the incidence matrix Anb×nn is deﬁned as:      0   not  aij = +1 if branch i is positively incident on node j     −1 negatively and the circuit matrix Cnb×nm is deﬁned as:      0   not  cij = +1 if branch i is positively included in mesh j     −1 negatively Draft (net/intro1.tex) March 23, 2005
5. 5. Matrix Representation 8–5 Figure 8.1: Example Directed Graph (Digraph) For example, consider the directed graph shown in Figure 8.1. For this graph, the incidence matrix is:   +1 −1 0 0 0 0 0  0 +1 −1 0 0 0 0     0 −1 0 +1 0 0 0     0 0 +1 0 −1 0 0    A9×7 =  +1  0 0 −1 0 0 0    0 0 0 +1 −1 0 0     0 0 0 −1 0 +1 0     0 0 0 0 +1 0 −1  0 0 0 0 0 +1 −1 Each row in the incidence matrix corresponds to one branch and has exactly two non-zero entries: a +1 in the column corresponding to the initial node, and a −1 in the column corresponding to the ﬁnal node. The circuit matrix for the digraph of Figure 8.1 is: Draft (net/intro1.tex) March 23, 2005
6. 6. Matrix Representation 8–6   +1 0 0  0 +1 0     −1 +1 0     0 +1 0    C9×3 =  −1 0 0    0 −1 +1     0 0 +1     0 0 +1  0 0 −1 Each row in the circuit matrix corresponds to a branch, and has one or two non- zero entries: a +1 in those columns corresponding to meshes having the same direction as the branch, and a −1 in those columns corresponding to meshes having opposite direction. It can be seen that these two matrices contain all of the information necessary to represent the four common relationships mentioned on page 8–4, thus they are a suﬃcient representation for all network problems (although they may not be eﬃcient). Sometimes, for convenience or eﬃciency, an adjacency matrix Xnn×nn is deﬁned where:      0   not  xij = +1 if node i is positively adjacent to node j     −1 negatively Two nodes are adjacent if they are connected by a branch. Node i is positively adjacent to node j if node i is the ﬁnal node and node j is the initial node of a branch. By deﬁnition, the diagonal elements aii are zero. Then the adjacency matrix for the digraph of Figure 8.1 is:   0 −1 0 −1 0 0 0  +1 0 −1 +1 0 0 0     0 +1 0 0 −1 0 0    X7×7 =  +1 −1  0 0 −1 +1 0    0 0 +1 +1 0 0 −1     0 0 0 −1 0 0 −1  0 0 0 0 −1 −1 0 Each row of the adjacency matrix corresponds to a node, and has non- zero entries only in those columns corresponding to those other nodes that are directly “attached” to it through branches. For an unoriented graph, (i.e., one in which the branch directions are irrel- evant), all elements of X are positive and the matrix is symmetric. Draft (net/intro1.tex) March 23, 2005
7. 7. Vector Representations of Networks 8–7 8.5.1 Matrix Operations on Networks Someday this will Many interesting network computations can be expressed using the normal ma- introduce some common network trix operations and one or more of the matrices introduced in the previous problems, and will section. show matrix formulations of some of the common problem types. 8.6 Vector Representations of Networks The matrix representations outlined in Section 8.5 above are not always good representations, as they result in very sparse matrices.2 This leads to seri- ous ineﬃciences in both memory space and processing time for large problems; therefore more compact representations are desirable. As a ﬁrst step to developing more eﬃcient representations, consider the four relationships mentioned above on page 8–4. We see that the branch-node relationship (1) can always be compactly represented by a NODEnb×2 array that simply gives the node numbers at both ends of each branch: nodei1 = the node incident on end 1 of branch i nodei2 = the node incident on end 2 of branch i Now consider the branch-mesh relationship (3). Graph theory tells us that the maximum number of independent meshes in any graph is given by: nmmax = nb − (nn − 1) and that all other meshes can be formed by linear combinations of these. Graph theory also tells us that any planar graph3 can be so arranged that any given branch belongs to at most 2 meshes. If we further orient the meshes so that they are all positive in the same direction, then any branch will be positively included in one mesh and negatively included in the other. We then have a simple and compact representation for relation (3) for planar graphs. Array MESHnb×2 , gives the mesh numbers in which each branch is included: meshi1 = the mesh in which branch i is positively included. meshi2 = the mesh in which branch i is negatively included. By convention, meshi1 or meshi2 is set to zero if branch i is in fewer than two meshes. For the example graph of Figure 8.1, the NODE and MESH arrays are: 2A sparse matrix is one in which there are relatively few non-zero entries. 3 Most Civil Engineering problems can be represented by planar graphs. Draft (net/intro1.tex) March 23, 2005
8. 8. Vector Representations of Networks 8–8     1 2 1 0  2 3   2 0       4 2   2 1       3 5   2 0      NODE9×2 =  1 4   MESH9×2 =  0 1    4 5   3 2       6 4   3 0       5 7   3 0  6 7 0 3 The node-branch relationship (2) and the mesh-branch relationship (4) of page 8–4 are more diﬃcult to eﬃciently represent, as there is no inherent ﬁxed upper limit to the number of columns in the array. That is, there can be any number of branches incident on a node, and a mesh may have any number of branches included in it. Nevertheless, it is possible to use vectors to represent these, though it is rarely desirable. To use vectors requires four arrays: 1. NBRNnn to count the number of branches incident on a node; 2. BRNnn×nbmaxn to list the branches incident on a node; 3. NBRMnm to count the number of branches included in a mesh; and, 4. BRMnm×nbmaxm to list the branches included in a mesh. We then have: nbrni = the number of branches incident on node i brnij = the j th branch incident on node i nbrmi = the number of branches included in mesh i brmij = the j th branch included in mesh i brnij or brmij may be negative to indicate that the branch is negatively incident on the node or negatively included in the mesh. These arrays for the example digraph of Figure 8.1 are:     2 −1 −5  3   +1 −2 +3       2   +2 −4      NBRN7 =   4  BRN7×4 =   −3 +5 −6 +7     3   +4 +6 −8       2   −7 −9  2 +8 +9 and:     3 +1 −3 −5 NBRM3 =  4  BRM3×4 =  +2 +4 −6 +3  4 +6 +8 −9 +7 Draft (net/intro1.tex) March 23, 2005
9. 9. Object Representations of Networks 8–9 8.7 Object Representations of Networks Modern programming languages that oﬀer list data types, such as Python, make it particularly easy to represent networks. First, a few deﬁnitions. 1. A successor of a node is another node that is on the far end of branches leading from it. That is, it is the ﬁnal, or destination, node for a branch for which this node is the initial, or source node. 2. A successor list for a node is a list of all successor nodes; it is a list of all other nodes that can be reached in one step by following all the out-going branches from the node. 3. If node b is a successor of node a, then node a is a predecessor of b. Obviously, if a branch is directed from node a to node b, then a is a predecessor of b and b is a successor of a. For example, in Figure 8.1, node 2 is a successor of both 1 and 4; 1 and 4 are predecessors of 2. 4. The in-degree of a node is a count of all the branches leading into the node (i.e., all branches for which it is a ﬁnal node). It is therefore also the number of predecessors that the node has. In Figure 8.1, the in-degree of node 4 is 2. As is the case for the representions of relations (2) and (4) of page 8–4 above, there is no inherent upper limit to the number of successors (or predecessors) of a node. Therefore, if we use an array representation, we have to anticipate the largest number of successors for any node, and dimension our arrays for that worst case. Fortunately, that is not necessary for lists that can automatically grow as large as necessary. Need more explanation here. More Python: The Python programming language goes to considerable eﬀort to make lists as eﬃcient as possible, in both space and time. They are created small so as to add little memory overhead, but can grow as large as necessary. They are adequately eﬃcient for all but the most demanding of applications. 8.7.1 Node-Oriented Networks In some network representations of Civil Engineering problems, the branches serve only to establish a relationship between nodes, and no other data need be stored or computed for the branches. One example of this is the ’Activity-on- Node’ representation of CPM project planning networks (Section 9.2). These networks are particularly easy to represent. With each node, we explicitly store only the node id, and its successor and predecessor lists. Class Node is a minimal implementation: Node1.py 1 class Node( object ): 2 Draft (net/intro1.tex) March 23, 2005
10. 10. Object Representations of Networks 8–10 3 """Class Node represents nodes in a network in which no data is 4 associated with the branches. Each node therefore just stores its 5 id and a list of its predecessors and of its successors.""" 6 7 def __init__( self, id ): 8 self.id = id 9 self.__successors = [] 10 self.__predecessors = [] 11 12 def addSuccessor( self, node ): 13 """Add node as a successor of this one.""" 14 self.__successors.append( node ) 15 16 def addPredecessor( self, node ): 17 """Add node as a predecessor of this one.""" 18 self.__predecessors.append( node ) 19 20 def successors( self ): 21 """Return a list of the successor nodes.""" 22 return self.__successors 23 24 def predecessors( self ): 25 """Return a list of the predecessor nodes.""" 26 return self.__predecessors The network itself just maintains a collection of nodes, with operations to ensure that predecessors and successors are updated properly for each branch. In this case, the node collection is a dictionary indexed by node id; this is used to ensure that there is only one node object for each diﬀerent id. Method node() ensures this. Method addBranchByID() simply ensures that the node objects for each end of the branch exist, then updates the approriate predecessor and successor lists for those end nodes . Network1.py 1 from Node1 import Node 2 3 class Network( object ): 4 5 """This class represents networks in which no data is associate 6 with the branches. In other words, a branch simply defines the 7 predecessor-successor relationship between two nodes, and all 8 important computational data is associated with the nodes. An 9 example of this kind of network is an activity-on-node CPM network. 10 This class maintains unique node objects for each node id.""" 11 12 def __init__( self ): 13 self.__nodes = {} # node dictionary indexed by id 14 15 def addBranchByID( self, sourceID, destID ): Draft (net/intro1.tex) March 23, 2005
11. 11. Operations on Graphs and Networks 8–11 16 """Add a branch to the network, given the ids of 17 the nodes at either end of the branch.""" 18 source = self.node( sourceID ) 19 dest = self.node( destID ) 20 self.addBranch( source, dest ) 21 22 def addBranch( self, source, dest ): 23 """Add a branch to the network, given the node 24 objects at either end of the branch.""" 25 source.addSuccessor( dest ) 26 dest.addPredecessor( source ) 27 28 def node( self, id, nodeClass=Node ): 29 """Return the node object for the given id, creating it 30 if necessary.""" 31 try: 32 return self.__nodes[id] 33 except KeyError: 34 n = nodeClass( id ) 35 self.__nodes[id] = n 36 return n 37 38 def nodes( self ): 39 """Return the list of nodes in the network.""" 40 return self.__nodes.values() 8.8 Operations on Graphs and Networks This section describes a few operations on graphs that will be useful when we discuss example applications; ﬂuid ﬂow balancing in this chapter, and project management (CPM) methods in a following chapter. 8.8.1 Topological Sorting In many graph applications, it is necessary to process the nodes and successor lists in a certain order. For example, computations for all predecessor nodes may have to be completed before computations for any successor can be started. This often requires that the nodes be numbered in such a way that the ﬁnal node of every branch has a higher number than the initial node of the same branch. As it is unreasonable to expect the input to a program to be ordered like this, any program that requires this ordering must re-number the nodes itself. This is usually done by assigning an “internal” node number for each node, doing all computations using that internal number, and simply translating back to the external (user) numbers or identiﬁers on output. The process of assigning internal node numbers so that the above criteria is met is called a topological sort. The process of performing the topological sort Draft (net/intro1.tex) March 23, 2005
12. 12. Operations on Graphs and Networks 8–12 will also detect oriented circuits; these are invalid in many contexts4 and are an indication of input errors. Intuitively, a topological sort orders the nodes into a “processing” order. That is, all of the predecessors of a node will have been processed before the node itself is processed. A simple example is in calculating the early start time for an activity in a CPM network; before we can do that we must compute the early start time of all predecessor activities. A topological sort of the activities will ensure this. The algorithm for topological sorting can be understood by observing that any node with an in-degree of 0 does not have any predecessors, and so can be “processed”. As that node is then no longer “needed”, it can be “removed” from the network and the in-degree of all of its successors can be reduced by one. The algorithm works by ﬁrst scanning all nodes and adding all with in- degree 0 to a work queue. Nodes are removed from the queue and “processed”; all successors whose in-degree then drops to zero are in turn added to the queue. 5 The algorithm stops when the queue is empty. If there are unprocessed nodes left at that time, then the network had cycles. The algorithm proceeds as follows: toposort.py 1 import Queue 2 3 def toposort( nodes, process=None ): 4 5 """Perform a topological sort of the nodes in the list of nodes. 6 Call the ’process’ function for each node as it is sorted.""" 7 8 answer = None 9 if process is None: # default is to build a list 10 answer = [] 11 process = answer.append # ’process’ just appends to list 12 13 q = Queue.Queue() # init queue of 0-indegree nodes 14 15 n = len( nodes ) # number of nodes 16 indeg = {} # in-deg counts indexed by node 17 for node in nodes: # compute indegrees of all nodes 18 indeg[node] = len(node.predecessors()) 19 if indeg[node] == 0: # if 0, add to queue 20 q.put(node) 21 22 while not q.empty(): # while queue is not empty 4 In CPM planning, for example, they would indicate the presence of cyclic dependencies, i.e., activity A depends on the completion of B, and B depends on the completion of A. 5 After processing each node, a “stupid” algorithm would scan the whole network again looking for new nodes with 0 in-degree. Because the only nodes whose in-degree changes at each step are the successors of the most recently processed node, it is only those that are candidates for addition to the queue, and thus only those need be tested. Draft (net/intro1.tex) March 23, 2005
13. 13. Operations on Graphs and Networks 8–13 23 node = q.get() # get a node 24 process( node ) # and process it 25 n -= 1 # and count it 26 for succ in node.successors(): # decr. indegree of successors 27 indeg[succ] -= 1 28 if indeg[succ] == 0: # add to queue if indeg is 0 29 q.put( succ ) 30 31 if n > 0: # all done, check counts 32 raise ValueError( "Network has cycles. %d nodes unsorted." % n ) 33 if n < 0: 34 raise ValueError( "Network has invalid pred./succ. lists." ) 35 36 return answer See Section 5.6 for discussion of the queue abstraction. The above algorithm is written as a function that takes two arguments – the second, optional, argument is another function that does the actual “processing” of each node as it is removed from the network. If the process function is not supplied, toposort() constructs a list of the nodes in topological order. To demonstrate the topological sort, consider the following example, topoeg1.py, that constructs the network of Figure 8.1. It does this simply by using the list of branches, where each branch is given by the ids (numbers) of the nodes at either end. The resulting set of nodes is topologically sorted, then new node numbers are assigned in the order of the sorted nodes. topoeg1.py 1 # Example network of Figure 8.1 2 3 from Network1 import Network 4 from toposort import toposort 5 6 branches = [ (1, 2), # branch 1, nodes 1 -> 2 7 (2, 3), # branch 2, nodes 2 -> 3 8 (4, 2), # branch 3, nodes 4 -> 2 9 (3, 5), # etc. ... 10 (1, 4), 11 (4, 5), 12 (6, 4), 13 (5, 7), 14 (6, 7) ] 15 16 N = Network() # create network from branch list 17 for src,dst in branches: 18 N.addBranchByID( src, dst ) 19 20 nodes = toposort( N.nodes() ) # sort nodes 21 Draft (net/intro1.tex) March 23, 2005
14. 14. Survey of Storage Requirements 8–14 22 i = 0 # assign new numbers to nodes 23 for node in nodes: 24 i += 1 25 node.newid = i 26 27 print "Node Numbers:" # print old, new numbers 28 print "%5s %5s" % (’Old’,’New’) 29 for node in nodes: 30 print "%5d %5d" % (node.id,node.newid) The output of that example program is shown here, and shows the corre- spondance between old (original) node numbers and new node numbers: topoeg1.out 1 Node Numbers: 2 Old New 3 1 1 4 6 2 5 4 3 6 2 4 7 3 5 8 5 6 9 7 7 Obviously from this, one can see that the ordering of original numbers of [1 6 4 2 3 5 7] is a topological sort of the nodes. Application of the above algorithm renumbers the nodes in the example graph of Figure 8.1 to that shown in Figure 8.2. It can readily be seen from the above ﬁgure that all branches are now incident on nodes whose numbers increase in the positive direction of the branch, and thus are topologically sorted. 8.9 Survey of Storage Requirements The reason we are tempted to use the list storage techniques is because of the ﬂexibility they oﬀer, particularly when a program must maintain a number of lists of data of varying length. It is possible to identify at least the following application areas in Civil Engineering where this is the case: • CPM Project Analysis. To compute early start times requires a for- ward pass over all the nodes (activities) in the network, starting with the initial node, and computing early start times for all successors of each node in turn. This requires that, for each activity, we maintain a list of successor activities. There is no natural upper bound on the number of successors an actvity may have, yet in practice most activites will have few (perhaps ﬁve or fewer). To compute late ﬁnish times requires a back- ward pass, and knowledge of all predecessors for every activity; exactly the same considerations apply here. Draft (net/intro1.tex) March 23, 2005
15. 15. Survey of Storage Requirements 8–15 Figure 8.2: Graph With Renumbered Nodes Draft (net/intro1.tex) March 23, 2005
16. 16. Survey of Storage Requirements 8–16 • Fluid Distribution Networks. A common technique to compute the ﬂow in each branch (pipe) in a distribution network is the Hardy–Cross method. This involves estimating a ﬂow in each branch, computing head loss (pressure drop) around a mesh using well known and simple relation- ships between ﬂow and pressure drop, and adjusting the estimated ﬂows in each mesh so that the pressure drop is zero. Because some branches are parts of two meshes, and because the relationship between ﬂow and pressure drop is non-linear, this requires an iterative solution, usually by processing and balancing meshes one-by-one. The data thus required is a list of branches in each mesh. While that number will never be less than two, and in practice will rarely be greater than ﬁve or six, there is still no inherent upper bound on the number of branches per mesh. • Fluid Collection Networks. Here one wishes to compute the ﬂows in all branches in the network, given expected ﬂows into the nodes (which may be catchment basins in a storm water drainage system). Before computing the ﬂow through a particular node, it is necessary to compute the ﬂow through all “upstream” nodes. It is therefore necessary to know all the nodes that are immediately upstream of a given node; if these are then processed in a correct order (which can be obtained using a topological sort), ﬂows can be computed. Again, there is no inherent upper limit to the number of pipes ﬂowing into a junction, although in practice the number will usually be small. • Stiﬀness Analysis of Structures. This involves using relationships of elasticity and equilibrium to develop, and solve, a system of linear simul- taneous equations (for structural displacements and distortions). This set of equations may be large, and when space and eﬃciency issues are important (they almost always are), a “frontal” technique is sometimes used. In this technique, the stiﬀness matrix is formed a row at a time, and the decompostion portion of the solution is done in parallel, as each row is formed. Each row of the stiﬀness matrix corresponds to a particular displacement degree of freedom at a node, and to form each row of the stiﬀness matrix requires knowledge of all other nodes directly connected to the current node through members or elements. Therefore one needs a connectivity list for every node, and again there is no inherent upper limit to the number of connected nodes (at least, not when the elements are line elements). In all of the above problems, there is not a ﬁxed, predictable upper limit to the number of elements in a particular list of data. Any limit so imposed by a dimension statement in a program either wastes considerable storage, or reduces program ﬂexibility, and usually does both. Therefore more sophisticated storage techniques are desirable. The list technique has the following advantages: • It is very ﬂexible — storage not used by one list because it is short can Draft (net/intro1.tex) March 23, 2005
17. 17. Survey of Storage Requirements 8–17 be used by a longer list. Space only has to be reserved for the maximum total number of list elements. • Logically adjacent list elements do not have to be in physically adjacent storage locations and therefore they can be created and added to the list in any order. On the other hand, list storage techniques have the following disadvantages: • The programming to use them eﬀectively is much more complex, and programs may be much more diﬃcult to debug. A pointer that is slightly wrong may cause unpredictable results, and the eﬀects may show up long after the source of the error. • The overhead taken for maintaining the pointers may be very large. This depends on the amount of data stored with each element, but a simple list of integers will take almost twice as much storage as if they were maintained in a singly subscripted array. Draft (net/intro1.tex) March 23, 2005
18. 18. Resources 8–18 8.10 Resources [1] Alfred V. Aho, John E. Hopcroft, and Jeﬀrey D. Ullman. The Design and Analysis of Computer Algorithms. Addison–Wesley, 1974. [2] Zamir Bavel. Math Companion for Computer Science. Reston Publishing Company, 1982. [3] A.T. Berztiss. Data Structures: Theory and Practice. Academic Press, 1971. [4] Alan Jennings. Matrix Computation for Engineers and Scientists. John Wiley & Sons, 198? [5] R.L. Peurifoy, W.B. Ledbetter, , and C.J. Schexnayder. Construction Plan- ning, Equipment, and Methods. McGraw-Hill, ﬁfth edition, 1996. [6] Alan A. Smith, Ernest Hinton, and Roland W. Lewis. Civil Engineering Systems Analysis and Design. John Wiley & Sons., 1983. [7] Andrew B. Templeman. Civil Engineering Systems. The Macmillan Press, 1982. [8] Guido van Rossum. Python patterns - implementing graphs [online]. 2000 [cited 2005/02/11]. Available from: http://www.python.org/doc/essays/ graphs.html. Draft (net/resources.tex) March 23, 2005