02 OamLab V1.10

02 OamLab V1.10 preview image

1 collaborator

121210_portrait_of_garvin Garvin Boyle (Author)

Tags

atwood's machine 

Tagged by Garvin Boyle over 8 years ago

biophysical economics 

Tagged by Garvin Boyle over 8 years ago

ecological economics 

Tagged by Garvin Boyle over 8 years ago

maximum power principle 

Tagged by Garvin Boyle over 8 years ago

sustainability 

Tagged by Garvin Boyle over 8 years ago

sustainable economics 

Tagged by Garvin Boyle over 8 years ago

Model group Sustainability | Visible to everyone | Changeable by group members (Sustainability)
Model was written in NetLogo 5.0.5 • Viewed 1193 times • Downloaded 50 times • Run 0 times
Download the '02 OamLab V1.10' modelDownload this modelEmbed this model

Do you have questions or comments about this model? Ask them here! (You'll first need to log in.)


WHAT IS IT?

OamLab - This is the first of a series of three planned models in a study of the maximum power principle (MPP) - the other two models being MppLab and TpLab. In OamLab energy arrives in a steady stream from the Sun and is captured by plants that form the heads of trophic chains. These trophic chains do not form a trophic web, but remain as distinct and competing entities. The energy passes from organism to organism down each trophic chain until the final organism (the apex predator) consumes the penultimate holder of the energy, and the last of the original endowment of energy is degraded as waste heat and released. By this means we have direct insight into the basic implications of Lotka's argument (Lotka, 1922a) about the evolution of system-wide processes that compete for energy and evolve to function with maximized energy flux. That argument by Lotka is now a fundamental piece of the concept called the MPP. But, how do you measure the fitness of processes that compete for access to energy? How do you compare the respective efficiencies of many competing system-wide processes that are, themselves, composed of many linked energy transformation processes? What are the effects on the individual transformations? With OamLab I begin to address some of these questions.

MAXIMUM POWER PRINCIPLE (MPP) - It is clear that, when isolated and left alone, all systems die, run down, erode, decay and/or dissipate their matter and energy. This process is closely associated with the phenomenon of entropy production, and the 2nd law of thermodynamics (sometimes referred to as the maximum entropy principle, or MEP) easily describes how this happens. Any such energetically isolated system automatically alters and reconfigures itself, moving through a series of ever more probable states along a trajectory of ever increasing entropy, until a most probable configuration or state of maximal entropy is achieved. This state of maximal entropy is usually characterized by an excess of sameness, a lack of structures, shapes or spatial variations, and by characteristic distributions of energies among the parts. Once having achieved such a configuration, the isolated system then remains in a state of maximal entropy (a most probable state) forever after. However, when we look around ourselves, virtually everything we see is characterized by remarkable improbable variety, a plethora of structures and shapes, and turbulent distributions of energy. Clearly, when a system is not isolated and left alone, there is another dynamic able to overpower the 2nd law and undo its nasty work. Such is the nature of the proposed 4th law of thermodynamics. A.J. Lotka, H.T. Odum and R.C. Pinkerton called this the Maximum Power Principle (MPP). H.T. Odum (1924-2002) went on, over four decades, to argue that the MPP is the best candidate for the fourth law of thermodynamics, having explanatory value for such things as ecosystems, economies, and other self-organizing systems. However, in spite of the fact that there is plenty of anecdotal evidence in support of the concept, it remains little understood, and little studied it seems. The MPP says (my words) that any self-organizing system that is open with respect to a flow of energy will configure itself to store/consume/use energy at the maximum rate possible. This model is a "laboratory" in which I can study the nature of the MPP.

Atwood's Machine - The approach in OamLab is to study the Lotka/Odum MPP using a marvelous gizmo called Atwood's Machine (AM). This machine was invented in 1784 by the English mathematician George Atwood for the study of Newton's laws of motion. It has since become a common device in the design of a variety of lifts which use counterweights. Odum and Pinkerton used the AM as an example in their 1955 study of the MPP. In a variety of diary notes that I have written in an attempt to understand the MPP, I have developed a rather arcane notation of OAMs, HOAMs and OAM chains. It is highly recommended that interested people read those notes prior to studying this model. They are summarized below.

SUSTAINABLE ECONOMICS - OamLab is being written as part of a personal study of the dynamics of a sustainable economy. It has become clear to me that a modern economy is a stirling example of a system that has evolved to extract matter and energy from its environment, and to degrade and disperse those resources at a maximal rate. That observation has lead to the study of the MPP. During the course of that study I have become aware that there are two principles that have been consistently proposed by scientists as candidates for the fourth law of thermodynamics. One is the MPP, as described above. The other is often referred to as the Maximum Entropy Production Principle (or MEPP). Note that this goes beyond the 2nd law - the MEP. The MEPP says (my words) that any self-organizing system that is open with respect to a flow of energy will configure itself to continuously produce entropy at the maximum rate possible. Now, I have intentionally reworded the two principles to draw attention to the similarity. I believe I have not mangled either idea too badly. I am personally convinced of two things:

  • The MPP and the MEPP are two sides of a single little-understood phenomenon, and in both cases the proponents argue that these laws play a significant role in the organization of both ecosystems and economic systems. In these days of daily news of ecological and economic perils, it seems we might want to put some effort into understanding such a phenomenon. And so, my study of economics has taken an unexpected turn towards the MPP and the MEPP for a while.
  • The very same phenomenon that is actively shaping our ecological and economic destinies is also active in many agent-based models (ABMs). I am NOT saying that I believe they are simulated in ABMs. I believe they are the organizing phenomena that cause unexpected emergent behaviour in ABMs. These principles are exhibited, or can be exhibited, in ABMs. What better place to study them, then, than in ABMs?

Atwood's Machine Understood - I will here provide a description of an AM that will help you understand the OamLab and MppLab applications. This differs only in mechanical design from other descriptions you will find, but not in function. An AM consists of two masses, one heavy and one light, coupled by a rope that is hung over a pair of non-leveraging simple pulleys. Most descriptions show a single pulley. I prefer to view it as a pair of pulleys, because I am going to split the AM into two halves, and each half has a pulley, a mass, an energy sink, a rope to couple masses together when needed, and a hold/release latch that can be used to pin the mass in place after it has been raised. In the AM, the heavy mass is primed with gravitational potential energy as it is raised a distance D off of the floor and latched in place. It is then coupled, using the ropes, to the lighter mass that rests on the floor, as a counterweight. When the heavy mass is released, it glides slowly to the floor as the lighter counterweight mass slowly rises. When the lighter mass has risen a distance of D, it is latched in place. At that point, the two masses may again be uncoupled.

I apologize for the use of a variety of acronyms in the following explanation, and in the interface of the model, and in the code, but without them I find I get really tangled up in my words. So, here is a list of the acronyms that are important. For more detail, read the notes mentioned below in the reference section:

  • AM - Atwood's Machine in its original design - a mechanical system that is closed with respect to energy, in the sense that most analyses of the original system start with the heavy mass already raised, and do not consider how the energy is first put into it. I use the AM as a metaphor for time-regulated transformation of energy. According to Odum, all energy-driven changes require time to unfold, and I am using the mechanics of a mechanical system to stand in as a time-based speed regulator for the biomechanical and biochemical changes that might happen as energy is passed from predator to prey in an ecosystem. I am using the well-understood mechanics of the AM to model the biochemistry of digestion.
  • OAM - Open Atwood's Machine - an imaginary version of the AM that is open with respect to energy, allowing a flow of energy into the system on the right, and out again on the left, as it runs its course.
  • HOAM - Half of an OAM - two of which remain when an OAM has its masses uncoupled and it is split in half. Each half consists of, as stated above, a pulley, a rope, a mass, an energy sink (the floor), and a hold-release latch that can be used to pin the mass up off of the floor.
  • RH-HOAM - An HOAM that has been linked to the right side of another HOAM to form an OAM. The RH-HOAM must have a mass larger than the mass in its counterpart.
  • LH-HOAM - An HOAM that has been linked to the left side of another HOAM to form an OAM. The LH-HOAM must have a mass lighter than the mass in its counterpart.
  • Chain of HOAMs - a series of HOAMs formed into a distinct chain. They are linkable in pairs to form OAMs such that each side-by-side pair of HOAMS can form a well-formed OAM. Energy can flow into the head of the chain, and, as OAMs are formed, and as the masses are coupled and uncoupled, the energy flows through the chain to the tail. Each HOAM may be uncoupled, coupled as an RH-HOAM, or coupled as an LH-HOAM. You can think of such a chain as a simulation of energy flow through a trophic chain (along one chain in a web), of energy flow through the organic molecules that make up the cytoplasm in a cell, or, possibly, of capital flows through a supply chain of economic agents in an economy. [This is the crazy concept I am chasing in my study of sustainable economics.]
  • Web of HOAMs - a collection of free-moving HOAMs that are freely linkable to other HOAMs with which they come in contact. They link in pairs to form OAMs such that each side-by-side pair of HOAMS forms a well-formed OAM. Energy flows from HOAM to HOAM as the masses are coupled, forming OAMs, and uncoupled again. Ultimately, the energy flows through the web. Each HOAM may exist in uncoupled form, coupled as an RH-HOAM, or coupled as an LH-HOAM. You can think of such a web as an analogy of energy flowing through an ecosystem, of energy flowing through the organic molecules that make up the cytoplasm in a cell, or, possibly, of capital flowing through independent economic agents in an economy. [This is the crazy concept I am chasing in my study of sustainable economics.]

In OamLab I present preformed and persistent chains of OAMs competing for survival. In MppLab there are free-swimming HOAMs that form OAMs at will and so make virtual chains of OAMs of fleeting existence as the HOAMs compete for survival and devour one another in that competition.

Other variable names, short forms and acronyms are indicated in brackets at the moment when they are first used, as I did with the acronyms MPP and MEPP above.

I do not intend to imply, at all, that I think self-organizing systems contain explicit chains of HOAMs, as are exhibited in OamLab, or even free-floating HOAMs, as are exhibited in this model. I think that, if this MPP concept contains any real useful insight, then HOAMs exist as organic molecules, organisms, and economic agents that link temporarily and exchange energy or capital via some time-regulated process. As the energy (or capital) flows through such systems from component to component, some is degraded and exhausted, while the rest is passed on down the chain. OamLab was a first simple laboratory. A more realistic model, say, of a trophic web, has taken some extra effort to set up. MppLab is the first such model of a trophic web. (See the "Omnivores" scenario.)

Mathematics of the AM - An AM starts with stored total gravitational potential energy (Wt) equal to the acceleration due to gravity (g) times the heavier mass (Mh) times the distance from the mass to the floor (D). We write that as Wt = g x D x Mh. After Mh is released, and as the AM runs to completion, this energy is transformed in two ways. The coupled mass assembly accelerates, and picks up kinetic energy. At the same time, the lighter mass (Ml) is raised off the floor by a distance D, gaining gravitational potential energy (Wu) according to the equation Wu = g x D x Ml. When Mh strikes the floor, the kinetic energy of both masses is dissipated into the heat sink. In my language, the energy is either transferred from the RH-HOAM to the LH-HOAM as stored high-grade gravitational potential energy, or exhausted as low-grade waste heat. No entropy is produced as Wu is transferred and stored. Entropy is produced as the waste energy (We) is exhausted. We = Wt - Wu. Odum defines the efficiency (Eu) of the AM in transferring and storing high-grade energy as Eu = Wu / Wt, which simplifies to Eu = Ml / Mh.

When Ml << Mh then Eu is close to zero, Mh falls quickly, and the time-to-drop is short. This baseline value of time-to-drop (Tb) is given by the formula Tb = (2 x D / g )^0.5. Most of the initial endowment of gravitational potential energy is transformed to waste heat, and cannot be passed on to other OAMs. When Mh is just slightly larger than Ml, then it descends very very slowly, the time-to-drop is long, and most of the endowment of energy is transformed into useful energy, stored in the LH-HOAM. Curiously, the fastest transfer of the endowment of energy to still useful energy in the LH-HOAM occurs when Eu has a value of 1/2. That is, maximum useful power happens when Mh = 2 x Ml. [ NOTE: there is an exception to that, sometimes, when it converges to 0.618, as happens in OamLab.]

Antithesis within the MPP - Every system that captures and consumes energy can be viewed as functioning dynamically at two or more levels - at the level of the system as a whole, and at the level of the component parts. The dynamics that are encapsulated in this acronym MPP has two apparently contradictory effects. It both maximizes and minimizes the rate of entropy production, all at the same time. At the level of the system-as-a-whole, the rate of entropy production is maximized. But, at the level of the system components, as energy is transferred from component to component, average rate of entropy production is minimized during transfers. I believe that the interaction of these two opposing dynamics is the source of rising complexity.

  • Huh? - The MPP says that this model system (which consists of many generalized HOAMs) will configure itself in such a way that two things will happen. At the lower level, the temporary OAMs, as they form, will come to operate, on average, at maximum useful power, which will occur at some intermediate level of efficiency. The rate of production of entropy in HOAM-to-HOAM transfers will be minimized. At the same time, the model as-a-whole will self-organize to capture and degrade as much energy as possible. The number of consumers (population of heterotrophs) will rise to capture as much energy as possible. The lengths of the trophic chains will extend as long as possible to effectivly consume, or degrade, as much of that energy as possible.

  • So, for example, when a frog (HOAM) eats a fly (HOAM), the process of capture and digestion (temporary formation of an OAM) will transfer still useful energy from the fly to the frog at a maximum achievable rate. According to the expectations in this model, 50% of the energy in the fly will still be useful, while 50% of that energy will be degraded and discarded as waste heat. These two species will co-evolve such that there is a maximal power of the flow of non-degraded energy across this link of the trophic chain. But the system as a whole will evolve to produce waste heat at a maximum rate consistent with resource constraints (i.e. at carrying capacity of the ecosystem).

  • Um. OK, but? - Another vision of the MPP puts it this way. In every self-organizing system there are processes that gather and process energy. Through a kind of Darwinian process of natural selection, those processes that transfer the useful energy down the chain at the highest rate persist, and will prevent the less effective processes from persisting. However, by the time some fraction of the useful energy at last reaches the end of the chain, it is all ultimately degraded and discarded and no longer useful. The ever evolving decomposers and detrivores see to that. And so the system evolves (reconfigures itself) such that it is capturing and processing and degrading energy at maximum power.

  • So we get these two opposing dynamics. At the lower level, the production of entropy is minimized (maximum power of useful energy), while at the highest level, the production of entropy of the system itself is maximized (maximum power of consumption).

As species, and trophic webs, and ecosystems evolve, this oppositional dynamic gives rise to increasing power of both kinds. And it gives rise to increasing complexity.

"But", you may ask, "by what mechanism does it increase complexity, in defiance of the second law of thermodynamics?"

I believe it works like this. Random genetic mutations occur all of the time due to imperfections in the process of duplication of DNA during reproduction of organisms. Most of these accidental mutations reduce the function, and viability, and complexity of the affected offspring. However, on rare ocasions, such a mutation (a) gives the offspring a competitive advantage among its cohort, as argued by Darwin; and (b) gives the trophic chain of which it is a component a competitive advantage among its cohort of energy pathways through the system, as argued by Lotka. If that advantage arises from increased sophistication of function or other increased complexity, then that complexity persists. Such advantage will always alter the flow of energy through the trophic web, and each such increase in complexity will persist and spread throughout the web as it dominates the capture and flow of energy.

OamLab, then, is a model in which I can study the formation of OAMs within preformed chains of HOAMs. These chains of HOAMs compete for the right to survival in an environment that has a limited carrying capacity. I define three fitness criteria that can be used in a Darwinian competition for a scarce resource (the right to a slot on a limited list of chains) in which only the most fit can survive.

Research Questions - Here are my research questions for OamLab:

  • Under what conditions does such a self-organizing system of competing chains of HOAMs converge to chains that have a common efficiency of Eu <= 1/2, as predicted by Odum and Pinkerton (1955)?
  • What system dynamics can be understood from the study of such evolving self-organizing systems?

HOW IT WORKS

A small population of chains of HOAMs is created, each chain having a head, several body links, and a tail. The head has a smiley face. All but the tail can be RH-HOAMs. A chain with five HOAMs has them numbered from 0 to 4, and it can form 4 OAMs numbered 0 to 3. There is a limited ability to select how the chains are created, having high Eu at start, low Eu, or mixed Eu. Eu is "Odum's Efficiency", defined in his paper of 1955, and being calculated, for the AM, as Ml / Mh. When each chain is created it has a characteristic total drop time, as does each linkable OAM within the chain.

For example, in "horse race mode" the first OAM might require 6.4 seconds for Mh to fall and hit the floor. As it is running, the head HOAM and the next HOAM turn yellow. Then, on the seventh tick, the first OAM will exhaust its waste heat, delink, and then the next OAM will link up and start operations. The mass that was raised as Ml in the first OAM has now become the Mh of the second OAM. The little yellow indicators of the active OAM will move to the left.

When the last OAM in the chain discharges, the chain is done. It replicates itself via fission, one successful chain producing two daughter chains. Within each of the two daughter chains, a random HOAM is selected, and the size of the mass is adjusted randomly upwards or downwards by a random distance. Once they are mutated, one daughter inherits the library slot occupied by its parent, but a place must be found to put the other daughter. All other chains are scanned, and the chain that is least fit is removed and replaced by the daughter of the successful chain. It's survival of the fittest!

You can choose not to allow head HOAMs to mutate. You can choose not to allow tail HOAMs to mutate. This causes some interesting and perhaps unpredicted results. By default, at setup all tails have a mass of 16 kg. You can use the "Special Scenario" instructions to ensure that all heads have a common mass. Then runs with mutation of heads and tails turned off become quite interesting, as the mass of the heads and of the tails become limiting constraints within which the system must evolve.

There are three fitness criteria that may be used to decide which chains are removed and replaced:

  • Mj - JOINT - a chain manages a trade-off between fast replication (short time to drop) and maximal transfer of high-grade energy towards the tail of the chain.
  • Mt - TIME - a chain replicates as quickly as possible, without regard for efficiency.
  • Eu - ENERGY - a chain transfers as much useful energy as possible towards the OAMs in the tail of the chain, without regard for time to drop. I refer to Eu as "Odum's Efficiency".

There is some logic behind these choices. An organism that reproduces very quickly has an evolutionary advantage of speed over other organisms competing for the same ecological niche. On the other hand, an organism that can endow its offspring with the maximal amount of energy at birth has an evolutionary advantage of durability. Nature must find ways to trade off these two opposing benefits.

There are two different modes of operation:

  • In the 'horse race' mode, the application actually ticks away the seconds, the HOAMs link into OAMs, release Mh, and transfer energy as it falls. Typically, in this mode, an OAM may take 5-6 seconds to complete its run, and a chain of OAMs may take from 50 to 250 ticks to complete the process of priming and discharging all of the OAMs in the chain. As each OAM is primed and active, it is coloured yellow. The field of all HOAM chains, then, looks like a horse race and the yellow colours move from right to left. In this mode, a chain does not reproduce until it has dropped the mass in the last OAM. This mode of operation could properly be called a 'simulation' of the masses actually dropping, one after another. The combination of fitness determination by computation, and fitness determination by simulation potentially adds an indeterminate bias into the results.
  • When 'horse race' mode is turned off, the action is less cute, but the potential bias introduced by simulation is removed. In this mode, the time to drop for each chain is calculated, but the drop is not simulated. There is no race to complete a drop in order to have the right to reproduce. Instead, in each generation of chains, they are sorted in order of the currently active fitness criterion, and the most fit reproduce, using their offspring to displace the least fit. This is a breeding program, and not a competition for survival. The most fit, by fiat, always survive. The least fit, by fiat, are always removed from the population. With every tick of the model, a new generation of chains is born, and half of the old generation are displaced and removed.

Understandably, with the 'horse race' mode turned off, the model converges to steady state almost 100 times more quickly. But, does it converge to the same solution? It is an interesting exercise to predict whether it will, and why (or why not).

HOW TO USE IT

You have heard, I suppose, of one-player games. One of my tutored students calls programs like this a zero-player game. You set the parameters, you start it, and you watch it.

There are a total of 3 x 3 x 4 = 36 different scenarios, and each of those 36 scenarios can be run with different random number seeds.

To perform a run of the model:

  • Select two scenario options, one of the Darwinian fitness measures (3 options: Mj, Mt, or Eu), and one of the initial configuration options (3 options: high Eu, low Eu, or mixed Eu);
  • Select a random seed;
  • Click on the Setup button to configure the system according to the options chosen;
  • Select a mutation mode using the two mutation switches (4 options: heads only, tails only, both, or neither;
  • Click on the Go button.

There are other optional sliders to the right with which you can change the length of the chains, or change the number of chains on start. It's pretty flexible, that way. If you turn on the debug feature you can watch a stream of information about the changes as they happen.

As a run proceeds, within each chain OAMs are formed from right to left. It takes each a while to "drop", so you may see no movement for the first few clicks. The active OAMs are yellow. Monitors display current values for the fitness measures Mj, Mt, and Eu (joint, time, and useful energy respectively). Graphs also display the average fitness of each type for each class of OAM, so you can see a cross-section of the chains as they evolve.

THINGS TO NOTICE

  • To my knowledge, Odum did not talk about chains of OAMs, or anything of the sort. But, within any OAM, when it is formed, I calculate Odum's efficiency (Eu) as well as the other two fitness criteria and store them in the RH-HOAM of the moment. Within the head of each chain I store the geometric averages of all three fitness measures across all RH-HOAMs. Then there are monitors which display the geometric average of all three fitness measures across all RH-HOAMs in the system. Note that, if you turn off the ability to mutate for both heads and tails, then the "Geo Ave Eu" stays rock steady and does not change. Can you explain that?
  • As each HOAM in a chain, excepting the tail, has its opportunity to be the RH-HOAM of an active OAM, I store a variety of data in it, including Mj, Mt, and Eu.
  • When the tail is not allowed to mutate, the mass in the tail remains at (e.g.) 16 kg. You can consider this as the load on the chain. The chain must transmit enough 'useful' energy to the end of the chain to lift that load as quickly (time fitness measure) or as efficiently (energy fitness measure) as possible. Then, as the system evolves to a steady state, the average size of all heads evolves to take in sufficent energy to handle that load. Those that are poor at lifting the load in the prescribed manner, are selected out of the population.
  • There is a list called the "chains library" which will hold up to 30 chains. As long as there is space for new chains in the library (and on the playing field) there is no Darwinian selection. There is room for all daughters. But, once the library is full, the chains are competing for a scarce resource - the spaces in the chains library. Fit chains can find room to place a daughter on the list by removing the unfit offspring of a less fit chain. Look for a period of genetic drift before selection kicks in. This is, perhaps, difficult to see in this implementation since the library is full after only five generations of chains experience fission.

THINGS TO TRY

  • SEEDS - Note the behaviour of the system for the same scenario that differ only by different random seeds.

  • EXPERIMENTATION - Explore some of the 36 possible scenarios. Alter the scenarios and some setup parameters, and note how the different averages and quantities react. E.g. keep your eye on drop time, Eu and fitness measures.

  • A VIEW INSIDE - [ NOTE: Do not let this run for a long time. It generates very large debug log files in a short time.] This is a four step process: (Step 1) Open the command centre by clicking on the teeny tiny upwards-pointing arrow at the bottom left of the screen. (Step 2) Then when the command centre appears at the bottom of the screen, click on the 'upsize' and 'clear' buttons at the top right of the command centre. (Step 3 ) Then use the debug button and the associated 'chooser' (scroll the view screen to the right to find these in panel 3) to turn on debug reporting for one or all of the steps. (Step 4 ) Click on 'one tick'. Then scroll through the debug info that has been written into the command centre log.

  • DATA EXPORT - Right click on any of the line graphs, and choose export. Or, open the command centre as described above, and in the observer command line input box at the very bottom of the screen, enter the command EXPORT-WORLD "filename.CSV", where filename is a name of your choosing. I suggest, that e.g. if the model is at tick 35, the filename might be "world35.CSV". The quotes are needed. Then, use MS Excel, or a similar spreadsheet to load that file. Every piece of data in the model will be found there somewhere in the output. Or, toggle on CSV data export for DPX (data per mutation event) or DPT (data per tick) output. These files can be loaded with MS Excel.

  • ALL OF THE WAY INSIDE - There are key routines in the code that provide insight into how the model operates. Go to the code tab and search for each of these routines: f-assign-high-e-to-new-chain, fr-compute-energetics-of-oam, f-replicate-this-chain, or f-mutate-this-chain.

EXTENDING THE MODEL

WHY 0.618? - In one way, this model is a failure. Several of the references below mention that, in some circumstances, systems organize such that they work at efficiencies close to 0.618 instead of 0.5. The possibility of getting such varying results is mentioned in Silvert (1982) and Odum (1983). In this model the convergence seems to be around 0.618, and not below 0.5 as predicted by Odum (1955). In particular, I expected that the average efficiency Eu of the system would converge to 0.5 under the following settings: joint fitness measure; heads and tails allowed to mutate; any startup option; any random seed. However, with these settings, the convergence is to ~0.618, a number consistent with Odum's statement (1983) in which he said "We were aware that the non-steady state Atwood's machine gives maximum power at 62%, and I had actually measured it experimentally in the physics laboratory at the University of Florida in 1953'. So, one very interesting extension of this model would be to explore why it converges to 0.618 instead of 0.5, and to implement a 0.5 version.

NATURAL SELECTION - In horse race mode, there is a combination of natural selection (he who wins the race has a right to reproduce) and selection by breeding program (the computed fitness is used to determine who is selected out of the population). In the 'horse race off' mode, selection is purely by breeding program. In either case, the HOAMs are bound together into chains representing processes within a system. A possibly more interesting version of this model would be one in which free-roaming HOAMs compete for energy sources, and link in temporary couplings for energy transfer (i.e. eat one another). In such a model, a true trophic web would be demonstrated, and the MPP would be exhibited in a less structured simulacrum of nature. Then true natural selection could replace the somewhat more contrived breeding programs that characterise this model. That has been undertaken in MppLab.

NETLOGO FEATURES

This model is heavily dependent on techniques to manipulate lists of agents, as opposed to agentsets. The chains are formed as lists, and the library is a list of lists. In all cases the order of processing is key to the model's design, and so ordered lists work better than unordered sets.

Line graphs are proving to be excellent tools for collecting time-series data, which can be exported to files as CSV data and loaded into MS Excel spreadsheets.

RELATED MODELS

This model is one of a series of models that have been developed as part of a personal exploration of the dynamics of sustainable economies. They include:

  • PSoup - Written in C++, this model explores the nature of evolutionary forces in a purely biophysical economy. Based on a previous model called Simulated Evolution by Dr Michael Palmiter, PSoup places a number of bugs into a primordial soup and tracks their development. Offering scenarios at many levels, it demonstrates a variety of effects of evolution from simple development of effective food search patterns in the lowest levels, to development of the five main senses, genetic cross-over and sexual reproduction. The amazing observation, for me, coming out of this model was the speed and certainty of the development of complexity. Whenever a complex option was made available in the potential genetic space of the bugs, it was explored and very complex interactions between a cohort of highly varied genotypes would emerge. I also learned, from this model, that a constant flow of energy was a necessary condition for a sustainable biophysical economy, and a necessary pre-cursor for the emergence of complexity.

  • ModEco - There are two versions of ModEco. Written in C++, the first-written version of ModEco is a hybrid economy consisting of a PSoup-like biophysical economy joined to a financial economy. In ModEco every transfer of matter and/or energy from agent to agent is facilitated by a reciprocal transfer of money. Again, as long as there is a consistent flow of energy, the economy evolves towards a steady-state biophysical condition. However, sustainability of the financial economy has proven to be a very elusive property. It was discovered that economic sustainability was only possible if profit and loss was eliminated from the financial sector, and in its place an extremely precise regime of recognition and preservation of biophysical value was instituted. The scenario that exhibited sustainability under this harsh condition was called, somewhat jokingly, the "Perpetual Motion Machine", or "The PMM". In more technical terms, the equilibrium achieved in the PMM is an unstable equilibrium that must be maintained by continuous external intervention.

  • ModEco and the PMM - Written in NetLogo, this model is a replication of the C++ model, but only of the single scenario called The PMM. Again, three observations are clear from this model, and from the two previous models, when looking back over the common characteristics. First, the steady-state condition of any of these models demonstrates clear evidence of entropy production rising to a maximal value, and then staying there. The distributions of alleles (in PSoup), or of wealth (in ModEco and The PMM) develop and then hold shapes characteristic of the MEP, even while energy being degraded and entropy produced. Second, the emergence of complex economic organizations and inter-agent interactions seems to be an inevitable part of the evolution towards such a sustainable configuration. Third, and perhaps most important, the steady state can only be maintained by programming techniques that address the inherent instability of the equilibria associated with those steady states.

  • EiLab - Written in C++, this model enables a rather detailed investigation of the phenomenon of rising entropy in economic models. Inspired by the work of Dragulescu and Yakovenko (2000), it implements a capital exchange model in which I could study the origins and impact of entropy production in such models. EiLab stands for "Entropic Index Laboratory". I like this "laboratory" approach, because I can study many scenarios, generate lots of data, and then study the data. There were a few key observations coming out of this model. First, the study of entropy in such models is highly analogous to the study of entropy by Gibbs in his development of the concepts of "Gibbs' Free Energy". Second, in spite of the similarity to entropy, as Gibbs understood it, the entropy being investigated is not thermodynamic entropy, but a purely mathematical abstraction of it which is produced by a logical system executing logical processes distinct from chemical or heat-related effects. Third, the emergence of maximum entropy distributions was inevitable in these models, but the emergence of complexity was not, implying that there may be two distinct sets of conditions causing (a) the production of entropy, and (b) the production of complexity.

  • OamLab - Written in NetLogo, this model is one of two developed to explore more fully the phenomenon of production of complexity in economic systems. This is a continuation of my study of sustainability of economic systems. It is the more simple early member of a set of three models in which I explore the "Maximum Power Principle" as first proposed by A.J. Lotka and as developed by H.T. Odum. Both men argued that there is a need for a "fourth" law of thermodynamics, required to explain the persistent emergence of complexity. However, I found that Odum's ideas on this topic are difficult to decipher for a number of reasons. Ultimately, I found it necessary to restate his MPP as a set of three closely-related falsifiable hypotheses, and only then could I design models to test those hypotheses. OamLab is the first of three such models designed to test the validity of my restatement of the MPP. The prediction was that this model would evolve to a steady state in which the average efficiency was 0.5. Strangely, the steady-state average efficiency was 0.618, and not 0.5. This led to the discovery of a dispute between Odum and Silvert in the early 1980s over which of the two numbers was the correct prediction. On further investigation, it turns out that there are, in fact, two valid answers, and both results are easily validated as consistent with the MPP. So, I consider that model, simple though it be, as supporting the hypotheses of the MPP.

  • MppLab - Written in NetLogo, this is the middle member of the trio of models exploring the validity of the MPP. This had an exciting result, as it is able to model a trophic web, in action, with from 6 to 10 trophic levels all operational at once. I have made a YouTube video using this model.

  • CmLab - Written in NetLogo, this is another in the series of models designed to understand sustainable economics. The name is short for "Conservation of Money" Laboratory. It's another model derived from the work of Dragulescu and Yakovenko - a capital exchange model. PSoup is a purely biophysical economy. ModEco is a hybrid biophysical/financial economy. CmLab is a purely financial economy. CmLab is a capital exchange model in which bank loans are used to create money, and double-entry book-keeping is used to track it. It can provide, I think, some interesting insights into the nature of flows of money, which forms one half of a sustainable economy.

  • TpLab - Written in NetLogo, this model is intended to explore the hypothesized phenomenon that I am calling "Teleological Pruning". I argue that the beliefs and practices of any society are "pruned" and shaped by the same evolutionary pressures that shape our genes. Our societies are therefore shaped to conform to and agree with the effects of the Maximum Power Principle. This would explain why consumerism has emerged as the most destructive and persistent form of economic activity in our highly complex modern global economy. Our global economy has become the most powerful economy ever to have existed (in terms of energy consumed per year, and possibly in terms of energy consumed per person per year). Our beliefs (e.g. the necessity of endless economic growth) and our practices (materialism and consumerism) are now aligned with this destructive social trend. In TpLab, social beliefs are pitted against the effects of evolutionary pressures, with interesting effects.

CREDITS AND REFERENCES

Here's a list of formal references that were helpful to me:

  • A.J.Lotka (1922) 'Contribution to the Energetics of Evolution', Proceedings of the National Academy of Sciences of the United States of America, Vol. 8, No. 6 (Jun. 15, 1922), pp. 147-151.

  • A.J.Lotka (1922) 'Natural Selection as a Physical Principle', Proceedings of the National Academy of Sciences of the United States of America, Vol. 8, No. 6 (Jun. 15, 1922), pp. 151-154.

  • H.T.Odum and R.C.Pinkerton (1955) 'Time's speed regulator: The optimum efficiency for maximum output in physical and biological systems ', Am. Sci., 43 pp. 331–343.Lotka Lotka, Pinkerton, Odum, Costanza, Hall.

  • H.T.Odum (1971) 'Environment, Power and Society', John Wiley, New York, 336 pp.

  • W.Silvert (1982) 'The theory of power and efficiency in ecology', Ecol. Modelling, 15: 159-164.

  • H.T.Odum ( 1983) 'Maximum power and efficiency: a rebuttal', Ecol. Modelling, 20: 71-82.

  • C.A.S Hall, J.A.Standord and R.F.Hauer (1992) 'The distribution and abundance of organsims as a consequence of energy balances along multiple environmental gradients', OIKOS 65: 377-390.

  • C.A.S Hall, Ed. (1995) 'Maximum Power: The Ideas and Applications of H.T.Odum', University Press of Colorado, 393 pp.

  • C.A.S Hall ' The continuing importance of maximum power', Ecological Modelling 178 (2004) 107-113.

  • T.T.Cai, T.W.Olsen and D.E.Campbell 'Maximum (em)power: a foundational principle linking man and nature', Ecological Modelling 178 (2004) 115-119.

  • T.T.Cai, C.L.Montague and J.S.Davis 'The maximum power principle: An empirical investigation', Ecological Modelling 190 (2006) 317-335.

Here are some less formal references:

CONTACT ME: Garvin H. Boyle Email: orrery@rogers.com Web: http://orrery-software.webs.com/ Snail-mail: PO Box 1149, Richmond, Ontario, Canada, K0A 2Z0

Comments and Questions

Please start the discussion about this model! (You'll first need to log in.)

Click to Run Model

;;-----------------------------------------------------------------------------|
;; SECTION A – AUTHOR IDENTIFICATION AND CODE ABSTRACT
;;-----------------------------------------------------------------------------|
;;
;; File Name: OamLab_V1.10.nlogo
;; By Orrery Software
;; Dated: 2015-01-28
;; Author contact:
;;   Garvin H Boyle
;;   orrery@rogers.com
;;   orrery-software.webs.com

;; As the author, I welcome questions, discussion of issues and suggestions
;;   for improvements.

;;-----------------------------------------------------------------------------|
;; This OamLab app is a laboratory in which students can study the MPP.

;;-----------------------------------------------------------------------------|
;; SECTION B – INITIAL DECLARATIONS OF GLOBALS AND BREEDS
;;-----------------------------------------------------------------------------|
;;
;;-----------------------------------------------------------------------------|
;; This program was developed on NetLogo Version 5.0.5
;;

;;-----------------------------------------------------------------------------|
;; code-determined global variables
globals
[
  ;; The version should be coded in this global variable to be included in
  ;;   output files.
  gs-Version
  
  ;; Note: Some global variables are declared inside of switches, sliders and 
  ;;   choosers when the interface is constructed and are not declared here.
  ;;   For the sake of clarity and completeness, they are noted here.
  
  ;; There are several uses of global variables:
  ;;  - Toggles (switches), and choosers which enable or disable features;
  ;;  - Numbers (in variables or sliders) which act as parameters;
  ;;  - Numbers (in variables) which collect data.
  ;;
  ;; Those marked as 'native Boolean' have values of true or false.
  ;; Those marked as 'numeric Boolean' have values of 1 or 0.
   
  ;;---------------------
  ;; MODELING ENVIRONMENT
  ;;---------------------
  
  ;; Assumed “Model Settings” on startup
  ;; horizontal wrap: off
  ;; vertical wrap: off
  ;; location of origin: bottom left
  ;; patch size: 9.63 pixels
  ;;-----------------------------------------------------------------------------|
  ;; Implicit global variables due to model settings – patch locations
  ;; min-pxcor  0
  ;; max-pxcor  15
  ;; min-pycor  0
  ;; max-pycor  31
  
  ;;----------------------------
  ;; SCENARIO SELECTION CONTROLS
  ;;----------------------------
  
  ;; gs-scenario       ;; Chooser, string converts to a scenario number
  g-scenario-number    ;; scenario number, 0, 1 or 2; interpretation of gs-scenario

  ;; The possible scenarios.
  g-scenario-low-e     ;; scenario 0
  g-scenario-high-e    ;; scenario 1
  g-scenario-mixed-e   ;; scenario 2

  ;; gs-fitness-measure  ;; Chooser, string converts to a fitness number
  g-fitness-number     ;; scenario number, 0, 1 or 2; interpretation of gs-scenario

  ;; The possible scenarios.
  g-fitness-joint      ;; Fitness-number 0
  g-fitness-time       ;; Fitness-number 1
  g-fitness-energy     ;; Fitness-number 2
  
  ;; The special scenario.
  ;; g-set-max-head-size  ;; Has it's own input box
  
  ;; To halt a scenario at a pre-determined tick.
  ;; g-halt-at-tick       ;; Has it's own input box

  ;; Initialize the Pseudo Random Number Generator (PRNG).
  ;; g-use-this-seed      ;; Slider, ( 1 <= g-use-this-seed <= 100 )

  ;;-----------------------------------------------
  ;; BIOPHYSICAL SUB-SYSTEM CONTROLS AND PARAMETERS
  ;;-----------------------------------------------

  ;; Structural control parameters (Sliders)
  ;; g-no-of-chains-at-start     ;; The initial number of primed chains
  g-no-of-chains-max             ;; The maximum number of primed chains
  ;; g-length-of-chains          ;; The fixed length of all chains
  ;; g-drop-distance             ;; The distance a mass falls (D)
  ;; g-acceleration              ;; Acceleration due to gravity (g).
  
  ;; Chain structures
  g-no-of-chains                 ;; The current number of primed chains
  g-next-chain-sn                ;; The serial number of the next chain born
  gl-new-chain                   ;; a list in which a new chain is constructed
  gl-chains-lib                  ;; a list containing all chains
  gl-chains-indices              ;; a list if indices into gl-chains

  ;;-------------------------------------
  ;; SPECIAL SCENARIO
  ;;-------------------------------------
  g-max-head-size
  g-min-tail-size
  
  ;;-------------------------------------
  ;; END OF MODEL PARAMETERS AND CONTROLS
  ;;-------------------------------------
  
  ;;-------------------------------------
  ;; DATA COLLECTION AND DISPLAY CONTROLS
  ;;-------------------------------------
  
  ;; The following global variables are not model controls or paramaters, 
  ;;   but, rather, are variables used to collect data about the model 
  ;;   for display in the user interface, in some fashion (monitors or plots),
  ;;   or used to manage all of the debug routines and output.
  
  ;; SYSTEM-WIDE AGGREGATES
  ;; Used to verify conservation of cash, mass and energy.
  ;; Also used to make 'balance sheet' display on interface.

  ;; also g-no-of-chains above.
  g-no-of-hoams             ;; count of all HOAMs
  g-no-of-heads             ;; count of all heads
  g-no-of-bodies            ;; count of all bodies
  g-no-of-tails             ;; count of all tails

  ;; These lists have g-length-of-chains entries. 
  gl-ttl-lg-nrg-per-hoam    ;; list; total of unusable energy
  gl-ttl-mass-per-hoam      ;; list; total mass
  ;; These lists have ( g-length-of-chains - 1 ) entries.
  gl-ttl-hg-nrg-per-oam     ;; list; total of usable energy
  gl-pi-Mj-per-oam          ;; list; product of joint fitness measures
  gl-pi-Mt-per-oam          ;; list; product of time fitness measures
  gl-pi-Eu-per-oam          ;; list; product of Odum Efficiency measures
  gl-geo-Mj-per-oam         ;; list; GeoAve of joint fitness measures
  gl-geo-Mt-per-oam         ;; list; GeoAve of time fitness measures
  gl-geo-Eu-per-oam         ;; list; GeoAve of Odum Efficiency measures

  gl-ttl-hg-nrg-per-tick    ;; list; average of usable energy
  gl-ttl-lg-nrg-per-tick    ;; list; average of unusable energy

  ;; Assorted measures
  g-geo-Mj                  ;; GeoAve of joint fitness measure all OAMs
  g-geo-Mt                  ;; GeoAve of time fitness measure all OAMs
  g-geo-Eu                  ;; GeoAve of Odum Efficiency measure all OAMs
  g-ttl-age-of-chains       ;; the sum of age of all chains
  g-ttl-dt-of-chains        ;; the sum of discharge time of all chains
  
  ;; Colours
  g-hoam-colour             ;; the default colour for a HOAM
  g-primed-colour           ;; the default colour for a primed HOAM
  gl-colour-pallette        ;; list of allowed colours
  
  ;; OPERATIONAL SWITCHES
  ;; Switch to allow the mass in heads to mutate.
  ;; gb-mutate-heads
  ;; Switch to allow the mass in tails to mutate.
  ;; gb-mutate-tails
  ;; Switch to disable horse-race mode.
  ;; gb-horse-race-on
  
  ;; PLOTS
  ;; Switch for plots
  ;; gb-plots-on              ;; Switch, Native Boolean, enables/disables plotting

  ;; Plot "Age Distribution - Chains"
  ;; Plot "Ln(Mass) Distribution - HOAMs"
  ;; Plot "Ln(Mass) Per HOAM"
  ;; Plot "Ave(Eu) Per OAM"
  ;; Plot "Average Drop Time - Chains"
  ;; Plot "Ave(Aggregated Fitness Measures)"
  
  
  ;; Other - built-in or declared implicitly in plot interface items
  ;; See each plot design dialogue.

  ;;--------------------------
  ;; DATA CAPTURE TO CSV FILES
  ;;--------------------------

  ;; CSV means "Character Separated Values"
  ;; I use a space to separate values.  This can be read by MS Excel.

  g-recno-max        ;; Maximum record number for all files.

  ;; Data Per Xaction
  gb-dpx-on          ;; Numeric Boolean switch
  gs-dpx-status      ;; Interpretation of gb-dpx-on
  gs-dpx-file-name   ;; The file name
  g-dpx-recno        ;; The number of the last record written.

  ;; Data Per Tick
  gb-dpt-on          ;; Numeric Boolean switch
  gs-dpt-status      ;; Interpretation of gb-dpt-on
  gs-dpt-file-name   ;; The file name
  g-dpt-recno        ;; The number of the last record written.

  ;;---------------
  ;; DEBUG CONTROLS
  ;;---------------
  
  gb-debug-on                 ;; Numeric Boolean, opens debug log file, 0 or 1.
  gs-debug-status             ;; for monitor, '1 (On)' or '0 (Off)', 
  ;; gs-debug-step-chooser    ;; Chooser, used with gb-debug-flow-on
  gb-debug-flow-on            ;; Numeric Boolean, in association with chooser, 
  gs-log-file-name            ;; name of the debug log file
                              ;;   opens flow to log file
  ;; gb-debug-show-steps      ;; Switch, Native Boolean, show in command centre
]


;;-----------------------------------------------------------------------------|
;; Attributes of patches
patches-own 
[
  ;; BUILT-IN ATTRIBUTES 
  ;; pxcor        ;; min-pxcor <= pxcor < max-pxcor
  ;; pycor        ;; min-pxcor <= pxcor < max-pxcor 
  ;; pcolor       ;; color of this patch ( 0 <= color < 140 ) 
  ;; plabel       ;; label of this patch
  ;; plabel-color ;; color of this patch's label ( 0 <= label-color < 140 ) 
   
  ;; OamLab-DETERMINED ATTRIBUTES
  ;; Nil.
]

;;-----------------------------------------------------------------------------|
;; Attributes of links
;; nil
;; I don't understand links and did not use any.

;;-----------------------------------------------------------------------------|
;; Turtles and breeds
breed [ heads  head ]
breed [ bodies body ]
breed [ tails  tail ]

;;-----------------------------------------------------------------------------|
;; Attributes of heads
heads-own 
[
  ;; BUILT-IN ATTRIBUTES
  ;; who         ;; fixed id number
  ;; breed       ;; to which breed this turtle belongs [head]
  ;; heading     ;; 0 <= heading < 360, 0 = north
  ;; xcor        ;; min-pxcor <= xcor < max-pxcor
  ;; ycor        ;; min-pxcor <= xcor < max-pxcor
  ;; size        ;; size relative to a patch, default is 1
  ;; shape       ;; a shape chosen from the shape library
  ;; color       ;; color of this turtle ( 0 <= color < 140 )
  ;; pen-mode    ;; "up" or "down"
  ;; pen-size    ;; in pixels
  ;; hidden?     ;; true or false
  ;; label       ;; label of this turtle
  ;; label-color ;; color of this turtle's label ( 0 <= label-color < 140 )
  
  ;; USER-DETERMINED ATTRIBUTES
  ;; Associated with chain.
  mas-sn                   ;; serial number of parent chain.
  chain-sn                 ;; serial number of this chain.
  index-into-chains-lib    ;; the index of this chain in gl-chains-lib
  age-of-chain             ;; age of this chain
  primed-rh-hoam-index     ;; index of active RH-HOAM
  primed-lh-hoam-index     ;; index of active LH-HOAM
  default-colour           ;; as it says
  chain-time-to-drop       ;; total time required to discharge all OAMs
  ;; For these measures, the least fit has the lowest measure.
  Mj-pi-this-chain         ;; product of Mj of chain
  Mt-pi-this-chain         ;; product of Mt of chain
  Eu-pi-this-chain         ;; product of Eu of chain
  Mj-geo-this-chain        ;; GeoAve of Mj of chain
  Mt-geo-this-chain        ;; GeoAve of Mt of chain
  Eu-geo-this-chain        ;; GeoAve of Eu of chain
  fitness-measure          ;; currently active fitness measure

  ;; Associated with HOAM.
  index-into-chain     ;; the serial index (position) of this HOAM
  mass                 ;; the mass in this HOAM

  ;; Associated with rh-hoam.
  oam-time-to-drop     ;; time required for heavy mass to fall
  age-to-discharge     ;; age at which discharge is possible
  energy-to-transfer   ;; amount of high-grade energy to be transferred
  energy-to-discharge  ;; amount of low-grade energy to be exhausted
  Mj-in-oam            ;; Mj is joint fitness measure
  Mt-in-oam            ;; Mt is time fitness measure
  Eu-in-oam            ;; Eu is Odum's efficiency measure
]

;;-----------------------------------------------------------------------------|
;; Attributes of bodies
bodies-own 
[
  ;; BUILT-IN ATTRIBUTES
  ;; who      ;; fixed id number
  ;; breed    ;; to which breed this turtle belongs [body]
  ;; heading  ;; 0 <= heading < 360, 0 = north
  ;; xcor     ;; min-pxcor <= xcor < max-pxcor
  ;; ycor     ;; min-pxcor <= xcor < max-pxcor
  ;; size     ;; size relative to a patch, default is 1
  ;; shape    ;; a shape chosen from the shape library
  ;; color    ;; color of this turtle ( 0 <= color < 140 )
  ;; pen-mode ;; "up" or "down"
  ;; pen-size ;; in pixels
  ;; hidden?  ;; true or false
  ;; label    ;; label of this turtle
  ;; label-color ;; color of this turtle's label ( 0 <= label-color < 140 )
   
  ;; USER-DETERMINED ATTRIBUTES
  ;; Associated with chain.
  ;; Nil.

  ;; Associated with this HOAM.
  index-into-chain     ;; the serial index (position) of this HOAM
  mass                 ;; the mass in this HOAM

  ;; Associated with rh-hoam.
  oam-time-to-drop     ;; time required for heavy mass to fall
  age-to-discharge     ;; age at which discharge is possible
  energy-to-transfer   ;; amount of high-grade energy to be transferred
  energy-to-discharge  ;; amount of low-grade energy to be exhausted
  Mj-in-oam            ;; Mj is joint fitness measure
  Mt-in-oam            ;; Mt is time fitness measure
  Eu-in-oam            ;; Eu is Odum's efficiency measure
]

;;-----------------------------------------------------------------------------|
;; Attributes of tails
tails-own 
[
  ;; BUILT-IN ATTRIBUTES
  ;; who      ;; fixed id number
  ;; breed    ;; to which breed this turtle belongs [tail]
  ;; heading  ;; 0 <= heading < 360, 0 = north
  ;; xcor     ;; min-pxcor <= xcor < max-pxcor
  ;; ycor     ;; min-pxcor <= xcor < max-pxcor
  ;; size     ;; size relative to a patch, default is 1
  ;; shape    ;; a shape chosen from the shape library
  ;; color    ;; color of this turtle ( 0 <= color < 140 )
  ;; pen-mode ;; "up" or "down"
  ;; pen-size ;; in pixels
  ;; hidden?  ;; true or false
  ;; label    ;; label of this turtle
  ;; label-color ;; color of this turtle's label ( 0 <= label-color < 140 )
   
  ;; USER-DETERMINED ATTRIBUTES
  ;; Associated with chain.
  ;; Nil.

  ;; Associated with the HOAM.
  index-into-chain     ;; the serial index (position) of this HOAM
  mass                 ;; the mass in this HOAM

  ;; Associated with rh-hoam.
  ;; Nil.
]

;;-----------------------------------------------------------------------------|
;; SECTION C – INITIALIZATION OR SETUP PROCEDURE( S )
;;-----------------------------------------------------------------------------|

;;-----------------------------------------------------------------------------|
;; The 'autostart' startup routine

to startup
  ;; This routine is to be executed by the observer.

  ;; The manual describes this routine as follows:
  ;; This procedure, if it exists, will be called when a model is first loaded in 
  ;;   the NetLogo application.  Startup does not run when a model is run headless 
  ;;   from the command line, or by parallel BehaviorSpace.

  ;; On loading the model, the debug feature is always off.
  set gb-debug-on 0
  set gs-debug-status "0 (Off)"
  
  ;; On loading the model, the data capture is always off.
  f-close-dpx-file
  f-close-dpt-file
  
  ;; On loading the model, the model, the choosers, switches and sliders are
  ;;   always reset to the values that are known to work.  Only the choosers
  ;;   for the scenario is not reset.  The last saved 
  ;;   selection of scenario is persistant.  This allows the 'Reset Defaults'
  ;;   button to NOT reset the scenario.
  f-reset-default-parameters

  ;; Run the setup routine to initialize other globals.
  setup
  ;; End of startup
end 

;;-----------------------------------------------------------------------------|
;; The setup button(s)

to setup
  ;; This routine is to be executed by the observer.

  ;; NOTE: The contents of switches, sliders, and choosers seem to be 
  ;;   immune to these 'clear' commands.
  clear-ticks
  clear-turtles
  clear-patches
  clear-drawing
  clear-all-plots
  clear-output
  ;; clear-globals   ;; Suppressed to make gb-debug-on value persistent.
  ;; NOTE: Instead of 'clear-globals', you must ensure all globals are 
  ;;   initialized properly in 'setup'.
  
  ;; The version should be coded in this global variable to be included in
  ;;   output files.
  set gs-Version "OamLab_V1.10" 

  ;; Debug features may be off or on depending on history.
  ;;   - Perhaps 'Setup' was called by 'to Startup'.
  ;;   - Perhaps 'setup' was called during a 'BehaviorSpace' run.
  ;;   - Perhaps 'setup' was called by a user-pushed 'setup' button.
  ;; Setup needs to handle some quasi-persistant values correctly regardless of
  ;;   the history.  For gb-debug-on, in particular, I want it to be 
  ;;   persistant so I can have debug output from the 'setup' routine routed
  ;;   to the debug log file, or to the command centre.
  
  ;; 'startup' automatically sets gb-debug-on to 0 when the application is first
  ;;   loaded.  I want to be able to (A) toggle debug on, then, (B) press 
  ;;   'setup' and watch the debug output of the 'setup' command.  The gb-debug-on
  ;;   must be persistant through the above 'clear' commands.  The debug log 
  ;;   file name and status, however, should not be persistent and must be 
  ;;   reset when setup runs, if appropriate.
  ifelse ( gb-debug-on = 1 )
  [
    ;; Debug is on due to user setting, so file name and status should be 
    ;;   reset.  I do this by turn the feature off then on.
    ;; First toggle it off, closing any remnant log file, if needed.
    f-toggle-debug
    ;; Then toggle it back on, opening a new time-stamped log file.
    f-toggle-debug
  ]
  ;; else
  [
    ;; Debug is off, possibly due to startup execution, possibly due to user 
    ;;   choice.
    ;; Ensure associated variables have compatible settings.
    set gb-debug-on 0              ;; Redundant but ensures consistency.
    set gs-debug-status "0 (Off)"  ;; Redundant but ensures consistency.
    set gb-debug-flow-on 0         ;; Step-specific flow is off.
    file-close-all                 ;; Close the debug log file.
    set gs-log-file-name "dummyname"
  ]
  
  ;; Now, do the standard check that is done at the start of each debuggable 
  ;;   routine.  This must follow the clear commands, which reset everything 
  ;;   except globals, switches, sliders and choosers.
  if( gb-debug-on = 1 )
  [
    ifelse( ( gs-debug-step-chooser = "all" ) or ( gs-debug-step-chooser = "setup" ) )
    [ set gb-debug-flow-on 1 LOG-TO-FILE "" LOG-TO-FILE word "Setup: Debug on; tick = " 0 ]
    [ set gb-debug-flow-on 0 ]
  ]

  ;; g-use-this-seed comes from a slider, and is persistant.
  random-seed g-use-this-seed      ;; Tells the PRNG to use this seed.
  
  ;; Data capture to file feature.
  ;;   The data capture files may be open, and the features, stored in switches,
  ;;   may be on, as they are persistent.  Ensure they are off.
  f-close-dpx-file
  f-close-dpt-file
  
  ;; Set the limit on the number of records in a CSV data file.
  ;; This applies to dpx and dpt files. (Debug log files?) 
  set g-recno-max 500000
  
  ;; There are 3 scenarios possible
  set g-scenario-low-e   0         ;; low Odum Efficiency at start
  set g-scenario-high-e  1         ;; high Odum Efficiency at start
  set g-scenario-mixed-e 2         ;; mixed Odum Efficiency at start

  ;; Use the input from the chooser gs-scenario to invoke the selected scenario.
  set g-scenario-number g-scenario-low-e  ;; default
  ifelse( gs-scenario = "Low Eu (Odum Efficiency)" )
  [
    set g-scenario-number g-scenario-low-e
  ]
  ;; else
  [
    ifelse( gs-scenario = "High Eu (Odum Efficiency)" )
    [
      set g-scenario-number g-scenario-high-e
    ]
    ;; else
    [
      ;; gs-scenario = "Mixed Eu (Odum Efficiency)"
      set g-scenario-number g-scenario-mixed-e
    ]
  ]
  
  ;; Special scenario
  set g-set-max-head-size -1 ;; An invalid value, has it's own input box
  
  ;; There are 3 fitness tests possible
  set g-fitness-joint   0         ;; time and energy
  set g-fitness-time    1         ;; time
  set g-fitness-energy  2         ;; energy

  ;; Use the input from the chooser gs-fitness-measure to invoke the selected test.
  set g-fitness-number g-fitness-joint  ;; default
  ifelse( gs-fitness-measure = "Mj - Joint" )
  [
    set g-fitness-number g-fitness-joint
  ]
  ;; else
  [
    ifelse( gs-fitness-measure = "Mt - Minimal Time To Drop" )
    [
      set g-fitness-number g-fitness-time
    ]
    ;; else
    [
      ;; gs-fitness-measure = "Eu - Maximal Useful Energy"
      set g-fitness-number g-fitness-energy
    ]
  ]
  
  ;; For debugging the debug feature!!!  Suppressed now.
  ;; show ( word "SETUP: Debug Is " gb-debug-on )
  ;; show ( word "SETUP: Debug Status Is " gs-debug-status )
  ;; show ( word "SETUP: Step Chooser Is " gs-debug-step-chooser )
  ;; show ( word "SETUP: Flow Control Is " gb-debug-flow-on )

  ;; For debugging the setup procedure, log the values of the globals.
  LOG-TO-FILE ( word "Do-set: Scenario number     - " g-scenario-number ) 
  LOG-TO-FILE ( word "Do-set: Scenario name       - " gs-scenario )
  LOG-TO-FILE ( word "Do-set: Fitness test number - " g-fitness-number ) 
  LOG-TO-FILE ( word "Do-set: Fitness test name   - " gs-fitness-measure )
  LOG-TO-FILE ( word "Do-set: Random seed         - " g-use-this-seed )

  LOG-TO-FILE ( "" )
  LOG-TO-FILE ( "Do-set: STRUCTURAL PARAMETERS (Sliders):" )
  LOG-TO-FILE ( word g-no-of-chains-at-start " - Number of chains on initiation." )
  LOG-TO-FILE ( word g-no-of-chains-max " - Maximum number of chains." )
  LOG-TO-FILE ( word g-length-of-chains " - Length of all chains"  )
  LOG-TO-FILE ( word g-drop-distance " - Distance a mass falls"  )
  LOG-TO-FILE ( word g-acceleration " - Acceleration due to gravity"  )

  ;; Zero the structural measures.
  ;; Operational variable first
  set g-no-of-chains 0
  
  LOG-TO-FILE ( "" )
  LOG-TO-FILE ( "Do-set: CURRENT STATUS INDICATORS:" )
  LOG-TO-FILE ( word g-no-of-chains " - Current number of chains"  )
  
  ;; Zero the data collection variables next.
  set g-no-of-hoams  0
  set g-no-of-heads  0
  set g-no-of-bodies 0
  set g-no-of-tails  0

  set g-max-head-size 0
  set g-min-tail-size 0

  ;; Zero the lists for structural averages.
  set gl-ttl-lg-nrg-per-hoam  ( n-values g-length-of-chains [0.0] )
  set gl-ttl-mass-per-hoam    ( n-values g-length-of-chains [0.0] )
  set gl-ttl-hg-nrg-per-oam   ( n-values ( g-length-of-chains - 1 ) [0.0] )
  set gl-pi-Mj-per-oam        ( n-values ( g-length-of-chains - 1 ) [1.0] )
  set gl-pi-Mt-per-oam        ( n-values ( g-length-of-chains - 1 ) [1.0] )
  set gl-pi-Eu-per-oam        ( n-values ( g-length-of-chains - 1 ) [1.0] )
  set gl-geo-Mj-per-oam       ( n-values ( g-length-of-chains - 1 ) [1.0] )
  set gl-geo-Mt-per-oam       ( n-values ( g-length-of-chains - 1 ) [1.0] )
  set gl-geo-Eu-per-oam       ( n-values ( g-length-of-chains - 1 ) [1.0] )

  ;; Zero the per tick throughput measures.
  set gl-ttl-hg-nrg-per-tick  ( n-values g-length-of-chains [0.0] )
  set gl-ttl-lg-nrg-per-tick  ( n-values g-length-of-chains [0.0] )

  ;; Zero other assorted measures.
  set g-geo-Mj 0   ;; Joint fitness measure, all chains
  set g-geo-Mt 0   ;; Time fitness measure, all chains
  set g-geo-Eu 0   ;; Odum Efficiency measure, all chains
  set g-ttl-age-of-chains 0
  set g-ttl-dt-of-chains 0  ;; Drop time, all chains
  
  ;; Colours
  set g-hoam-colour 95     ;; the default colour for a HOAM
  set g-primed-colour 45   ;; the default colour for a primed HOAM
  set gl-Colour-Pallette [5 15 25 35 55 75 85 95 105 115 125 135]
  ;; Note: colour 65 (lime) is used for the background, and has been elided here.
  ;; Note: colour 45 (yellow) is used for primed haoms, and has been elided here.
  
  ;; The main lists.
  set gl-new-chain []      ;; construction site of new chains of turtles
  set gl-chains-lib []     ;; library of current chains of hoams
  set gl-chains-indices [] ;; indices of unfit chains
  set g-next-chain-sn 0    ;; Serial number of the next chain
  
  ;; Turn on the mutating heads function.
  ;; set gb-mutate-heads true
  ;; Turn on the mutating tails function.
  ;; set gb-mutate-tails true
  ;; Disable the horse race mode.
  ;; set gb-horse-race-on false
  
  ;; Turn on the plotting function.
  ;; Default is 'on'.
  set gb-plots-on true
  
  set-default-shape heads  "face happy"  ;; pulled from shapes library
  set-default-shape bodies "circle"      ;; pulled from shapes library
  set-default-shape tails  "circle"      ;; pulled from shapes library

  ask patches 
  [ 
    set pcolor lime
  ]
   
  f-build-initialized-chains

  ;; Aggregates.
  ;; The aggregates must be updated after the chains are built.
  ;; The aggregates must be updated before any plots are invoked.
  f-update-aggregates  ;; Totals and averages.
    
  reset-ticks      ;; restarts tick counter and runs setup commands within plots

  ;; This call requires that 'reset-ticks' be called first.
  f-compute-energetics-of-chains
  ;; Update the aggregates again, after energetics computed.
  f-update-aggregates  ;; Totals and averages.

  ;; Clears unwanted zeros in plots.
  clear-all-plots
  setup-plots
  
  ;; Debug controls
  set gb-debug-flow-on 0 ;; Boolean, in association with chooser, turns debug LOG-TO-FILE on/off
  set g-halt-at-tick -1  ;; input variable to set a tick for stopping

  LOG-TO-FILE "Do-set: procedure completed" 

  ;; End of setup
end 

;;-----------------------------------------------------------------------------|
;; Initialize a set of chains.

to f-build-initialized-chains
  ;; This routine is to be executed by the observer.

  ;; g-no-of-chains is initialized in to Setup.
  while [ g-no-of-chains < g-no-of-chains-at-start ]
  [
    LOG-TO-FILE ( word "  Initializing: Chain " g-no-of-chains )
    f-build-initialized-chain
    
    ;; g-no-of-chains is incremented in f-build-initialized-chain.
    ;; Give the new chain a serial number.
    let this-chain-index ( g-no-of-chains - 1 )
    let this-chain ( item this-chain-index gl-chains-lib )
    let this-head ( item 0 this-chain )
    ask this-head
    [
      set chain-sn ( g-next-chain-sn )
      set g-next-chain-sn ( g-next-chain-sn + 1 )
      set mas-sn -1  ;; These chains have no parent.
    ]
  ] 
  
  ;; end f-build-initial-chains
end 

;;-----------------------------------------------------------------------------|
;; Build an initialized chain.

to f-build-initialized-chain
  ;; This routine is to be executed by the observer.

  ;; Create a new chain near the origin in the global variable.
  f-populate-gl-new-chain
  
  f-add-new-chain-to-chains-lib
  
  ;; end f-build-initialized-chain
end 

;;-----------------------------------------------------------------------------|
;; Add chain to library and move into arena.

to f-add-new-chain-to-chains-lib
  ;; This routine is to be executed by the observer.

  ;; Move this chain into place in the arena.  Does not put turtles in lib.
  f-relocate-this-chain gl-new-chain
  
  ;; Mark this chain with an index into gl-chains-lib.
  let head ( item 0 gl-new-chain )
  ask head
  [
    set index-into-chains-lib g-no-of-chains
  ]
  
  set gl-chains-lib ( lput gl-new-chain gl-chains-lib )
  
  ;; Increment the counter.
  set g-no-of-chains ( g-no-of-chains + 1 )
  
  set gl-new-chain []  
  ;; End of f-add-new-chain-to-chains-lib
end 

;;-----------------------------------------------------------------------------|
;; Initialize a single chain.

to f-populate-gl-new-chain
  ;; This routine is to be executed by the observer.

  LOG-TO-FILE ( word "    Initializing in gl-new-chain" )
  ;; Start with the head.
  let this-colour 45
  let this-patch patch 0 0
  ask this-patch 
  [ 
    sprout-heads 1 
    [ 
      set default-colour ( one-of gl-colour-pallette )
      set this-colour default-colour
    ]
  ] 
  let this-head heads-on this-patch
  set gl-new-chain ( list this-head )
  ask this-head 
  [ 
    f-initialize-new-head  
    set index-into-chain 0
  ]  ;; Initialize and move it out of the road.
  set g-no-of-heads ( g-no-of-heads + 1 )
  set g-no-of-hoams ( g-no-of-hoams + 1 )
  LOG-TO-FILE ( word "      Head initialized: HOAM 0" )
    
  ;; Add the body parts.
  let this-hoam-index 1  ;; half open Atwood's Machine
  while [ this-hoam-index < ( g-length-of-chains - 1 ) ]
  [
    ask this-patch [ sprout-bodies 1 [ set color this-colour ] ] 
    let this-body bodies-on this-patch
    ask this-body  
    [ 
      f-initialize-new-body 
      set index-into-chain this-hoam-index
    ]
    set gl-new-chain ( lput this-body gl-new-chain )  ;; add to end of chain
    set g-no-of-bodies ( g-no-of-bodies + 1 )
    set g-no-of-hoams ( g-no-of-hoams + 1 )

    LOG-TO-FILE ( word "      Body initialized: HOAM " this-hoam-index )
    set this-hoam-index ( this-hoam-index + 1 )
  ]

  ;; End with the tail.
  ask this-patch [ sprout-tails 1 [ set color this-colour ] ] 
  let this-tail tails-on this-patch
  ask this-tail 
  [ 
    f-initialize-new-tail 
    set index-into-chain ( g-length-of-chains - 1 )  ;; an index
  ]
  set gl-new-chain ( lput this-tail gl-new-chain )  ;; add to end of chain
  set g-no-of-tails ( g-no-of-tails + 1 )
  set g-no-of-hoams ( g-no-of-hoams + 1 )
  LOG-TO-FILE ( word "      Tail initialized: HOAM " ( g-length-of-chains - 1 ) )
  
  ;; The parts are now all in place in the list.
  ;; Adjust masses and compute efficiencies.
  LOG-TO-FILE ( word "    Efficiencies being adjusted: Scenario no " g-scenario-number )
  ifelse ( g-scenario-number = g-scenario-low-e )
  [
    f-assign-low-e-to-new-chain gl-new-chain
  ]
  ;; else
  [
    ifelse ( g-scenario-number = g-scenario-high-e )
    [
      f-assign-high-e-to-new-chain gl-new-chain
    ]
    ;; else
    [
      ;; g-scenario-number = g-scenario-mixed-e
      f-assign-mixed-e-to-new-chain gl-new-chain
    ]
  ]
  
  ;; end f-populate-gl-new-chain
end 

;;-----------------------------------------------------------------------------|
;; Initialize a single head.

to f-initialize-new-head
  ;; This routine is to be executed by a head.

  ;; BUILT-IN ATTRIBUTES
  ;; who         ;; set automatically
  set heading 90 ;; east
  ;; xcor        ;; min-pxcor <= xcor < max-pxcor
  ;; ycor        ;; min-pxcor <= xcor < max-pxcor
  ;; pen-mode    ;; "up" or "down"
  ;; pen-size    ;; in pixels
  ;; size        ;; size relative to a patch, default is 1

  ;; USER-DETERMINED ATTRIBUTES
  ;; Associated with chain.
  set mas-sn -1                 ;; serial number of parent chain
  set chain-sn -1               ;; serial number of parent chain
  set index-into-chains-lib -1  ;; index of this chain in gl-chains-lib
  set age-of-chain 0            ;; age of this chain
  set primed-rh-hoam-index 0    ;; index of active RH-HOAM
  set primed-lh-hoam-index 0    ;; index of active LH-HOAM
  set chain-time-to-drop 0      ;; total time for chain to discharge all OAMs.

  set Mj-pi-this-chain       1  ;; product of Mj across chain
  set Mt-pi-this-chain       1  ;; product of Mt across chain
  set Eu-pi-this-chain       1  ;; product of Eu across chain
  set Mj-geo-this-chain      1  ;; geometric average Mj of chain
  set Mt-geo-this-chain      1  ;; geometric average Mt of chain
  set Eu-geo-this-chain      1  ;; geometric average Eu of chain
  set fitness-measure        1  ;; active fitness-measure

  ;; Associated with HOAM.
  set index-into-chain 0     ;; the serial position
  set mass 16                ;; the mass in this HOAM

  ;; Associated with rh-hoam.
  set oam-time-to-drop 0     ;; time required for heavy mass to fall
  set age-to-discharge  -1   ;; next tick at which discharge is possible
  set energy-to-transfer 0   ;; amount of high-grade energy to be transferred
  set energy-to-discharge  0 ;; amount of low-grade energy to be exhausted
  set Mt-in-oam 1            ;; Mt is time fitness measure
  set Eu-in-oam 1            ;; Eu is Odum's efficiency measure
  set Mj-in-oam 1            ;; Mj is joint fitness measure
  
  forward 1  ;; Move it out of the road.
  ;; end f-initialize-new-head
end 

;;-----------------------------------------------------------------------------|
;; Initialize a single body element.

to f-initialize-new-body
  ;; This routine is to be executed by a body.

  ;; BUILT-IN ATTRIBUTES
  ;; who        ;; set automatically
  set heading 90 ;; east
  ;; xcor       ;; min-pxcor <= xcor < max-pxcor
  ;; ycor       ;; min-pxcor <= xcor < max-pxcor
  ;; pen-mode   ;; "up" or "down"
  ;; pen-size   ;; in pixels
  ;; size       ;; size relative to a patch, default is 1

  ;; USER-DETERMINED ATTRIBUTES
  ;; Associated with HOAM.
  ;; set index-into-chain 1  ;; the serial position
  set mass 16                ;; the mass in this HOAM

  ;; Associated with rh-hoam.
  set oam-time-to-drop 0     ;; time required for heavy mass to fall
  set age-to-discharge -1    ;; next tick at which discharge is possible
  set energy-to-transfer 0   ;; amount of high-grade energy to be transferred
  set energy-to-discharge 0  ;; amount of low-grade energy to be exhausted
  set Mt-in-oam 1            ;; Mt is time fitness measure
  set Eu-in-oam 1            ;; Eu is Odum's efficiency measure
  set Mj-in-oam 1            ;; Mj is joint fitness measure
 
  forward 1  ;; Move it out of the road.
  ;; end f-initialize-new-body
end 

;;-----------------------------------------------------------------------------|
;; Initialize a single tail.

to f-initialize-new-tail
  ;; This routine is to be executed by a tail.

  ;; BUILT-IN ATTRIBUTES
  ;; who        ;; set automatically
  set heading 90 ;; east
  ;; xcor       ;; min-pxcor <= xcor < max-pxcor
  ;; ycor       ;; min-pxcor <= xcor < max-pxcor
  ;; pen-mode   ;; "up" or "down"
  ;; pen-size   ;; in pixels
  ;; size       ;; size relative to a patch, default is 1

  ;; USER-DETERMINED ATTRIBUTES
  ;; Associated with HOAM.
  ;; set index-into-chain 1  ;; the serial position
  set mass 16                ;; the mass in this HOAM
  
  forward 1  ;; Move it out of the road.
  ;; end f-initialize-new-tail
end 

;;-----------------------------------------------------------------------------|
;; Initialize the masses and efficiencies - low e.

to f-assign-low-e-to-new-chain [ to-this-chain ]
  ;; This routine is to be executed by the observer.
  
  ;; This does not alter the mass in the tail.
  ;; For low efficiencies, the heavy mass must be substantially larger. 
  let this-lhhoam-index ( g-length-of-chains - 1 )  ;; half open Atwood's Machine
  while [ this-lhhoam-index > 0 ] 
  [
    let this-lhhoam ( item this-lhhoam-index to-this-chain ) ;; target the lh-HOAM.
    let next-rhhoam ( item ( this-lhhoam-index - 1 ) to-this-chain ) ;; target the rh-HOAM.
    
    let light-mass ( item 0 [mass] of this-lhhoam )
    let heavy-mass ( light-mass / 0.10 )
    let this-Eu ( light-mass / heavy-mass )
    let mass-total ( heavy-mass + light-mass )
    let mass-diff  ( heavy-mass - light-mass )
    let this-Mt ( ( mass-diff / mass-total ) ^ ( 0.5 ) )
    let this-Mj ( this-Mt * this-Eu )
    
    ask next-rhhoam 
    [ 
      set mass heavy-mass
      set Mt-in-oam this-Mt  ;; Time fitness measure
      set Eu-in-oam this-Eu  ;; Odum Efficiency measure 
      set Mj-in-oam this-Mj  ;; Joint fitness measure
    ]
    
    LOG-TO-FILE ( word "      Low-e: HOAM " ( this-lhhoam-index - 1 ) "; mass: " heavy-mass )
    set this-lhhoam-index ( this-lhhoam-index - 1 )
  ]
  
  ;; end of f-assign-low-e-to-new-chain
end 

;;-----------------------------------------------------------------------------|
;; Initialize the masses and efficiencies - high e.

to f-assign-high-e-to-new-chain [ to-this-chain ]
  ;; This routine is to be executed by the observer.

  ;; This does not alter the mass in the tail.
  ;; For high efficiencies, the heavy mass must be slightly larger. 
  let this-lhhoam-index ( g-length-of-chains - 1 )  ;; half open Atwood's Machine
  while [ this-lhhoam-index > 0 ] 
  [
    let this-lhhoam ( item this-lhhoam-index to-this-chain ) ;; target the lh-hoam.
    let next-rhhoam ( item ( this-lhhoam-index - 1 ) to-this-chain ) ;; target the rh-hoam.
    
    let light-mass ( item 0 [mass] of this-lhhoam )
    let heavy-mass ( light-mass / 0.90 )
    let this-Eu ( light-mass / heavy-mass )
    let mass-total ( heavy-mass + light-mass )
    let mass-diff  ( heavy-mass - light-mass )
    let this-Mt ( ( mass-diff / mass-total ) ^ ( 0.5 ) )
    let this-Mj ( this-Mt * this-Eu )
    
    ask next-rhhoam 
    [ 
      set mass heavy-mass
      set Mt-in-oam this-Mt  ;; Time fitness measure
      set Eu-in-oam this-Eu  ;; Odum Efficiency measure 
      set Mj-in-oam this-Mj  ;; Joint fitness measure
    ]
    
    LOG-TO-FILE ( word "      High-e: HOAM " ( this-lhhoam-index - 1 ) "; mass: " heavy-mass )
    set this-lhhoam-index ( this-lhhoam-index - 1 )
  ]

  ;; end of f-assign-high-e-to-new-chain
end 

;;-----------------------------------------------------------------------------|
;; Initialize the masses and efficiencies - mixed e.

to f-assign-mixed-e-to-new-chain [ to-this-chain ]
  ;; This routine is to be executed by the observer.

  ;; This does not alter the mass in the tail.
  ;; For variable efficiencies, the heavy mass must be variably larger. 
  let this-lhhoam-index ( g-length-of-chains - 1 )  ;; half open Atwood's Machine
  while [ this-lhhoam-index > 0 ] 
  [
    let this-lhhoam ( item this-lhhoam-index to-this-chain ) ;; target the lh-HOAM.
    let next-rhhoam ( item ( this-lhhoam-index - 1 ) to-this-chain ) ;; target the rh-HOAM.
    
    let random-efficiency ( ( random-float 1 ) * 0.8 ) ;; [ 0, 0.8 )
    set random-efficiency 0.10 + random-efficiency   ;; [ 0.10, 0.90 )
    
    let light-mass ( item 0 [mass] of this-lhhoam )
    let heavy-mass ( light-mass / random-efficiency )
    let this-Eu ( light-mass / heavy-mass )
    let mass-total ( heavy-mass + light-mass )
    let mass-diff  ( heavy-mass - light-mass )
    let this-Mt ( ( mass-diff / mass-total ) ^ ( 0.5 ) )
    let this-Mj ( this-Mt * this-Eu )
    
    ask next-rhhoam 
    [ 
      set mass heavy-mass
      set Mt-in-oam this-Mt  ;; Time fitness measure
      set Eu-in-oam this-Eu  ;; Odum Efficiency measure
      set Mj-in-oam this-Mj  ;; Joint fitness measure
    ]
    
    LOG-TO-FILE ( word "      Mixed-e: HOAM " ( this-lhhoam-index - 1 ) "; mass: " heavy-mass )
    set this-lhhoam-index ( this-lhhoam-index - 1 )
  ]

  ;; end of f-assign-mixed-e-to-new-chain
end 


;;-----------------------------------------------------------------------------|
;; Move the chain from where it was built to where you want it to appear.

to f-relocate-this-chain [ chain-to-relocate ]
  ;; This routine is to be executed by the observer.

  ;; Move this chain into place in the arena.
  ;; This moves the display into place, according to the index stored in the
  ;;   head, and does not affect its location in memory.
  let this-hoam-index 0
  while [ this-hoam-index < g-length-of-chains ]
  [
    let this-hoam ( item this-hoam-index gl-new-chain )
    ask this-hoam
    [
      set xcor ( max-pxcor - ( this-hoam-index + 1 ) )
      set ycor ( g-no-of-chains + 1 )
    ]
    set this-hoam-index ( this-hoam-index + 1 )
  ]
  LOG-TO-FILE ( word "  Relocated to: xcor: " 
    ( max-pxcor - 1 ) "; ycor: " ( g-no-of-chains + 1 ) )
  
  ;; End of f-relocate-this-chain [ chain-to-relocate ]
end 

;;-----------------------------------------------------------------------------|
;; Compute the energy changes, Odum Efficiency, and time to drop for this OAM.

to f-compute-energetics-of-chains
  ;; This routine is to be executed by the observer.

  let chain-index 0
  let this-chain gl-new-chain
  while [ chain-index < g-no-of-chains ]
  [
    set this-chain ( item chain-index gl-chains-lib )
    
    LOG-TO-FILE ( word "Computing Energetics: Chain " chain-index )
    f-compute-energetics-of-chain this-chain
  
    ;; And, prime the first OAM in the chain.
    ;; Each possible OAM in the chain was actually primed in the above
    ;;   call, from a programming point of view, but metaphorically, it
    ;;   is not primed until the previous OAM has discharged its energy.
    f-prime-oam 0 1 this-chain
    
    set chain-index ( chain-index + 1 )
  ]
  ;; End of f-compute-energetics-of-chains
end 

;;-----------------------------------------------------------------------------|
;; Compute the energy changes, Odum Efficiency, and time to drop for this OAM.

to f-compute-energetics-of-chain [ of-this-chain ]
  ;; This routine is to be executed by the observer.

  ;; Compute energetics for all OAMs in the chain.  An OAM is composed of
  ;;   an LH-HOAM linked to a RH-HOAM.  'Energetics' includes:
  ;;   - energy to be transferred from RH-HOAM to LH-HOAM
  ;;   - energy to be exhausted from RH-HOAM
  ;;   - oam-time-to-drop for RH-HOAM
  ;;   - accumulated time-to-discharge for RH-HOAM, across chain
  ;;   - three local measures associated with each RH-HOAM:
  ;;     - Mj - joint fitness measure for time and energy = Mt*Eu
  ;;     - Mt - fitness measure of time used = Td/Tb
  ;;     - Eu - Odum's efficiency measure of used energy = Ml/Mh
  ;;
  ;; These are rolled up to compute four indices for the chain as a whole:
  ;;   - Geometric average of the Mjs - the joint fitness measure
  ;;   - Geometric average of the Mts - the time fitness measure
  ;;   - Geometric average of the Eus - Odum Efficiency fitness measure
  ;;   
  
  ;; The masses (and efficiencies) were set in the 'f-asign- routine(s).
  ;; Time-to-discharge is tricky.  Often it is a non-integer, and so
  ;;   the next OAM is constituted and released at some time before
  ;;   the current tick started.  Each time-to-discharge needs to
  ;;   be computed from the initial release of OAM 0.
  let total-time-to-drop 0
  
  let this-head ( item 0 of-this-chain )
  let this-colour ( item 0 [default-colour] of this-head )
  let chain-index ( item 0 [index-into-chains-lib] of this-head )
  let sn-of-chain ( item 0 [chain-sn] of this-head )
  let this-pi-Mj 1
  let this-pi-Mt 1
  let this-pi-Eu 1
  
  let rhhoam-index 0
  ;; Only index for rh-hoams.  Leave out the tail.
  while [ rhhoam-index < ( g-length-of-chains - 1 ) ]
  [
    ;; Compute values within OAM (linking pairs of HOAMs).
    LOG-TO-FILE ( word "  Comp Energetics: Ch(" sn-of-chain "," 
      chain-index "); OAM " rhhoam-index )
    set total-time-to-drop 
      fr-compute-energetics-of-oam rhhoam-index total-time-to-drop of-this-chain
    
    ;; Access the RH-HOAM of this HOAM pair, this OAM.
    let this-hoam ( item rhhoam-index of-this-chain )
    ;; While here, I do a little non-relevant house-cleaning.
    ask this-hoam [ set color this-colour ]
    
    ;; Multiply the efficiencies, as basis for geometric average.
    set this-pi-Mj ( this-pi-Mj * ( item 0 [Mj-in-oam] of this-hoam ) )
    set this-pi-Mt ( this-pi-Mt * ( item 0 [Mt-in-oam] of this-hoam ) )
    set this-pi-Eu ( this-pi-Eu * ( item 0 [Eu-in-oam] of this-hoam ) )
    
    set rhhoam-index ( rhhoam-index + 1 )
  ]

  ;; Store the total time to drop in the head.
  ask this-head [ set chain-time-to-drop total-time-to-drop ]
  
  ;; Determine the correct root to use.
  let proper-root ( 1 / ( g-length-of-chains - 1 ) ) ;; 1 / (Number of OAMs).

  ;; Compute the geometric average of Mj across the chain of HOAMs.
  ;; This is based on Mj = Eu * Mt
  let this-geo-ave-Mj ( this-pi-Mj ^ proper-root )
  ask this-head 
  [ 
    set Mj-pi-this-chain this-pi-Mj 
    set Mj-geo-this-chain this-geo-ave-Mj 
  ]
  LOG-TO-FILE ( word "  CompEn: Joint Fitness Measure  (GeoAveMj) - Mj = " this-geo-ave-Mj )

  ;; Compute the geometric average of Mt across the chain of HOAMs.
  ;; This is based on ( constrained time to drop ) / ( unconstrained time to drop )
  let this-geo-ave-Mt ( this-pi-Mt ^ proper-root )
  ask this-head 
  [ 
    set Mt-pi-this-chain this-pi-Mt 
    set Mt-geo-this-chain this-geo-ave-Mt 
  ]
  LOG-TO-FILE ( word "  CompEn: Time Fitness Measure   (GeoAveMt) - Mt = " this-geo-ave-Mt )

  ;; Compute the geometric average of Eu across the chain of HOAMs.
  ;; This is based on Mu = Eu
  let this-geo-ave-Eu ( this-pi-Eu ^ proper-root )
  ask this-head 
  [ 
    set Eu-pi-this-chain this-pi-Eu 
    set Eu-geo-this-chain this-geo-ave-Eu 
  ]
  LOG-TO-FILE ( word "  CompEn: Energy Fitness Measure (GeoAveEu) - Eu = " this-geo-ave-Eu )

  ;; Assign the active fitness measure.
  if( g-fitness-number = 0 ) [ ask this-head [ set fitness-measure Mj-geo-this-chain ] ]
  if( g-fitness-number = 1 ) [ ask this-head [ set fitness-measure Mt-geo-this-chain ] ]
  if( g-fitness-number = 2 ) [ ask this-head [ set fitness-measure Eu-geo-this-chain ] ]
  
  let this-tail ( item ( g-length-of-chains - 1 ) of-this-chain )
  ask this-tail [ set color this-colour ]
  ;; End of f-compute-energetics-of-chain [ of-this-chain ]
end 

;;-----------------------------------------------------------------------------|
;; Compute the energy changes, Odum Efficiency, and time to drop for this OAM.

to-report fr-compute-energetics-of-oam [ rh-hoam-index ttl-time-to-drop in-this-chain ]
  ;; This routine is to be executed by the observer.

  let lh-hoam-index ( rh-hoam-index + 1 )
  
  let rh-hoam ( item rh-hoam-index in-this-chain )
  let lh-hoam ( item lh-hoam-index in-this-chain )
  
  let mass-heavy item 0 ( [mass] of rh-hoam )
  let mass-light item 0 ( [mass] of lh-hoam )
  let mass-total ( mass-heavy + mass-light )
  let mass-diff  ( mass-heavy - mass-light )

  let this-Eu ( mass-light / mass-heavy )
  let this-Mt ( ( mass-diff / mass-total ) ^ 0.5 )
  let this-Mj ( this-Mt * this-Eu )
  
  let numerator ( 2 * g-drop-distance * mass-total )
  let denominator ( g-acceleration * mass-diff )
  
  let time-to-fall ( ( numerator / denominator ) ^ 0.5 )
  set ttl-time-to-drop ( ttl-time-to-drop + time-to-fall )

  let energy-total   ( g-drop-distance * g-acceleration * mass-heavy )
  let energy-kinetic ( g-drop-distance * g-acceleration * mass-diff )
  let energy-xferred ( energy-total - energy-kinetic )
  
  ask rh-hoam
  [
    set oam-time-to-drop time-to-fall
    set age-to-discharge ttl-time-to-drop
    set Mt-in-oam this-Mt
    set Eu-in-oam this-Eu
    set Mj-in-oam this-Mj
    set energy-to-transfer energy-xferred
    set energy-to-discharge energy-kinetic
  ]
  
  LOG-TO-FILE ( word "  CompEn: oam-time-to-drop    - " time-to-fall )
  LOG-TO-FILE ( word "  CompEn: age-to-discharge    - " ttl-time-to-drop )
  LOG-TO-FILE ( word "  CompEn: Mj-in-oam           - " this-Mj )
  LOG-TO-FILE ( word "  CompEn: Mt-in-oam           - " this-Mt )
  LOG-TO-FILE ( word "  CompEn: Eu-in-oam           - " this-Eu )
  LOG-TO-FILE ( word "  CompEn: energy-to-transfer  - " energy-xferred )
  LOG-TO-FILE ( word "  CompEn: energy-to-discharge - " energy-kinetic )

  report ttl-time-to-drop
  ;; End of fr-compute-energetics-of-oam
end 

;;-----------------------------------------------------------------------------|
;; Indicate which OAM in the HOAM chain is primed.

to f-prime-oam [ rh-hoam-index lh-hoam-index in-this-chain ]
  ;; This routine is to be executed by the observer.

  ASSERT( rh-hoam-index < lh-hoam-index ) ( word "Set: rh-hoam-index = " rh-hoam-index " " ) -1
  ASSERT( lh-hoam-index < ( g-length-of-chains ) ) ( word "Set: rh-hoam-index = " rh-hoam-index " " ) -1
  
  let this-head ( item 0 in-this-chain )
  let this-colour 45 ;; a dummy declaration.
  ask this-head
  [
    ;; Unpack indices.
    let old-rh-hoam-index primed-rh-hoam-index
    let old-lh-hoam-index primed-lh-hoam-index
    set this-colour default-colour
    
    ;; Change colour.
    let this-hoam ( item old-rh-hoam-index in-this-chain )
    ask this-hoam [ set color this-colour ]
    
    ;; Change colour.
    set this-hoam ( item old-lh-hoam-index in-this-chain )
    ask this-hoam [ set color this-colour ]
    
    ;; Change colour.
    set this-hoam ( item rh-hoam-index in-this-chain )
    ask this-hoam [ set color g-primed-colour ]
    
    ;; Change colour.
    set this-hoam ( item lh-hoam-index in-this-chain )
    ask this-hoam [ set color g-primed-colour ]
    
    set primed-rh-hoam-index rh-hoam-index
    set primed-lh-hoam-index lh-hoam-index
  ]
  
  ;; End of f-prime-oam [ rh-hoam-index lh-hoam-index in-this-chain ]
end 

;;-----------------------------------------------------------------------------|
;; Reset the default values for the interface-declared items.

to f-reset-default-parameters 
  ;; The observer executes this routine.

  ;; Switches, sliders and choosers implicitly declare global variables.  The
  ;;   values in these variables are parameters for the model, and many 
  ;;   combinations of those parameters are not sustainable.  However, the
  ;;   values in those user interface devices are stored with the model and
  ;;   are persistant across a save/load action.  The default values must
  ;;   be reset on load, or available to a user as a parameter set.  The
  ;;   purpose of this routine is to store at least one viable set of 
  ;;   parameter values.
  
  ;; Parameters needed for "Setup" routine.
  ;; Initialize the fitness test chooser.
  set gs-fitness-measure "Mj - Joint"
  ;; The chooser that selects between the three scenarios is allowed to be 
  ;;   persistant.  It is not reset here.  This gives the user the ability
  ;;   to choose the scenario for which the defaults are to be restored.
  ;; Initialize the Pseudo Random Number Generator (PRNG).
  set g-use-this-seed 7

  ;; Operational controls, can be changed during a run.
  set gb-plots-on true
  set gb-mutate-heads true
  set gb-mutate-tails true
  set gb-horse-race-on true
   
  ;;-----------------------------------------------
  ;; BIOPHYSICAL SUB-SYSTEM CONTROLS AND PARAMETERS
  ;;-----------------------------------------------

  ;; Structural controls needed for "Setup"
  ;; Slider range settings are shown as (Min,Increment,Max)
  set g-no-of-chains-at-start 30 ;; (  1, 15,   100 ) Chains
  set g-no-of-chains-max 30      
  set g-length-of-chains 14      ;; (  3,  1,    14 ) HOAMs
  set g-drop-distance 100        ;; ( 50,  5,   200 ) meters
  set g-acceleration 10          ;; (  8,  0.10, 12 ) m/s/s
  
  ;; End of f-reset-default-parameters
end 

;;-----------------------------------------------------------------------------|
;; SECTION D – GO OR MAIN-LOOP PROCEDURE( S )
;;-----------------------------------------------------------------------------|

;;-----------------------------------------------------------------------------|
;; The go button

to go
  ;; This routine is to be executed by the observer.

  ;; Stop codes:
  ;; All stop decisions must be here in the 'go' procedure, as it causes an
  ;;   exit from the current procdure only.

  if( g-halt-at-tick = ticks  ) 
  [
    set g-halt-at-tick -1
    stop
  ]
  
  let b-should-stop-now false
  if( count turtles <= 0 ) [ set b-should-stop-now true ]
  if( b-should-stop-now = true )
  [
    f-close-dpx-file
    f-close-dpt-file
    ;; The Debug log file is handled differently elsewhere.
    stop
  ]

  ;; MANUAL CHANGE FOR DEBUG
  ;; If needed, each check for validity can be enabled between steps.
  ;; They have been suppressed (turned into comments) for the sake 
  ;;   of speed of execution, but can be re-enabled if a bug has 
  ;;   somehow been re-introduced.
  ;; A single call to the validity check has been left active inside of the
  ;;   Do-Post-Tick step.  If it flags a problem, re-activate these to
  ;;   narrow down where the problem starts.
  
  ;; Major steps or functions, done once per tick, in order of execution.
  do-pre-tick
  ;; if( frb-agents-are-all-valid = false ) [ LOG-TO-FILE ( word "Agents failed validity test: Do-pre." ) ]

  do-check-chains
  ;; if( frb-agents-are-all-valid = false ) [ LOG-TO-FILE ( word "Agents failed validity test: Do-chk." ) ]

  do-post-tick
  ;; if( frb-agents-are-all-valid = false ) [ LOG-TO-FILE ( word "Agents failed validity test: Do-pos." ) ]

  ;; End of to go
end 

;;-----------------------------------------------------------------------------|
;; D1 - do-pre-tick procedure( s )
;;-----------------------------------------------------------------------------|

to do-pre-tick
  ;; This routine is to be executed by the observer.
  
  if( gb-debug-on = 1 )
  [
    ifelse( ( gs-debug-step-chooser = "all" ) or ( gs-debug-step-chooser = "pre-tick" ) )
    [ set gb-debug-flow-on 1 LOG-TO-FILE "" LOG-TO-FILE word "Do-Pre-tick: Debug on.; tick = " ticks ]
    [ set gb-debug-flow-on 0 ]
  ]
  
  ;; Enter all commands that need to be done before a tick begins.
  ;; Supressed. f-update-aggregates
  
  ;; Advance the tick counter by 1 tick.
  ifelse( gb-plots-on = true )
  [
    ;; Advance the ticks by one and update the plots.
    tick
    ;; 'tick' is exactly the same as 'update-plots' except that the tick counter 
    ;;   is incremented before the plot commands are executed.
    
  ]
  ;; else
  [
    ;; Advance ticks by one but do not update the plots.
    tick-advance 1
  ]

  ;; Check to see if dpx file is full.
  if( gb-dpx-on = 1 )
  [
    if( g-dpx-recno > g-recno-max )
    [
      f-reopen-dpx-file
    ]
  ]
  
  ;; Ensure that the derived parameters are properly valued.
  ;; THESE ARE PLACED HERE TO MAKE BEHAVIOUR SPACE (BS) WORKS CORRECTLY.
  ;; BS ADJUSTS THE SLIDERS, BUT THESE ARE DERIVED THEREFROM. 
  ;; Nil changes required.

  ask heads [ set age-of-chain ( age-of-chain + 1 ) ]
  
  ;; Plot "Usage Rates Per Tick"
  ;; Zero the per tick throughput measures.
  set gl-ttl-hg-nrg-per-tick  ( n-values g-length-of-chains [0.0] )
  set gl-ttl-lg-nrg-per-tick  ( n-values g-length-of-chains [0.0] )

  LOG-TO-FILE ( word "Do-pre: Halt at tick - " g-halt-at-tick "; current ticks - " ticks ) 

  LOG-TO-FILE "Do-pre: routine completed."
  ;; End of to do-pre-tick
end 

;;-----------------------------------------------------------------------------|
;; D2 – check-chains procedure(s)
;;-----------------------------------------------------------------------------|

to do-check-chains
  ;; This routine is to be executed by the observer.
  
  if( gb-debug-on = 1 )
  [
    ifelse( ( gs-debug-step-chooser = "all" ) or ( gs-debug-step-chooser = "check-chains" ) )
    [ set gb-debug-flow-on 1 LOG-TO-FILE "" LOG-TO-FILE word "Do-check-chains: Debug on; tick = " ticks ]
    [ set gb-debug-flow-on 0 ]
  ]
  
  ifelse (gb-horse-race-on = true )
  [
    ;; This is 'horse race' mode.  I thought it would help the visualization
    ;;   of the model if I could 'see' the OAMs form and drop, so I coloured the
    ;;   active OAMs yellow.  It gives the effect of horses racing for the 
    ;;   finish line, and it is relatively dramatic.  A chain replicates when it
    ;;   has finished its drop, so drop time affects how often a chain can 
    ;;   replicate, even when the 'time fitness measure' is not being used.  I am
    ;;   concerned that this distorts the results.  So, I have left this 
    ;;   original version of the horse race as an option.  It is cute.  But, for
    ;;   more serious study of the MPP one should toggle the horse race mode
    ;;   off.
    
    ;; Initialize the list of chains, for this pass of the 'do-check-chains' routine.
    set gl-chains-indices ( [index-into-chains-lib] of heads )
    
    let chains-index fr-get-random-chains-index
    while [ chains-index != -1 ]
    [
      let this-chain ( item chains-index gl-chains-lib )
      let this-chain-sn ( item 0 [chain-sn] of ( item 0 this-chain ) )
      LOG-TO-FILE ( word "Chk Chain (S/N, index): Ch(" this-chain-sn "," chains-index ") " )
      f-check-one-chain-hrmode-on this-chain
      
      set chains-index fr-get-random-chains-index
    ]
  ]
  ;; Else
  [
    ;; This is the mode of operation when 'horse race mode' is turned off.
    
    ;; Initialize the list of chains, for this pass of the 'do-check-chains' 
    ;;   routine.
    ;; Re-initialize the global list again as an empty list.
    set gl-chains-indices []
    ;; Create a temporary list of heads sorted in descending order of fitness.
    let temp-list ( sort-on [(- fitness-measure)] heads )
    foreach temp-list 
    [ 
      ;; Add each index to the list, in descending order of fitness.
      ask ? 
      [ 
        set gl-chains-indices ( lput index-into-chains-lib gl-chains-indices )
        ;; show ( word "who: " who ", fitness: " fitness-measure ", index: " 
        ;;   index-into-chains-lib ) 
      ] 
    ]
     
    let chains-index fr-get-fit-chains-index
    while [ chains-index != -1 ]
    [
      let this-chain ( item chains-index gl-chains-lib )
      let this-chain-sn ( item 0 [chain-sn] of ( item 0 this-chain ) )
      LOG-TO-FILE ( word "Chk Chain (S/N, index): Ch(" this-chain-sn "," chains-index ") " )
      f-check-one-chain-hrmode-off this-chain
      
      set chains-index fr-get-fit-chains-index
    ]
  ]
  ;; End else
  
  ;; Supressed. f-update-aggregates

  LOG-TO-FILE "Do-Chk: procedure completed"
  
  ;; End of to do-check-chains
end 

;;-----------------------------------------------------------------------------|
;; The observer pulls a random index.

to-report fr-get-random-chains-index
  ;; The observer executes this routine.
  
  let next-index -1
  if( not ( empty? gl-chains-indices ) )
  [
    ;; Move a random index to the front of the list of indices.
    set gl-chains-indices ( shuffle gl-chains-indices )
    ;; Select that index to report back.
    set next-index ( item 0 gl-chains-indices )
    ;; Delete that index from the list.
    set gl-chains-indices ( but-first gl-chains-indices )
  ]
  
  ;; Report a valid as-yet-unused index, or -1 for an empty list.
  report next-index
  ;; End of to fr-get-next-chains-index
end 

;;-----------------------------------------------------------------------------|
;; the observer checks a chain to see if it needs to be updated

to f-check-one-chain-hrmode-on [ chain-to-check ]
  ;; The observer executes this routine.
  
  ;; This is the heart of the model.
  ;;   - If the primed OAM is not ready to discharge - do nothing.
  ;;   - Else, discharge and
  ;;   --- If this is not the last OAM, prime the next OAM.
  ;;   --- Else, replicate this chain, mutate and prime the offspring.
  
  ;; Retrieve the primed OAM (Open Atwood's Machine) indices.
  let this-head ( item 0 chain-to-check )
  let age-of-this-chain ( item 0 [age-of-chain] of this-head )
  LOG-TO-FILE ( word "  Age of chain: " age-of-this-chain )

  let rh-hoam-index ( item 0 [primed-rh-hoam-index] of this-head )
  let lh-hoam-index ( item 0 [primed-lh-hoam-index] of this-head )
  LOG-TO-FILE ( word "  OAM " rh-hoam-index )
  
  ;; Access the rh-hoam
  let rh-hoam ( item rh-hoam-index chain-to-check )
  
  ;; Determine if sufficient time has passed to exhaust waste heat.
  let discharge-age ( item 0 [age-to-discharge] of rh-hoam )

  LOG-TO-FILE ( word "  Discharge age: " discharge-age )
  if ( age-of-this-chain >= discharge-age )
  [
    LOG-TO-FILE ( word "  OAM " rh-hoam-index " discharging" )
    ;; The rh-hoam has smacked down on the floor.
    ;; Access the other half of the oam, the lh-hoam.
    let lh-hoam ( item lh-hoam-index chain-to-check )
    
    ;; Exhaust waste heat.
    let nrg-exhausted ( item 0 [energy-to-discharge] of rh-hoam )
    let ttl-lg-nrg ( item rh-hoam-index gl-ttl-lg-nrg-per-tick ) 
    set ttl-lg-nrg 
      ( ttl-lg-nrg + nrg-exhausted )
    set gl-ttl-lg-nrg-per-tick 
      ( replace-item lh-hoam-index gl-ttl-lg-nrg-per-tick ttl-lg-nrg )
    LOG-TO-FILE ( word "    Nrg exhausted: " nrg-exhausted )
  
    ;; Transfer of hg-nrg per tick is handled in f-update-aggregates.
    
    ;; The energy does not have to actually be transferred, as the amount is
    ;;   determined by the structure of the OAM for each OAM.  I.e. it is a
    ;;   pre-determined amount, and can be calculated within the OAM when it
    ;;   is primed, based on the size of the masses.  All masses are raised
    ;;   by the same g-drop-distance when the OAM is primed.
    ;; But I log it here.  It's a virtual transfer.
    let nrg-xferred ( item 0 [energy-to-transfer] of rh-hoam )
    LOG-TO-FILE ( word "    Nrg transferred: " nrg-xferred )
    
    ;; Check if this OAM is the last of the chain.
    ifelse ( lh-hoam-index = ( g-length-of-chains - 1 ) )
    [
      ;; It is the last OAM. Exhaust the remaining energy, de-activate the OAM,
      ;;   de-activate the chain, and replicate with variation.
      
      ;; Exhaust transferred energy as waste heat.
      ;; Data is stored in the aggregate list using the lh-hoam-index.
      set ttl-lg-nrg ( item lh-hoam-index gl-ttl-lg-nrg-per-tick ) 
      set ttl-lg-nrg ( ttl-lg-nrg + nrg-xferred ) ;; xferred nrg here exhausted.
      set gl-ttl-lg-nrg-per-tick
        ( replace-item lh-hoam-index gl-ttl-lg-nrg-per-tick ttl-lg-nrg )
      LOG-TO-FILE ( word "    Nrg exhausted by tail: " nrg-xferred )
      
      ;; Deactivate this OAM. This is done simply by changing the access 
      ;;   indices in the head back to defaults.  It is unnecessary, however, since
      ;;   the chain is being deactivated, mutated, and re-primed with 
      ;;   the head primed.
      ask this-head 
      [ 
        set rh-hoam-index 0
        set lh-hoam-index 1
      ]
      
      ;; The chain has completed processing of all energy received by the head.
      ;; The next call will (a) if possible, cause this chain to replicate, and
      ;;   (b) alter a random mass somewhere other than in the tail, for each
      ;;   of the two offspring chains.
      LOG-TO-FILE ( word "  Rep: Replication of chain ensues." )
      f-replicate-this-chain chain-to-check
     ]
    ;; else
    [
     ;; Prime the next OAM.
      LOG-TO-FILE ( word "    Priming OAM " lh-hoam-index )
      f-prime-oam ( rh-hoam-index + 1 ) ( lh-hoam-index + 1 ) chain-to-check
    ]
  ]
  ;; Else, primed OAM is not ready to discharge, do nothing.

  ;; End of f-check-one-chain-hrmode-on [ chain-to-check ]
end 

;;-----------------------------------------------------------------------------|
;; The observer pulls the next most fit index.

to-report fr-get-fit-chains-index
  ;; The observer executes this routine.

  let next-index -1
  if( not ( empty? gl-chains-indices ) )
  [
    ;; Indices are in order of descending fitness of chains.
    ;; Select the most fit index to report back.
    set next-index ( item 0 gl-chains-indices )
    ;; Delete that index from the list.
    set gl-chains-indices ( but-first gl-chains-indices )
  ]

  ;; Report a valid as-yet-unused index, or -1 for an empty list.
  report next-index
  ;; End of fr-get-fit-chains-index
end 

;;-----------------------------------------------------------------------------|
;; the observer checks a chain to see if it needs to be updated

to f-check-one-chain-hrmode-off [ chain-to-check ]
  ;; The observer executes this routine.
  
  ;; This is the heart of the 'no horse race' mode of the model.
  ;; Each chain is replicated in order from most fit downwards.
  ;;   As each fit chain is replicated, the least fit is replaced from the 
  ;;   bottom up.
  
  ;; In this mode, it does not matter which OAM in the chain is primed.  The
  ;;   decision as to when a chain replicates is not a horse race.  The decision 
  ;;   about fitness is entirely determined by examination of the energetics
  ;;   of the chain.  In every tick, all chains either replicate or are
  ;;   replaced.  This is purely a breeding program and 'natural selection' does
  ;;   not happen here.
  
  ;; Log the relevant data.
  let this-head ( item 0 chain-to-check )
  let this-chain-index ( item 0 [index-into-chains-lib] of this-head )
  let sn-of-this-chain ( item 0 [chain-sn] of this-head )
  LOG-TO-FILE ( word "  Checking: Ch(" sn-of-this-chain "," this-chain-index ")" )
  let fm-of-this-chain ( item 0 [fitness-measure] of this-head )
  LOG-TO-FILE ( word "    Fitness: " ( precision fm-of-this-chain 6 ) )
  let Mj-of-this-chain ( item 0 [Mj-geo-this-chain] of this-head )
  let Mt-of-this-chain ( item 0 [Mt-geo-this-chain] of this-head )
  let Eu-of-this-chain ( item 0 [Eu-geo-this-chain] of this-head )
  let Dt-of-this-chain ( item 0 [chain-time-to-drop] of this-head )
  LOG-TO-FILE ( word "    Mj: " ( precision Mj-of-this-chain 6 ) )
  LOG-TO-FILE ( word "    Mt: " ( precision Mt-of-this-chain 6 ) )
  LOG-TO-FILE ( word "    Mu: " ( precision Eu-of-this-chain 6 ) )
  LOG-TO-FILE ( word "    Dt: " ( precision Dt-of-this-chain 6 ) )

  ;; Exhaust waste heat.  Exclude the tail data.
  ;; TODO: Note, in this mode the final energy passed to the tail is not
  ;;   included in the discharge statistic.
  let tail-excluded ( but-last chain-to-check )
  let nrg-exhausted 0
  let nrg-transferred 0
  foreach tail-excluded
  [
    ask ?
    [
      let rh-hoam-index ( item 0 [index-into-chain] of ? )
      let lh-hoam-index ( rh-hoam-index + 1 )

      set nrg-exhausted ( item 0 [energy-to-discharge] of ? )
      let ttl-lg-nrg ( item rh-hoam-index gl-ttl-lg-nrg-per-tick ) 
      set ttl-lg-nrg 
        ( ttl-lg-nrg + nrg-exhausted )
      set gl-ttl-lg-nrg-per-tick 
        ( replace-item lh-hoam-index gl-ttl-lg-nrg-per-tick ttl-lg-nrg )

      set nrg-transferred ( item 0 [energy-to-transfer] of ? )
      let ttl-hg-nrg ( item rh-hoam-index gl-ttl-hg-nrg-per-tick ) 
      set ttl-hg-nrg 
        ( ttl-hg-nrg + nrg-transferred )
      set gl-ttl-hg-nrg-per-tick 
        ( replace-item lh-hoam-index gl-ttl-hg-nrg-per-tick ttl-hg-nrg )
    ]
  ]
  LOG-TO-FILE ( word "    Nrg exhausted: " nrg-exhausted )
  LOG-TO-FILE ( word "    Nrg transferred: " nrg-transferred )
  LOG-TO-FILE ( word "  Rep: Replication of chain ensues." )

  f-replicate-this-chain chain-to-check

  ;; End of f-check-one-chain-hrmode-on [ chain-to-check ]
end 

;;-----------------------------------------------------------------------------|
;; the observer checks a chain to see if it needs to be updated

to f-replicate-this-chain [ chain-to-replicate ]
  ;; The observer executes this routine.

  ;; This is the soul of the model
  ;; The list 'chain-to-replicate' is located somewhere in the super-list 
  ;;   'gl-chains-lib'.  If there is room for another, simply replicate by 
  ;;   sprouting a new chain of turtles in gl-new-chain, copying the data into 
  ;;   that new set of turtles, and then moving the turtles into the 
  ;;   gl-chains-lib library of chains.
  ;;   If there is no room for another chain, then the worst chain that has
  ;;   not yet discharged is terminated, and the offspring replaces it.  In that
  ;;   case, no new turtles are sprouted.
  ;; The chains are competing for the scarce resource of 'place on the list'.
  ;; That sounds silly, but, the parameter 'g-no-of-chains-max' is effectively
  ;;   the carrying capacity of this system, and it is a hard limit.  Those
  ;;   that process most quickly will stay on the list.  Those that process
  ;;   the most slowly will be removed, and replaced.
  ;;
  ;; Time to process is determined by low efficiency.  The least efficient
  ;;   transform their energy to kinetic energy and drop quickly, and 
  ;;   exhaust it as waste heat.  So, won't the average efficiency drop?
  ;;   As  drops, the load (energy delivered to the tail) drops.
  ;; The tail is of fixed mass.  The ultimate load is fixed.  So, the winner
  ;;   is the chain that can deliver that fixed load the most quickly.
  
  ;; Unpack the parent chain's serial number.
  let sn-of-ma ( item 0 [chain-sn] of ( item 0 chain-to-replicate ) )
  ;; Unpack the parent chain's index number.
  let index-of-ma ( item 0 [index-into-chains-lib] of ( item 0 chain-to-replicate ) )
  let index-of-da1 index-of-ma  ;; Index of first daughter, replaces mother.
  let index-of-da2 -1           ;; Index of second daughter.
  
  ;; Duplicate the target chain, by sprouting a new one, or copying over an old.
  let daughter-chain []
  ifelse ( g-no-of-chains < g-no-of-chains-max )
  [
    ;; There is room in the library of chains for another chain, which means
    ;;   there is a need for the creation of a new set of turtles.
    f-build-initialized-chain
    ;; This populates gl-new-chain with turtles, somewhat unnecessarily 
    ;;   initializes each, and transfers the whole chain into the gl-chains-lib, 
    ;;   and then, adjusts efficiencies to match the scenario.  This is all for
    ;;   the new turtles.  This is wasted computing, but the waste only goes on
    ;;   until gl-chains-lib is full.  So I have not tried to make it more
    ;;   efficient in processing time.  It does not compute energetics, 
    ;;   as that is handled below.
    
    ;; Clear construction area.
    set gl-new-chain []
    
    ;; Establish a handling name for the daughter chain within the library.
    ;; No new turtles are created, they are just listed in this list.
    set daughter-chain ( item ( g-no-of-chains - 1 ) gl-chains-lib )
    set index-of-da2 ( g-no-of-chains - 1 )

    ;; Copy everything except colour and location into the daughter chain.
    ;; This over-writes all of the data established during initialization.
    f-copy-chain-to-chain chain-to-replicate daughter-chain
    
    ;; There are now two almost identical copies in the library.
    ;; Give each a unique serial number, used for CSV output and analysis.
    ;; Ensure this-chain is ready to go.
    let daughter1-head ( item 0 chain-to-replicate )
    ask daughter1-head
    [
      set age-of-chain 0
    ]
    
    ;; Ensure daughter-chain is ready to go.
    let daughter2-head ( item 0 daughter-chain )
    ask daughter2-head
    [
      set index-into-chains-lib ( g-no-of-chains - 1 )
      set age-of-chain 0
    ]
  ]
  ;; else
  [
    ;; There is no room.  Find worst chain and replace it.
    
    let head-to-replicate ( item 0 chain-to-replicate )
    ;; Daughter2 cannot replace this chain.  Daughter1 replaces it.
    let index-to-exclude 
      ( item 0 [index-into-chains-lib] of head-to-replicate )
    ;; Find a suitable other chain to replace.
    let index-of-worst-chain
      fr-get-index-of-worst-chain index-to-exclude 
    
    ;; Write a 'data per x-action' record, if appropriate.
    WRITE-DPX-D-RECORD index-of-worst-chain "Discard"

    ;; Target the worst chain for replacement.
    set daughter-chain ( item index-of-worst-chain gl-chains-lib ) 
    let sn-of-chain ( item 0 [chain-sn] of item 0 daughter-chain )
    LOG-TO-FILE ( word "    Replacing Ch(" sn-of-chain "," index-of-worst-chain 
      ") with daughter chain" )

    ;; Replace the worst.  Copy everything except colour and location.
    f-copy-chain-to-chain chain-to-replicate daughter-chain
    set index-of-da2 index-of-worst-chain
    
    ;; There are now two almost identical copies in the library.
    ;; Give each a unique serial number, used for CSV output and analysis.
    ;; Ensure this-chain is ready to go.
    let daughter1-head ( item 0 chain-to-replicate )
    ask daughter1-head
    [
      set age-of-chain 0
    ]
    
    ;; Ensure daughter-chain is ready to go.
    let daughter2-head ( item 0 daughter-chain )
    ask daughter2-head
    [
      set index-into-chains-lib index-of-worst-chain
      ;; Correct the faulty age.
      set age-of-chain 0
    ]
  ]
  ;; End else
  
  ;; At this point both chain-to-replicate and daughter-chain exist and
  ;;   are in the library and are located in the arena.  They are identical
  ;;   except for colour, location, and serial numbers.
  
  ;; Write a 'data per x-action' record, if appropriate.
  WRITE-DPX-D-RECORD index-of-ma "Fission"
  
  ;; Update the serial numbers.
  let daughter1-head ( item 0 chain-to-replicate )
  ask daughter1-head
  [
    set chain-sn g-next-chain-sn
    set g-next-chain-sn ( g-next-chain-sn + 1 )
    set mas-sn sn-of-ma
  ]
  let daughter2-head ( item 0 daughter-chain )
  ask daughter2-head
  [
    set chain-sn g-next-chain-sn
    set g-next-chain-sn ( g-next-chain-sn + 1 )
    set mas-sn sn-of-ma
  ]
    
  let d1-sn ( item 0 [chain-sn] of daughter1-head )
  let d2-sn ( item 0 [chain-sn] of daughter2-head )
  let d1-in ( item 0 [index-into-chains-lib] of daughter1-head )
  let d2-in ( item 0 [index-into-chains-lib] of daughter2-head )
  LOG-TO-FILE ( word "    D1 chain is Ch(" d1-sn "," d1-in ")" )
  LOG-TO-FILE ( word "    D2 chain is Ch(" d2-sn "," d2-in ")" )

  ;; Mutate each chain.
  f-mutate-this-chain chain-to-replicate
  WRITE-DPX-D-RECORD index-of-da1 "Birth"
  f-mutate-this-chain daughter-chain
  WRITE-DPX-D-RECORD index-of-da2 "Birth"
  ;; While mutating, the energetics were re-computed and the 
  ;;   first OAM primed.

  ;; End of f-replicate-this-chain [ chain-to-replicate ]
end 

;;-----------------------------------------------------------------------------|
;; Get the fitness measure of this chain.

to-report fr-get-fitness-measure-of-chain [ of-this-chain ]
  ;; The observer executes this routine.
  
  let this-head ( item 0 of-this-chain )
  let active-fitness-measure 1
  
  if( g-fitness-number = g-fitness-joint )
    [ set active-fitness-measure ( item 0 [Mj-geo-this-chain] of this-head ) ]
  if( g-fitness-number = g-fitness-time )
    [ set active-fitness-measure ( item 0 [Mt-geo-this-chain] of this-head ) ]
  if( g-fitness-number = g-fitness-energy )
    [ set active-fitness-measure ( item 0 [Eu-geo-this-chain] of this-head ) ]
  
  report active-fitness-measure
  
  ;; End of fr-get-fitness-measure-of-chain
end 

;;-----------------------------------------------------------------------------|
;; Get the fitness measure of this head.

to-report fr-get-fitness-measure-of-head [ this-head ]
  ;; The observer executes this routine.
  
  let active-fitness-measure 1
  
  if( g-fitness-number = g-fitness-joint )
    [ set active-fitness-measure ( item 0 [Mj-geo-this-chain] of this-head ) ]
  if( g-fitness-number = g-fitness-time )
    [ set active-fitness-measure ( item 0 [Mt-geo-this-chain] of this-head ) ]
  if( g-fitness-number = g-fitness-energy )
    [ set active-fitness-measure ( item 0 [Eu-geo-this-chain] of this-head ) ]
  
  report active-fitness-measure
  
  ;; End of fr-get-fitness-measure-of-head
end 

;;-----------------------------------------------------------------------------|
;; Get the index of the worst chain in the library.

to-report fr-get-index-of-worst-chain [ excluded-index ]
  ;; The observer executes this routine.
  
  ;; This routine is used to find the worst chain in the library of chains,
  ;;   for the purpose of replicating the discharging chain into it.  The
  ;;   discharging chain, of course, should not be copied over itself, and
  ;;   so, its index is excluded from the search.
    
  ;; First, create an agentset of heads that exclude the appropriate head.
  let heads-to-include ( heads with [ not ( index-into-chains-lib = excluded-index ) ]  )
  ;; Then, exclude those with lower fitness measure.
  ;; set heads-to-include ( heads-to-include with [ fitness-measure <= min-fitness ] )
    
  ;; There are three difference fitness criteria:
  ;; - Mj - A joint criteria that finds a compromise.
  ;; - Mt - Minimize time to drop;
  ;; - Eu - Maximize useful energy passed on to next OAM;
  let list-of-worst [ -1 ]
  ifelse ( g-fitness-number = g-fitness-joint )
  [
    ;; Joint fitness measure invoked.
    set list-of-worst 
    ( [index-into-chains-lib] of 
      ( heads-to-include with-min [Mj-geo-this-chain] ) )
  ]
  ;; else - not joint
  [
    ifelse ( g-fitness-number = g-fitness-time )
    [
      ;; Time fitness measure invoked.
      set list-of-worst 
      ( [index-into-chains-lib] of 
        ( heads-to-include with-min [Mt-geo-this-chain] ) )
    ]
    ;; else - not time
    [
      ;; Energy fitness measure invoked.
      set list-of-worst 
      ( [index-into-chains-lib] of 
        ( heads-to-include with-min [Eu-geo-this-chain] ) )
    ]
    ;; End else
  ]
  ;; End else
  
  ;; We now have a list of indices of chains, any of which would be suitable.
  ;; Randomly order the list.
  set list-of-worst ( shuffle list-of-worst )
  
  ;; Choose one.
  let index-of-worst 0
  ifelse( empty? list-of-worst ) 
  [ set index-of-worst excluded-index ]
  [ set index-of-worst ( item 0 list-of-worst ) ]  
    
  ;; There is one thing left to do.  Since the 'worst' will be over-written
  ;;   with a fresh newly mutated chain of age zero, it should be removed from
  ;;   the list of chains checked in this turn.  If this is not done, those
  ;;   newly minted chains that replace an already-been-checked chain will
  ;;   have a disadvantage, having one less tick to perform in the race.  This
  ;;   may cause fluctuations that amount to noise.
    
  ;; Check if this index is in the list of as-yet unchecked chains.
  if ( member? index-of-worst gl-chains-indices )
  [
    let position-to-exclude ( position index-of-worst gl-chains-indices )
    set gl-chains-indices ( remove-item position-to-exclude gl-chains-indices )
  ]
    
  report index-of-worst
  
  ;; End of fr-get-index-of-worst-chain
end 

;;-----------------------------------------------------------------------------|
;; Copy from one chain to the other, contents of one turtle at a time.

to f-copy-chain-to-chain [ from-chain to-chain ]
  ;; The observer executes this routine.
  
  ;; Both chains must exist prior to copy action.  This copies the important
  ;;   content that is specific to OamLab.
  ;; This is the primary routine for enabling a 'fission' of the chain when a 
  ;;   chain is allowed to reproduce.  
  
  let hoam-index 0
  while [ hoam-index < g-length-Of-chains ]
  [
    let from-hoam ( item hoam-index from-chain )
    let to-hoam   ( item hoam-index to-chain )
    
    ifelse ( hoam-index = 0 ) [ f-copy-head-to-head from-hoam to-hoam ]
    [
      ifelse ( hoam-index < ( g-length-of-chains - 1 ) ) 
        [ f-copy-body-to-body from-hoam to-hoam ]
        [ f-copy-tail-to-tail from-hoam to-hoam ]
    ]
    set hoam-index ( hoam-index + 1 )
  ]
  
  ;; End of f-copy-chain-to-chain [ from-chain to-chain ]
end 

;;-----------------------------------------------------------------------------|
;; Copy contents from one head to another.

to f-copy-head-to-head [ from-head to-head ]
  ;; The observer executes this routine.
  
  ;; Both heads must have different who numbers.
  let from-who ( item 0 [who] of from-head )
  let to-who   ( item 0 [who] of to-head )
  ASSERT ( from-who != to-who ) 
    ( word "Copy error: who " from-who " = " to-who ) from-who
  
  ;; I don't know of an easy way to do this.  It looks messy.
  
  ;; Associated with chain.
  ask to-head [ set mas-sn 
    ( item 0 [mas-sn] of from-head ) ]
  ask to-head [ set chain-sn 
    ( item 0 [chain-sn] of from-head ) ]
  ask to-head [ set index-into-chains-lib 
    ( item 0 [index-into-chains-lib] of from-head ) ]
  ask to-head [ set age-of-chain 
    ( item 0 [age-of-chain] of from-head ) ]
  ask to-head [ set Mj-pi-this-chain 
    ( item 0 [Mj-pi-this-chain] of from-head ) ]
  ask to-head [ set Mt-pi-this-chain 
    ( item 0 [Mt-pi-this-chain] of from-head ) ]
  ask to-head [ set Eu-pi-this-chain 
    ( item 0 [Eu-pi-this-chain] of from-head ) ]
  ask to-head [ set Mj-geo-this-chain 
    ( item 0 [Mj-geo-this-chain] of from-head ) ]
  ask to-head [ set Mt-geo-this-chain 
    ( item 0 [Mt-geo-this-chain] of from-head ) ]
  ask to-head [ set Eu-geo-this-chain 
    ( item 0 [Eu-geo-this-chain] of from-head ) ]

  ask to-head [ set primed-rh-hoam-index 
    ( item 0 [primed-rh-hoam-index] of from-head ) ]
  ask to-head [ set primed-lh-hoam-index 
    ( item 0 [primed-lh-hoam-index] of from-head ) ]
  ;; ask to-head [ set default-colour 
  ;;   ( item 0 [default-colour] of from-head ) ]

  ;; Associated with HOAM.
  ask to-head [ set index-into-chain 
    ( item 0 [index-into-chain] of from-head ) ]
  ask to-head [ set mass 
    ( item 0 [mass] of from-head ) ]

  ;; Associated with rh-hoam.
  ask to-head [ set oam-time-to-drop 
    ( item 0 [oam-time-to-drop] of from-head ) ]
  ask to-head [ set age-to-discharge 
    ( item 0 [age-to-discharge] of from-head ) ]
  ask to-head [ set energy-to-transfer 
    ( item 0 [energy-to-transfer] of from-head ) ]
  ask to-head [ set energy-to-discharge 
    ( item 0 [energy-to-discharge] of from-head ) ]
  ask to-head [ set Mt-in-oam 
    ( item 0 [Mt-in-oam] of from-head ) ]
  ask to-head [ set Eu-in-oam 
    ( item 0 [Eu-in-oam] of from-head ) ]
  ask to-head [ set Mj-in-oam 
    ( item 0 [Mj-in-oam] of from-head ) ]

  ;; End of f-copy-head-to-head
end 

;;-----------------------------------------------------------------------------|
;; Copy contents from one body to another.

to f-copy-body-to-body [ from-body to-body ]
  ;; The observer executes this routine.
  
  ;; Both bodys must have different who numbers.
  let from-who ( item 0 [who] of from-body )
  let to-who   ( item 0 [who] of to-body )
  ASSERT ( from-who != to-who ) 
    ( word "Copy error: who " from-who " = " to-who ) from-who
  
  ;; I don't know of an easy way to do this.  It looks messy.
  
  ;; Associated with chain.
  ;; Nil.

  ;; Associated with HOAM.
  ask to-body [ set index-into-chain 
    ( item 0 [index-into-chain] of from-body ) ]
  ask to-body [ set mass 
    ( item 0 [mass] of from-body ) ]

  ;; Associated with rh-hoam.
  ask to-body [ set oam-time-to-drop 
    ( item 0 [oam-time-to-drop] of from-body ) ]
  ask to-body [ set age-to-discharge 
    ( item 0 [age-to-discharge] of from-body ) ]
  ask to-body [ set energy-to-transfer 
    ( item 0 [energy-to-transfer] of from-body ) ]
  ask to-body [ set energy-to-discharge 
    ( item 0 [energy-to-discharge] of from-body ) ]
  ask to-body [ set Mt-in-oam 
    ( item 0 [Mt-in-oam] of from-body ) ]
  ask to-body [ set Eu-in-oam 
    ( item 0 [Eu-in-oam] of from-body ) ]
  ask to-body [ set Mj-in-oam 
    ( item 0 [Mj-in-oam] of from-body ) ]

  ;; End of f-copy-body-to-body
end 

;;-----------------------------------------------------------------------------|
;; Copy contents from one tail to another.

to f-copy-tail-to-tail [ from-tail to-tail ]
  ;; The observer executes this routine.
  
  ;; Both tails must have different who numbers.
  let from-who ( item 0 [who] of from-tail )
  let to-who   ( item 0 [who] of to-tail )
  ASSERT ( from-who != to-who ) 
    ( word "Copy error: who " from-who " = " to-who ) from-who
  
  ;; I don't know of an easy way to do this.  It looks messy.
  
  ;; Associated with chain.
  ;; Nil.
  
  ;; Associated with HOAM.
  ask to-tail [ set index-into-chain 
    ( item 0 [index-into-chain] of from-tail ) ]
  ask to-tail [ set mass 
    ( item 0 [mass] of from-tail ) ]

  ;; Associated with rh-hoam.
  ;; Nil.

  ;; End of f-copy-tail-to-tail
end 

;;-----------------------------------------------------------------------------|
;; Alter one of the masses, other than the mass in the tail.

to f-mutate-this-chain [ chain-to-mutate ]
  ;; The observer executes this routine.

  let this-head ( item 0 chain-to-mutate )
  ask this-head [ set age-of-chain 0 set default-colour ( one-of gl-colour-pallette ) ]
  let this-chain-index ( item 0 [index-into-chains-lib] of this-head )
  let this-chain-sn ( item 0 [chain-sn] of this-head )
  LOG-TO-FILE ( word "  Mutating Ch(" this-chain-sn "," this-chain-index ")" )
  
  ;; Decide how many, and which, HOAMs can have mass mutated.
  let argument g-length-of-chains
  if( gb-mutate-heads = false ) [ set argument ( argument - 1 ) ]
  if( gb-mutate-tails = false ) [ set argument ( argument - 1 ) ]
  
  ;; Select an RH-HOAM randomly.
  let random-hoam-index random argument ;;  { 0, ..., (argument - 1 ) }
  ;; By default this includes the head.  Adjust upwards if needed.
  if( gb-mutate-heads = false ) [ set random-hoam-index ( random-hoam-index + 1 ) ]
  
  ;; Access the randomly selected HOAM.
  let this-hoam ( item random-hoam-index chain-to-mutate )
  LOG-TO-FILE ( word "    Mutating HOAM " random-hoam-index )
  
  ;; Extract the masses.
  let this-mass ( item 0 [mass] of this-hoam )
  let this-mass-was this-mass
  LOG-TO-FILE ( word "    Old mass: " this-mass )
  
  ;; Decide whether the mass in this HOAM will go up or down.
  let b-mass-goes-up random 2  ;; { 0, 1 }
  ;; Set a default size-factor
  let size-factor 1.0
  
  ;; When you adjust the mass in an HOAM you affect the efficiency of both
  ;;   OAMs formed using this HOAM.  An altered mass can make the combined
  ;;   time to discharge for both OAMs longer or shorter.  I want to make
  ;;   the change small enough that variances in time to process are not
  ;;   volatile, but large enough that the system can converge on a solution
  ;;   relatively quickly.  I have decided to use a random delta that is,
  ;;   at most, 1/4 of the distance to the previous or next mass
  
  ;; Compute a new mass for this HOAM.
  ;; Treat the head and tail differently from the others.
  ;; This is complicated, having six optional paths, all handled by ifelse.
  ifelse ( random-hoam-index = 0 )
  [
    ;; This-hoam is the head.
    ;; There is no prev-hoam.
    let next-hoam ( item ( random-hoam-index + 1 ) chain-to-mutate )
    let next-mass ( item 0 [mass] of next-hoam )

    ifelse ( b-mass-goes-up = 1 )
    [
      ;; Mass goes up.  It may go up by as much as 1/4 the distance
      ;;   to the next mass down.  Since, for the head, there is no next mass
      ;;   up, I use the next mass down to scale the change, but raise the 
      ;;   mass up.
      let mass-diff ( this-mass - next-mass )
      set size-factor ( ( random-float 1 ) / 4 )   ;; [0, 0.25 )
      set this-mass ( this-mass + ( size-factor * mass-diff ) )
    ]
    ;; else
    [
      ;; Mass goes down.  It may go down by as much as 1/4 the distance
      ;;   to the next mass.
      let mass-diff ( this-mass - next-mass )
      set size-factor ( ( random-float 1 ) / 4 )   ;; [0, 0.25 )
      let mass-delta ( -1 * size-factor * mass-diff )
      set this-mass ( this-mass + mass-delta )
    ]
  ] ;; End if ( random-hoam-index = 0 )
  ;; else
  [
    ;; This-hoam is not the head.  But it may be the tail, which also needs 
    ;;   special processing.
    
    ifelse ( random-hoam-index = ( g-length-of-chains - 1 ) )
    [
      ;; This-hoam is a tail HOAM.  There is no next HOAM.
      ;; Unpack the mass of the previous HOAM.
      let prev-hoam ( item ( random-hoam-index - 1 ) chain-to-mutate )
      let prev-mass ( item 0 [mass] of prev-hoam )
      
      ifelse ( b-mass-goes-up = 1 )
      [
        ;; Mass goes up.  It may go up by as much as 1/4 the distance
        ;;   to the previous mass.
        let mass-diff ( prev-mass - this-mass )
        set size-factor ( ( random-float 1 ) / 4 )  ;; [0, 0.25 ) 
        set this-mass ( this-mass + ( size-factor * mass-diff ) )
      ]
      ;; else
      [
        ;; Mass goes down.  It may go down by as much as 1/4 the distance
        ;;   to the next mass.
        let mass-diff this-mass ;; Special case for tail.
        set size-factor ( ( random-float 1 ) / 4 )   ;; [0, 0.25 ) 
        set this-mass ( this-mass - ( size-factor * mass-diff ) )
      ]
      ;; End else
    ]
    ;; Else
    [
      ;; This-hoam is a body HOAM.
      ;; Unpack the mass of the previous HOAM.
      let prev-hoam ( item ( random-hoam-index - 1 ) chain-to-mutate )
      let prev-mass ( item 0 [mass] of prev-hoam )
      ;; Unpack the mass of the next HOAM.
      let next-hoam ( item ( random-hoam-index + 1 ) chain-to-mutate )
      let next-mass ( item 0 [mass] of next-hoam )
      
      ifelse ( b-mass-goes-up = 1 )
      [
        ;; Mass goes up.  It may go up by as much as 1/4 the distance
        ;;   to the previous mass.
        let mass-diff ( prev-mass - this-mass )
        set size-factor ( ( random-float 1 ) / 4 )  ;; [0, 0.25 ) 
        set this-mass ( this-mass + ( size-factor * mass-diff ) )
      ]
      ;; else
      [
        ;; Mass goes down.  It may go down by as much as 1/4 the distance
        ;;   to the next mass.
        let mass-diff ( this-mass - next-mass )
        set size-factor ( ( random-float 1 ) / 4 )   ;; [0, 0.25 ) 
        set this-mass ( this-mass - ( size-factor * mass-diff ) )
      ]
      ;; End else
    ]
    ;; End else
  ]  ;; End else ( random-hoam-index != 0 )

  ;; Change mass in this-hoam, which is still in chain-to-mutate.
  ask this-hoam [ set mass this-mass ]
  LOG-TO-FILE ( word "    New mass: " this-mass )
  
  ;; And, finally, recompute the energetics of this mutated chain.
  f-compute-energetics-of-chain chain-to-mutate
  ;; And, prime the first OAM in the chain.
  ;; Each possible OAM in the chain was actually primed in the above
  ;;   call, from a programming point of view, but metaphorically, it
  ;;   is not primed until the previous OAM has discharged its energy.
  f-prime-oam 0 1 chain-to-mutate
 
  if( gb-dpx-on = 1 )
  [
    ;; Collect 'data per x-action' items if appropriate.
    let dpx-record-B ( n-values 5 [0.0] )  ;; Zeros
    
    let sn-of-ma ( item 0 [mas-sn] of this-head )
    set dpx-record-B ( replace-item 0 dpx-record-B sn-of-ma )

    let sn-of-chain ( item 0 [chain-sn] of this-head )
    set dpx-record-B ( replace-item 1 dpx-record-B sn-of-chain )

    set dpx-record-B ( replace-item 2 dpx-record-B random-hoam-index )
    set dpx-record-B ( replace-item 3 dpx-record-B this-mass-was )
    set dpx-record-B ( replace-item 4 dpx-record-B this-mass )

    WRITE-DPX-RECORD-B dpx-record-B
  ]
  
  ;; End of f-mutate-this-chain [ chain-to-mutate ]
end 
 
;;-----------------------------------------------------------------------------|
;; D3 - f-post-tick procedure(s)
;;-----------------------------------------------------------------------------|

to do-post-tick
  ;; This routine is to be executed by the observer.
   
  if( gb-debug-on = 1 )
  [
    ifelse( ( gs-debug-step-chooser = "all" ) or ( gs-debug-step-chooser = "post-tick" ) )
    [ set gb-debug-flow-on 1  LOG-TO-FILE "" LOG-TO-FILE word "Do-Post-tick: Debug on; tick = " ticks ]
    [ set gb-debug-flow-on 0 ]
  ]
  
  ;; MANUAL CHANGE FOR DEBUG.
  ;; This is a call to a debug routine which could be suppressed if all is okay.
  ;; This is one of a group of such calls, most of which are between steps in 
  ;;   the 'Go' routine.  They are suppressed there, but can be enabled again.
  ;; I have decided to leave this one active, for now.
  ;; It checks all agents, every tick, to ensure that all values are greater than
  ;;   or equal to zero.  
  if( frb-agents-are-all-valid = false ) [ LOG-TO-FILE ( word "Agents failed validity test." ) ]
  
  ;; Write "Data Per Tick" (dpt) macro data to CSV file, if it is turned on.
  DPT-DUMP
  
  ;; Update the aggregates for display in the monitors.
  f-update-aggregates

  display

  LOG-TO-FILE "Do-Pos: procedure completed."
  
  ;; End of to do-post-tick
end 

;;-----------------------------------------------------------------------------|
;; SECTION E – DRAWING AND MAINTENANCE PROCEDURE(S)
;;-----------------------------------------------------------------------------|

;;-----------------------------------------------------------------------------|
;; Update the values of global aggregate numbers.

to-report fr-geometric-mean [list-of-geo-means]
  ;; This routine is to be executed by the observer.
  ;;   As input it takes a list of numbers between 0 and 1 and produces
  ;;   the geometric mean of those numbers.  The list can be a list of
  ;;   geometric means of indices, or just a list of indices.
  
  let index 0
  let results 1  ;; Must be one.
  let this-number 0
  let list-length ( length list-of-geo-means )
  while [ index < list-length ]
  [
    set this-number ( item index list-of-geo-means )
    set results ( results * this-number )
    
    set index ( index + 1 )
  ]
  set results ( results ^ ( 1 / list-length ) )
  report results
  
  ;; End of fr-geometric-mean
end 

;;-----------------------------------------------------------------------------|
;; Update the values of global aggregate numbers.

to f-update-aggregates
  ;; This routine is to be executed by the observer.

  ;; Although this is a display-only routine, it implicitly calls the PRNG and
  ;;   so does have an effect on the trajectory of the model.  In a standard 'go'
  ;;   run it is called only once per tick, before graphs are updated.  If you
  ;;   use the one-step debug buttons, it is called once after each step, so
  ;;   debug runs that use those buttons will not replicate a real run.
  
  ;; Most per-tick aggregates are handled as they happen.  High-grade
  ;;   energy happens as the light mass rises, and it is computed here.
  
  ;; Zero all aggregates not part of per-tick actions.
  set gl-ttl-lg-nrg-per-hoam  ( n-values g-length-of-chains [0.0] )
  set gl-ttl-mass-per-hoam    ( n-values g-length-of-chains [0.0] )
  set gl-ttl-hg-nrg-per-oam   ( n-values ( g-length-of-chains - 1 ) [0.0] )
  set gl-pi-Mj-per-oam        ( n-values ( g-length-of-chains - 1 ) [1.0] )
  set gl-pi-Mt-per-oam        ( n-values ( g-length-of-chains - 1 ) [1.0] )
  set gl-pi-Eu-per-oam        ( n-values ( g-length-of-chains - 1 ) [1.0] )
  set gl-geo-Mj-per-oam       ( n-values ( g-length-of-chains - 1 ) [1.0] )
  set gl-geo-Mt-per-oam       ( n-values ( g-length-of-chains - 1 ) [1.0] )
  set gl-geo-Eu-per-oam       ( n-values ( g-length-of-chains - 1 ) [1.0] )

  set gl-ttl-hg-nrg-per-tick  ( n-values g-length-of-chains [0.0] )
  ;; set gl-ttl-lg-nrg-per-tick  ( n-values g-length-of-chains [0.0] )

  ;; All of these are collected as potential numerators of fractions.
  set g-no-of-hoams count turtles
  set g-no-of-heads count heads
  set g-no-of-bodies count bodies
  set g-no-of-tails count tails
  set g-ttl-age-of-chains sum [age-of-chain] of heads
  set g-ttl-dt-of-chains sum [chain-time-to-drop] of heads
  
  ;; These are the geometric mean of a set of geometric means.
  set g-geo-Mj ( fr-geometric-mean ( [Mj-geo-this-chain] of heads ) )
  set g-geo-Mt ( fr-geometric-mean ( [Mt-geo-this-chain] of heads ) )
  set g-geo-Eu ( fr-geometric-mean ( [Eu-geo-this-chain] of heads ) )
  
  ;; Declaration of needed variables.
  let this-chain-index 0
  let this-hoam-index 0
  let this-chain gl-new-chain ;; a dummy assignment
  let this-hoam one-of heads
  let value-from-hoam 0
  let value-from-list 0
  let time-for-this-drop 0
  
  ;; I have to do some tricky stuff here with indices into the lists
  ;;   because there are four rh-hoams in which data is collected that
  ;;   is associated with five transaction types:
  ;; - For hg energy, the energy coming into the first rh-hoam is not recorded.
  ;; - For hg energy, per tick, it must be computed, with the same problem.
  ;; - For lg energy, it's the tail exhausts all.
  ;; - For efficiency, there are four oams and four records.  A fifth is invented.
  
  ;; Loop through all hoams in all chains.
  while [ this-chain-index < g-no-of-chains ]
  [
    set this-chain ( item this-chain-index gl-chains-lib )
    
    set this-hoam-index 0
    while [ this-hoam-index < g-length-of-chains ]
    [
      set this-hoam ( item this-hoam-index this-chain )
      
      ;; Mass is the easiest to compile.
      set value-from-hoam item 0 ( [mass] of this-hoam ) 
      set value-from-list ( item this-hoam-index gl-ttl-mass-per-hoam )
      set value-from-list ( value-from-list + value-from-hoam )
      ;; Store it in the list
      set gl-ttl-mass-per-hoam
        ( replace-item this-hoam-index gl-ttl-mass-per-hoam value-from-list )
      
      ;; Some data is only associated with RH-HOAMS.
      if ( this-hoam-index < ( g-length-of-chains - 1 ) ) ;; I.e. not a tail
      [
        ;; High-grade energy
        ;; Calculate the amount transferred out of this rh-HOAM.
        set value-from-hoam ( item 0 [energy-to-transfer] of this-hoam ) 
        set value-from-list ( item this-hoam-index gl-ttl-hg-nrg-per-oam )
        set value-from-list ( value-from-list + value-from-hoam )
        ;; Store it in the list
        set gl-ttl-hg-nrg-per-oam
          ( replace-item this-hoam-index gl-ttl-hg-nrg-per-oam value-from-list )
          
        ;; Now, handle the per tick flow of hg nrg to the lh-hoam.
        set time-for-this-drop ( item 0 ( [oam-time-to-drop] of this-hoam ) )
        ifelse ( time-for-this-drop = 0 )
        [ set value-from-hoam 0 ]
        [ set value-from-hoam item 0 ( [energy-to-transfer] of this-hoam )
          set value-from-hoam ( value-from-hoam / time-for-this-drop ) ]
        set value-from-list ( item this-hoam-index gl-ttl-hg-nrg-per-tick )
        set value-from-list ( value-from-list + value-from-hoam )
        ;; Store it in the list
        set gl-ttl-hg-nrg-per-tick
          ( replace-item this-hoam-index gl-ttl-hg-nrg-per-tick value-from-list )

        ;; Now, handle total lg nrg.
        set value-from-hoam item 0 ( [energy-to-discharge] of this-hoam )
        set value-from-list ( item this-hoam-index gl-ttl-lg-nrg-per-hoam )
        set value-from-list ( value-from-list + value-from-hoam )
        ;; Store it in the list
        set gl-ttl-lg-nrg-per-hoam
          ( replace-item this-hoam-index gl-ttl-lg-nrg-per-hoam value-from-list )
      
        ;; The tail OAM needs to be handled as a special case of the HOAM that
        ;;   immediately precedes it.
        if ( this-hoam-index = ( g-length-of-chains - 2 ) )
        [
          ;; All of the energy transferred to the tail is exhausted.
          ;; Get 'transferred', but store as low grade or 'exhausted'.
          set value-from-hoam item 0 ( [energy-to-transfer] of this-hoam )
          set value-from-list ( item ( this-hoam-index + 1 ) gl-ttl-lg-nrg-per-hoam )
          set value-from-list ( value-from-list + value-from-hoam )
          ;; Store it in the list
          set gl-ttl-lg-nrg-per-hoam
            ( replace-item ( this-hoam-index + 1 ) gl-ttl-lg-nrg-per-hoam value-from-list )
        ]

        ;; And Mj.
        set value-from-hoam ( item 0 [Mj-in-oam] of this-hoam )
        set value-from-list ( item this-hoam-index gl-pi-Mj-per-oam )
        set value-from-list ( value-from-list * value-from-hoam )
        ;; Store it in the list
        set gl-pi-Mj-per-oam
          ( replace-item this-hoam-index gl-pi-Mj-per-oam value-from-list )

        ;; Mt.
        set value-from-hoam ( item 0 [Mt-in-oam] of this-hoam )
        set value-from-list ( item this-hoam-index gl-pi-Mt-per-oam )
        set value-from-list ( value-from-list * value-from-hoam )
        ;; Store it in the list
        set gl-pi-Mt-per-oam
          ( replace-item this-hoam-index gl-pi-Mt-per-oam value-from-list )

        ;; And Eu.
        set value-from-hoam ( item 0 [Eu-in-oam] of this-hoam )
        set value-from-list ( item this-hoam-index gl-pi-Eu-per-oam )
        set value-from-list ( value-from-list * value-from-hoam )
        ;; Store it in the list
        set gl-pi-Eu-per-oam
          ( replace-item this-hoam-index gl-pi-Eu-per-oam value-from-list )
      ]

      set this-hoam-index ( this-hoam-index + 1 )
    ]  ;; End of while [ this-hoam-index < g-length-of-chains ]

    set this-chain-index ( this-chain-index + 1 )
  ]  ;; Enf of while [ this-chain-index < g-no-of-chains ]
  
  ;; Compute the geometric averages using the products.
  set this-hoam-index 0
  let geometric-mean 0
  while [ this-hoam-index < ( g-length-of-chains - 1 ) ]
  [
     set value-from-list ( item this-hoam-index gl-pi-Mj-per-oam ) 
     set geometric-mean ( value-from-list ^ ( 1 / g-no-of-chains ) )
     set gl-geo-Mj-per-oam ( replace-item this-hoam-index gl-geo-Mj-per-Oam geometric-mean )
     
     set value-from-list ( item this-hoam-index gl-pi-Mt-per-oam ) 
     set geometric-mean ( value-from-list ^ ( 1 / g-no-of-chains ) )
     set gl-geo-Mt-per-oam ( replace-item this-hoam-index gl-geo-Mt-per-Oam geometric-mean )
     
     set value-from-list ( item this-hoam-index gl-pi-Eu-per-oam ) 
     set geometric-mean ( value-from-list ^ ( 1 / g-no-of-chains ) )
     set gl-geo-Eu-per-oam ( replace-item this-hoam-index gl-geo-Eu-per-Oam geometric-mean )
     
     set this-hoam-index ( this-hoam-index + 1 ) 
  ]
 
  ;;-----------------------------------------------------------------------------|
  ;; To ensure that the PRNG is called whether or not plots are displayed, the
  ;;   calculations needed for the histogram plots are carried out here where
  ;;   they will happen every tick.

  ;; This log entry may come from any step during debug operations.  
  LOG-TO-FILE "Do-xxx: All aggregates updated."  
  
  ;; End of f-update-aggregates
end 

;;--------------------------
;; DATA CAPTURE TO CSV FILES
;;--------------------------
  
;;-----------------------------------------------------------------------------|
;; Open a dpx file.

to f-open-dpx-file
  ;; This routine is to be executed by the observer.
  
  ;; DPX stands for 'Data Per Xaction'
  ;; Ensure previous dpx file is closed.
  f-close-dpx-file
  
  set gb-dpx-on 1
  set gs-dpx-status "1 (On)"
  set gs-dpx-file-name ( fr-construct-file-name "dpx" )
  set g-dpx-recno 0
  
  file-open gs-dpx-file-name
  
  ;; Write the mast head for the file.
  file-show "Data Per Transaction (DPX) File for a OamLab (NetLogo) Model."
  file-show word "File Name: " gs-dpx-file-name
  file-show ( word "Application Version Number: "gs-Version )
  file-show ""
    
  ifelse ( file-exists? gs-dpx-file-name )
  [
    ;; Send a message directly to the command centre.
    show word gs-dpx-file-name " opened."

    ;; Write the system parameter settings to the file.
    f-write-system-settings
    
    f-write-dpx-headers
  ]
  ;; else
  [
    ;; Send a message directly to the command centre.
    show word gs-dpx-file-name " not opened."
  
    set gb-dpx-on 0
    set gs-dpx-status "0 (Off)"
    set gs-dpx-file-name "DpxDummyName"
  ]
  
  ;; End of f-open-dpx-file
end 

;;-----------------------------------------------------------------------------|
;; Write header recordS to the dpx data file.

to f-write-dpx-headers
  ;; This routine is to be executed by the observer.

  ;; Select the file
  file-open gs-dpx-file-name
  
  ;; Write a header record for mutation data. 
  let line-out "DPX-A, "
  set line-out ( word line-out "RecNo, " )
  set line-out ( word line-out "Tick, " )

  set line-out ( word line-out "Ma's Serial #, " )
  set line-out ( word line-out "Serial #, " )
  set line-out ( word line-out "HOAM #, " )
  set line-out ( word line-out "Mass Was, " )
  set line-out ( word line-out "Mass Is now, " )

  file-print line-out
 
  ;; Write a header record for a mutated chain. 
  set line-out "DPX-C, "
  set line-out ( word line-out "RecNo, " )
  set line-out ( word line-out "Tick, " )

  ;; Head of chain
  set line-out ( word line-out "X-Action, " )
  set line-out ( word line-out "Ch: Ma's Serial #, " )
  set line-out ( word line-out "Ch: Serial #, " )
  set line-out ( word line-out "Ch: time-to-drop, " )
  set line-out ( word line-out "Ch: Mj, " )
  set line-out ( word line-out "Ch: Mt, " )
  set line-out ( word line-out "Ch: Eu, " )
  set line-out ( word line-out "He: Who #, " )
  set line-out ( word line-out "He: HOAM #, " )
  set line-out ( word line-out "He: HOAM-mass, " )
  set line-out ( word line-out "He: OAM-time-to-drop, " )
  set line-out ( word line-out "He: OAM-energy-to-transfer, " )
  set line-out ( word line-out "He: OAM-energy-to-discharge, " )
  set line-out ( word line-out "He: OAM-Mj, " )
  set line-out ( word line-out "He: OAM-Mt, " )
  set line-out ( word line-out "He: OAM-Eu, " )

  ;; Bodies within chain.
  let hoam-index 1
  while [ hoam-index < ( g-length-of-chains - 1 ) ] ;; Exclude head and tail.
  [
    set line-out ( word line-out "Bo: Who #, " )
    set line-out ( word line-out "Bo: HOAM #, " )
    set line-out ( word line-out "Bo: HOAM-mass, " )
    set line-out ( word line-out "Bo: OAM-time-to-drop, " )
    set line-out ( word line-out "Bo: OAM-energy-to-transfer, " )
    set line-out ( word line-out "Bo: OAM-energy-to-discharge, " )
    set line-out ( word line-out "Bo: OAM-Mj, " )
    set line-out ( word line-out "Bo: OAM-Mt, " )
    set line-out ( word line-out "Bo: OAM-Eu, " )
    
    set hoam-index ( hoam-index + 1 )
  ]

  set line-out ( word line-out "Ta: Who #, " )
  set line-out ( word line-out "Ta: HOAM #, " )
  set line-out ( word line-out "Ta: HOAM-mass " )

  file-print line-out
 
 ;; End of f-write-dpx-headers
end 

;;-----------------------------------------------------------------------------|
;; Write the data record type B (mutation event) for the dpx data file.

to WRITE-DPX-RECORD-B [ this-record ]
  ;; This routine is to be executed by the observer.

  ;; Select the file
  file-open gs-dpx-file-name
  
  ;; Write a data record for X-Action. 
  set g-dpx-recno ( g-dpx-recno + 1 )
  ;; Record type
  let line-out "DPX-B, "
  ;; Record number
  set line-out ( word line-out g-dpx-recno ", " )
  set line-out ( word line-out ticks ", " )

  set line-out ( word line-out ( item  0 this-record ) ", " ) ;; Ma's Serial #
  set line-out ( word line-out ( item  1 this-record ) ", " ) ;; Serial #
  set line-out ( word line-out ( item  2 this-record ) ", " ) ;; HOAM #
  set line-out ( word line-out ( item  3 this-record ) ", " ) ;; Mass was
  set line-out ( word line-out ( item  4 this-record ) ", " ) ;; Mass is now

  file-print line-out
  
  ;; End of WRITE-DPX-RECORD-B
end 

;;-----------------------------------------------------------------------------|
;; Write a record to the DPX file, if appropriate.

to WRITE-DPX-D-RECORD [ index-of-chain action ]
  ;; The observer executes this routine.
  
  ;; Only execute if "data per event" is toggled on.
  if ( gb-dpx-on = 1 )
  [
    ;; Select the file
    file-open gs-dpx-file-name
  
    ;; Increment the record number. 
    set g-dpx-recno ( g-dpx-recno + 1 )

    ;; Unpack the chain.
    let this-chain ( item index-of-chain gl-chains-lib ) 
    let this-value 0   ;; Dummy declaration
    
    ;; Record type
    let line-out "DPX-D, "
    set line-out ( word line-out g-dpx-recno ", " )
    set line-out ( word line-out ticks ", " )
    set line-out ( word line-out action ", " )

    ;; Unpack the head of chain
    let this-hoam ( item 0 this-chain )

    ;; Write data from the head.
    set this-value ( item 0 [mas-sn] of this-hoam )
    set line-out ( word line-out this-value ", " ) ;; Ma's serial number

    set this-value ( item 0 [chain-sn] of this-hoam )
    set line-out ( word line-out this-value ", " ) ;; Serial number

    set this-value ( item 0 [chain-time-to-drop] of this-hoam )
    set line-out ( word line-out this-value ", " ) ;; Chain-time-to-drop

    set this-value ( item 0 [Mj-geo-this-chain] of this-hoam )
    set line-out ( word line-out this-value ", " ) ;; Chain-Mj

    set this-value ( item 0 [Mt-geo-this-chain] of this-hoam )
    set line-out ( word line-out this-value ", " ) ;; Chain-Mt

    set this-value ( item 0 [Eu-geo-this-chain] of this-hoam )
    set line-out ( word line-out this-value ", " ) ;; Chain-Eu

    set this-value ( item 0 [who] of this-hoam )
    set line-out ( word line-out this-value ", " ) ;; Who #

    set this-value ( item 0 [index-into-chain] of this-hoam )
    set line-out ( word line-out this-value ", " ) ;; HOAM #

    set this-value ( item 0 [mass] of this-hoam )
    set line-out ( word line-out this-value ", " ) ;; HOAM-mass

    set this-value ( item 0 [oam-time-to-drop] of this-hoam )
    set line-out ( word line-out this-value ", " ) ;; OAM-time-to-drop

    set this-value ( item 0 [energy-to-transfer] of this-hoam )
    set line-out ( word line-out this-value ", " ) ;; OAM-energy-to-transfer

    set this-value ( item 0 [energy-to-discharge] of this-hoam )
    set line-out ( word line-out this-value ", " ) ;; OAM-energy-to-discharge

    set this-value ( item 0 [Mj-in-oam] of this-hoam )
    set line-out ( word line-out this-value ", "  ) ;; OAM-Mj

    set this-value ( item 0 [Mt-in-oam] of this-hoam )
    set line-out ( word line-out this-value ", " ) ;; OAM-Mt

    set this-value ( item 0 [Eu-in-oam] of this-hoam )
    set line-out ( word line-out this-value ", " ) ;; OAM-Eu

    ;; Bodies within chain.
    let hoam-index 1  ;; Exclude head, start at index = 1.
    while [ hoam-index < ( g-length-of-chains - 1 ) ] ;; Exclude tail.
    [
      set this-hoam ( item hoam-index this-chain )
      
      set this-value ( item 0 [who] of this-hoam )
      set line-out ( word line-out this-value ", " ) ;; Who#
      
      set this-value ( item 0 [index-into-chain] of this-hoam )
      set line-out ( word line-out this-value ", " ) ;; HOAM #
      
      set this-value ( item 0 [mass] of this-hoam )
      set line-out ( word line-out this-value ", " ) ;; HOAM-mass
      
      set this-value ( item 0 [oam-time-to-drop] of this-hoam )
      set line-out ( word line-out this-value ", " ) ;; OAM-time-to-drop
      
      set this-value ( item 0 [energy-to-transfer] of this-hoam )
      set line-out ( word line-out this-value ", " ) ;; OAM-energy-to-transfer
      
      set this-value ( item 0 [energy-to-discharge] of this-hoam )
      set line-out ( word line-out this-value ", " ) ;; OAM-energy-to-discharge
      
      set this-value ( item 0 [Mj-in-oam] of this-hoam )
      set line-out ( word line-out this-value ", " ) ;; OAM-Mj
      
      set this-value ( item 0 [Mt-in-oam] of this-hoam )
      set line-out ( word line-out this-value ", " ) ;; OAM-Mt
      
      set this-value ( item 0 [Eu-in-oam] of this-hoam )
      set line-out ( word line-out this-value ", " ) ;; OAM-Eu

      set hoam-index ( hoam-index + 1 )
    ]  ;; End while [ hoam-index < ( g-length-of-chains - 1 ) ]

    ;; The tail of the chain.
    set this-hoam ( item hoam-index this-chain )

    set this-value ( item 0 [who] of this-hoam )
    set line-out ( word line-out this-value ", " ) ;; Who #
      
    set this-value ( item 0 [index-into-chain] of this-hoam )
    set line-out ( word line-out this-value ", " ) ;; HOAM #
      
    set this-value ( item 0 [mass] of this-hoam )
    set line-out ( word line-out this-value ", " ) ;; HOAM-mass

    file-print line-out
  ]  ;; End if ( gb-dpx-on = 1 )
  
  ;; End of WRITE-DPX-D-RECORD
end 

;;-----------------------------------------------------------------------------|
;; Close the dpx file.

to f-close-dpx-file
  ;; This routine is to be executed by the observer.
  
  ;; DPX stands for 'Data Per Xaction'
  if ( Is-string? gs-dpx-file-name )
  [
    if ( file-exists? gs-dpx-file-name )
    [
      ;; Select the file
      file-open gs-dpx-file-name
      ;; Close it.
      file-close
    ]
  ]
  set gb-dpx-on 0
  set gs-dpx-status "0 (Off)"
  set gs-dpx-file-name "DpxDummyName"
  set g-dpx-recno 0
  
  ;; End of f-close-dpx-file
end 

;;-----------------------------------------------------------------------------|
;; Close and reopen the dpx file, it is too full.

to f-reopen-dpx-file
  ;; This routine is to be executed by the observer.
  
  f-close-dpx-file
  f-open-dpx-file

  ;; End of f-reopen-dpx-file
end 

;;-----------------------------------------------------------------------------|
;; Write a pair of records for the system settings.

to f-write-system-settings
  ;; This routine is to be executed by the observer.

  ;; A file must already be selected.
  ;; These system setting records are meant to be writtin right after the
  ;;   mast head lines.
  
  ;; Write a header record for system parameters.  
  let line-out "SYS-A, "
  set line-out ( word line-out "Version, " )
  set line-out ( word line-out "Scenario, " )
  set line-out ( word line-out "Fitness test, " )
  set line-out ( word line-out "PRNG-Seed, " )
  
  set line-out ( word line-out "g-no-of-chains-at-start, " )
  set line-out ( word line-out "g-no-of-chains-max, " )
  set line-out ( word line-out "g-length-of-chains, " )
  set line-out ( word line-out "g-drop-distance, " )
  set line-out ( word line-out "g-acceleration, " )
  set line-out ( word line-out "gb-mutate-heads, " )
  set line-out ( word line-out "gb-mutate-tails " )
  
  file-print line-out
  
  ;; Write a data record for system parameters.  
  set line-out "SYS-B, "
  set line-out ( word line-out gs-Version ", " )
  set line-out ( word line-out gs-scenario ", " )
  set line-out ( word line-out gs-fitness-measure ", " )
  set line-out ( word line-out g-use-this-seed ", " )
  
  set line-out ( word line-out g-no-of-chains-at-start ", " )
  set line-out ( word line-out g-no-of-chains-max ", " )
  set line-out ( word line-out g-length-of-chains ", " )
  set line-out ( word line-out g-drop-distance ", " )
  set line-out ( word line-out g-acceleration ", " )
  set line-out ( word line-out gb-mutate-heads ", " )
  set line-out ( word line-out gb-mutate-tails " " )
  
  file-print line-out
  
  ;; Now, write instructions on how to process the data.
  set line-out ( word "INSTRUCTIONS:" )
  file-print line-out
  set line-out ( word " - Copy the above rows of meta-data to a fresh sheet." )
  file-print line-out
  set line-out ( word " - Then delete the rows of meta-data and instructions." )
  file-print line-out
  set line-out ( word " - Then sort all columns and all rows of headers and data using Column A as sort key." )
  file-print line-out
  
  ;; End of f-write-system-settings
end 

;;-----------------------------------------------------------------------------|
;; Dump "Data Per Tick" data to dpt file, if open.

to DPT-DUMP
  ;; This routine is to be executed by the observer.

  ;; Activate only if the dpt file is open and ready to receive data.
  if( gb-dpt-on = 1 )
  [
    ;; If the file is full, close it.  MS Excel can handle 1,048,000 records.
    ;; Terminate the file before 1,000,000 records.
    ifelse( g-dpt-recno > g-recno-max ) [ f-reopen-dpt-file ]
    [
      ;; Activate once per tick.  Take a reading.
      ;; This collects macro-economic data of various kinds.
      f-write-dpt-macro-data 
    ]
  ]
  
  ;; End of DPT-DUMP
end 

;;-----------------------------------------------------------------------------|
;; Open a dpt file.

to f-open-dpt-file
  ;; This routine is to be executed by the observer.
  
  ;; DPT stands for 'Data Per Tick'
  ;; Ensure previous dpt file is closed.
  f-close-dpt-file
  
  set gb-dpt-on 1
  set gs-dpt-status "1 (On)"
  set gs-dpt-file-name ( fr-construct-file-name "dpt" )
  set g-dpt-recno 0
  
  file-open gs-dpt-file-name
 
  ;; Write the mast head for the file.
  file-show "Data Per Transaction (dpt) File for a OamLab (NetLogo) Model."
  file-show ( word "Application Version Number: "gs-Version )
  file-show word "File opened at:" date-and-time
  file-show ""
    
  ifelse ( file-exists? gs-dpt-file-name )
  [
    ;; Send a message directly to the command centre.
    show word gs-dpt-file-name " opened."

    ;; Write the system parameter settings to the file.
    f-write-system-settings
    
    ;; Write header records to the file.
    f-write-dpt-headers
  ]
  ;; else
  [
    ;; Send a message directly to the command centre.
    show word gs-dpt-file-name " not opened.  Writing dpt data cancelled."
  
    set gb-dpt-on 0
    set gs-dpt-status "0 (Off)"
    set gs-dpt-file-name "DptDummyName"
  ]
  
  ;; End of f-open-dpt-file
end 

;;-----------------------------------------------------------------------------|
;; Write the header records for the dpt data file.

to f-write-dpt-headers
  ;; This routine is to be executed by the observer.

  ;; Select the file
  file-open gs-dpt-file-name
  
  ;; Write a header record for general macro-level data. 
  f-write-dpt-a-header
  
  ;; Write headers for data collected per HOAM.
  f-write-dpt-x-hoam-header "DPT-C" "Ave Mass per HOAM"
  f-write-dpt-x-hoam-header "DPT-E" "Ave Low-grade energy per HOAM"
  f-write-dpt-x-hoam-header "DPT-G" "Ave High-grade energy transferred"
  f-write-dpt-x-hoam-header "DPT-I" "Ave Low-grade energy exhausted"
  
  ;; Write headers for data collected per OAM.
  f-write-dpt-x-oam-header "DPT-K" "Ave High-grade energy per OAM"
  f-write-dpt-x-oam-header "DPT-M" "GeoAve Mj per OAM"
  f-write-dpt-x-oam-header "DPT-O" "GeoAve Mt per OAM"
  f-write-dpt-x-oam-header "DPT-Q" "GeoAve Eu per OAM"
  
  ;; Write header for data associated with switches that may be flipped.
  f-write-dpt-u-header
  
  ;; End of f-write-dpt-headers
end 

;;-----------------------------------------------------------------------------|
;; Write the header record, the DPT-A record type.

to f-write-dpt-a-header
  ;; This routine is to be executed by the observer.

  ;; Select the file
  file-open gs-dpt-file-name
  
  ;; Write a header record for general macro-level data. 
  let line-out "DPT-A, "
  set line-out ( word line-out "RecNo, " )
  set line-out ( word line-out "Tick, " )
  
  set line-out ( word line-out "g-no-of-chains, " )
  set line-out ( word line-out "Ave drop time of chains, " )
  set line-out ( word line-out "Geo Ave Mj, " )
  set line-out ( word line-out "Geo Ave Mt, " )
  set line-out ( word line-out "Geo Ave Eu " )

  file-print line-out

  ;;End of f-write-dpt-a-header
end 
  
;;-----------------------------------------------------------------------------|
;; Write the header record, the DPT-X record type, per HOAM.

to f-write-dpt-x-hoam-header [ s-rectype s-recname ]
  ;; This routine is to be executed by the observer.

  ;; Select the file
  file-open gs-dpt-file-name
  
  ;; Write a header record for averages by HOAM type. 
  let line-out ( word s-rectype ", " )
  set line-out ( word line-out "RecNo, " )
  set line-out ( word line-out "Tick, " )
  set line-out ( word line-out s-recname " " )
  
  let hoam-index 0
  while [  hoam-index < g-length-of-chains ]
  [
    set line-out ( word line-out ", HOAM " hoam-index " " )
        
    set hoam-index ( hoam-index + 1 )
  ]

  file-print line-out

  ;; End of f-write-dpt-x-hoam-header
end 
  
;;-----------------------------------------------------------------------------|
;; Write the header record, the DPT-X record type, per OAM.

to f-write-dpt-x-oam-header [ s-rectype s-recname ]
  ;; This routine is to be executed by the observer.

  ;; Select the file
  file-open gs-dpt-file-name
  
  ;; Write a header record for averages by OAM type. 
  let line-out ( word s-rectype ", " )
  set line-out ( word line-out "RecNo, " )
  set line-out ( word line-out "Tick, " )
  set line-out ( word line-out s-recname " " )
  
  let oam-index 0
  while [ oam-index < ( g-length-of-chains - 1 ) ]
  [
    set line-out ( word line-out ", OAM " oam-index " " )
    set oam-index ( oam-index + 1 )
  ]

  file-print line-out

  ;; End of f-write-dpt-x-oam-header
end 
  
;;-----------------------------------------------------------------------------|
;; Write the header record, the DPT-U record type.

to f-write-dpt-u-header
  ;; This routine is to be executed by the observer.

  ;; Select the file
  file-open gs-dpt-file-name
  
  ;; Write a header record for general macro-level data. 
  let line-out "DPT-U, "
  set line-out ( word line-out "RecNo, " )
  set line-out ( word line-out "Tick, " )
  ;; 
  set line-out ( word line-out "g-no-of-chains-max, " )
  set line-out ( word line-out "g-length-of-chains, " )
  set line-out ( word line-out "g-drop-distance, " )
  set line-out ( word line-out "g-acceleration, " )
  set line-out ( word line-out "gb-mutate-heads, " )
  set line-out ( word line-out "gb-mutate-tails " )
  file-print line-out
  
  ;; End of f-write-dpt-u-header
end 

;;-----------------------------------------------------------------------------|
;; Write the data records for the dpt data file.

to f-write-dpt-macro-data
  ;; This routine is to be executed by the observer.

  ;; Select the file
  file-open gs-dpt-file-name
  
  ;; Write a data record for general macro-level data. 
  f-write-dpt-a-data
  
  ;; Write data collected per HOAM.
  f-write-dpt-x-hoam-data "DPT-D" "Ave Mass per HOAM" gl-ttl-mass-per-hoam
  f-write-dpt-x-hoam-data "DPT-F" "Ave Low-grade energy per HOAM" gl-ttl-lg-nrg-per-hoam
  f-write-dpt-x-hoam-data "DPT-H" "Ave Hg energy transferred" gl-ttl-hg-nrg-per-tick
  f-write-dpt-x-hoam-data "DPT-J" "Ave Lg energy exhausted" gl-ttl-lg-nrg-per-tick
  
  ;; Write data collected per OAM.
  f-write-dpt-x-oam-data "DPT-L" "Ave High-grade energy per OAM" gl-ttl-hg-nrg-per-oam
  f-write-dpt-x-oam-data "DPT-P" "Geo Ave Mt" gl-geo-Mt-per-oam
  f-write-dpt-x-oam-data "DPT-N" "Geo Ave Eu" gl-geo-Eu-per-oam 
  f-write-dpt-x-oam-data "DPT-T" "Geo Ave Mj" gl-geo-Mj-per-oam
  
  ;; Write data associated with switches that may be flipped.
  f-write-dpt-u-data
  
  ;; End of f-write-dpt-macro-data
end 

;;-----------------------------------------------------------------------------|
;; Write the data record, the dpt-a data record.

to f-write-dpt-a-data
  ;; This routine is to be executed by the observer.

  ;; Select the file
  file-open gs-dpt-file-name
  
  ;; Increment the record number.
  set g-dpt-recno ( g-dpt-recno + 1 )

  ;; Write a data record for general macro-level data. 
  let line-out "DPT-B, "
  set line-out ( word line-out g-dpt-recno ", " )
  set line-out ( word line-out ticks ", " )
  
  let value-out 0

  set line-out ( word line-out g-no-of-chains ", " )

  set value-out ( g-ttl-dt-of-chains / g-no-of-chains )
  set line-out ( word line-out value-out ", " )

  set value-out g-geo-Mj
  set line-out ( word line-out value-out ", " )

  set value-out g-geo-Mt
  set line-out ( word line-out value-out ", " )

  set value-out g-geo-Eu
  set line-out ( word line-out value-out " " )

  file-print line-out
  
  ;; End of f-write-dpt-a-data
end 

;;-----------------------------------------------------------------------------|
;; Write the data record, the DPT-X record type, per HOAM.

to f-write-dpt-x-hoam-data [ s-rectype s-recname this-list ]
  ;; This routine is to be executed by the observer.

  ;; Select the file
  file-open gs-dpt-file-name
  
  ;; Increment the record number.
  set g-dpt-recno ( g-dpt-recno + 1 )

  ;; Write a data record for averages per HOAM. 
  let line-out ( word s-rectype ", " )
  set line-out ( word line-out g-dpt-recno ", " )
  set line-out ( word line-out ticks ", " )
  
  set line-out ( word line-out s-recname " " )
  
  let value-out 0   ;; Dummy declaration
  let hoam-index 0
  while [  hoam-index < g-length-of-chains ]
  [
    set value-out ( item hoam-index this-list )
    set value-out ( value-out / g-no-of-chains )
    set line-out ( word line-out ", " value-out " " )
        
    set hoam-index ( hoam-index + 1 )
  ]

  file-print line-out

  ;; End of f-write-dpt-x-hoam-data
end 
  
;;-----------------------------------------------------------------------------|
;; Write the data record, the DPT-X record type, per OAM.

to f-write-dpt-x-oam-data [ s-rectype s-recname this-list ]
  ;; This routine is to be executed by the observer.

  ;; Select the file
  file-open gs-dpt-file-name
  
  ;; Increment the record number.
  set g-dpt-recno ( g-dpt-recno + 1 )
  
  ;; Write a header record for averages by OAM type. 
  let line-out ( word s-rectype ", " )
  set line-out ( word line-out g-dpt-recno ", " )
  set line-out ( word line-out ticks ", " )
  
  set line-out ( word line-out s-recname " " )
  
  let value-out 0  ;; Dummy declaration.
  let oam-index 0
  while [ oam-index < ( g-length-of-chains - 1 ) ]
  [
    set value-out ( item oam-index this-list )
    set value-out ( value-out / g-no-of-chains )
    set line-out ( word line-out ", " value-out " " )
    
    set oam-index ( oam-index + 1 )
  ]

  file-print line-out

  ;; End of f-write-dpt-x-oam-data
end 
  
;;-----------------------------------------------------------------------------|
;; Write the data record, the DPT-V record type.

to f-write-dpt-u-data
  ;; This routine is to be executed by the observer.

  ;; Select the file
  file-open gs-dpt-file-name
  
  ;; Increment the record number.
  set g-dpt-recno ( g-dpt-recno + 1 )

  ;; Write a data record for quasi-variable switches. 
  let line-out "DPT-V, "
  set line-out ( word line-out g-dpt-recno ", " )
  set line-out ( word line-out ticks ", " )
  
  set line-out ( word line-out g-no-of-chains-max ", " )
  set line-out ( word line-out g-length-of-chains ", " )
  set line-out ( word line-out g-drop-distance ", " )
  set line-out ( word line-out g-acceleration ", " )
  set line-out ( word line-out gb-mutate-heads ", " )
  set line-out ( word line-out gb-mutate-tails " " )
  file-print line-out
  
  ;; End of f-write-dpt-u-data
end 

;;-----------------------------------------------------------------------------|
;; Close the dpt file.

to f-close-dpt-file
  ;; This routine is to be executed by the observer.
  
  ;; DPT stands for 'Data Per Tick'
  if ( Is-string? gs-dpt-file-name )
  [
    if ( file-exists? gs-dpt-file-name )
    [
      ;; Select the file
      file-open gs-dpt-file-name
      ;; Close it.
      file-close
    ]
  ]
  set gb-dpt-on 0
  set gs-dpt-status "0 (Off)"
  set gs-dpt-file-name "DptDummyName"
  set g-dpt-recno 0
  
  ;; End of f-close-dpt-file
end 

;;-----------------------------------------------------------------------------|
;; Close and reopen the dpt file, it is too full.

to f-reopen-dpt-file
  ;; This routine is to be executed by the observer.
  
  f-close-dpt-file
  f-open-dpt-file

  ;; End of f-reopen-dpt-file
end 

;;-----------------------------------------------------------------------------|
;; Construct a CSV data file name.

to-report fr-construct-file-name [ type-string ]
  ;; This routine is to be executed by the observer.
  ;;
  ;; Date-string format "01:19:36.685 PM 19-Sep-2002"
  let date-string date-and-time
  let file-name ( word "OamLab_" type-string "_" )
  ;; Append the year as yy.
  set file-name word file-name ( substring date-string 25 27 )
  ;; Append the month as Mmm.
  set file-name word file-name fr-convert-mmm-mm ( substring date-string 19 22 )
  ;; Append the day as dd.
  set file-name word file-name ( substring date-string 16 18 )
  ;; Append a dash.
  set file-name word file-name "_"

  ;; Append the hour as hh.
  set file-name word file-name fr-convert1224 ( substring date-string 0 2 ) ( substring date-string 13 15 )
  ;; Append the minute as mm.
  set file-name word file-name ( substring date-string 3 5 )
  ;; Append the second as ss.
  set file-name word file-name ( substring date-string 6 8 )
  ;; Append the .csv extension.
  set file-name word file-name ".csv"

  report file-name
  
  ;; End of fr-construct-file-name
end 



;;-----------------------------------------------------------------------------|
;; DEBUG AND DEBUG LOG FILE MANAGEMENT FUNCTIONS
;;-----------------------------------------------------------------------------|

;;-----------------------------------------------------------------------------|
;; Open a log file for debug output.

to f-open-log-file
  ;; This routine is to be executed by the observer.
  
  ;; Ensure previous log file is closed.
  if ( is-string? gs-log-file-name )
  [
    if ( file-exists? gs-log-file-name )
    [
      file-close-all
    ]
  ]
  
  ;; Date-string format "01:19:36.685 PM 19-Sep-2002"
  let date-string date-and-time
  set gs-log-file-name "OamLab_Log_"
  ;; Append the year as yy.
  set gs-log-file-name word gs-log-file-name ( substring date-string 25 27 )
  ;; Append the month as Mmm.
  set gs-log-file-name word gs-log-file-name fr-convert-mmm-mm ( substring date-string 19 22 )
  ;; Append the day as dd.
  set gs-log-file-name word gs-log-file-name ( substring date-string 16 18 )
  ;; Append a dash.
  set gs-log-file-name word gs-log-file-name "_"

  ;; Append the hour as hh.
  set gs-log-file-name word gs-log-file-name fr-convert1224 ( substring date-string 0 2 ) ( substring date-string 13 15 )
  ;; Append the minute as mm.
  set gs-log-file-name word gs-log-file-name ( substring date-string 3 5 )
  ;; Append the second as ss.
  set gs-log-file-name word gs-log-file-name ( substring date-string 6 8 )
  ;; Append the .txt extension.
  set gs-log-file-name word gs-log-file-name ".txt"

  file-open gs-log-file-name
  file-show "Log File for a OamLab (NetLogo) Model."
  file-show word "File Name: " gs-log-file-name
  file-show word "File opened at:" date-and-time
  file-show ""
  
  ;; Send a message directly to the command centre.
  ifelse ( file-exists? gs-log-file-name )
  [
    show word gs-log-file-name " opened."
  ]
  [
    show word gs-log-file-name " not opened."
  ]
  
  ;; End of f-open-log-file
end 

;;-----------------------------------------------------------------------------|
;; Convert month in text form to digital form.

to-report fr-convert-mmm-mm [ mmm ]
  ;; This routine is to be executed by the observer.
  ;; It converts a string in the form mmm ( alpha text ) to the form mm ( digit-text ).
  
  let mm "00"
  if( mmm = "Jan" ) [ set mm "01" ]
  if( mmm = "Feb" ) [ set mm "02" ]
  if( mmm = "Mar" ) [ set mm "03" ]
  if( mmm = "Apr" ) [ set mm "04" ]
  if( mmm = "May" ) [ set mm "05" ]
  if( mmm = "Jun" ) [ set mm "06" ]
  if( mmm = "Jul" ) [ set mm "07" ]
  if( mmm = "Aug" ) [ set mm "08" ]
  if( mmm = "SeP" ) [ set mm "09" ]
  if( mmm = "Oct" ) [ set mm "10" ]
  if( mmm = "Nov" ) [ set mm "11" ]
  if( mmm = "Dec" ) [ set mm "12" ]
  report mm
  
  ;; End of fr-convert-mmm-mm
end 

;;-----------------------------------------------------------------------------|
;; Convert hour in 12 format to 24 hour format.

to-report fr-convert1224 [ hh ampm ]
  ;; This routine is to be executed by the observer.
  ;; It converts a string in 12 hour format to 24 hour format.
  
  let hour read-from-string hh
  if( ampm = "PM" ) [ set hour ( hour + 12 ) ]
  
  let dd ( word "00" hour )
  let d2 last dd
  set dd but-last dd
  let d1 last dd
  set dd ( word d1 d2 )
  report dd
  
  ;; End of fr-convert1224
end 

;;-----------------------------------------------------------------------------|
;; Close a log file for debug output.

to f-close-log-file
  ;; This routine is to be executed by the observer.
  
  let b-filename-exists 0
  if ( is-string? gs-log-file-name ) 
  [
    if ( file-exists? gs-log-file-name )
    [
      set b-filename-exists 1
    ]
  ] 

  ifelse( b-filename-exists = 1 )
  [
    ;; Ensure the file is selected.
    file-open gs-log-file-name
      
    ;; Stanp it.
    LOG-TO-FILE word "File closed at: " date-and-time
      
    ;; Flush the buffers.
    file-flush 
      
    ;; Close it.
    file-close-all
      
    ;; Note sent to command centre.
    show word gs-log-file-name " closed."
    
    ;; Revert to dummy name.
    set gs-log-file-name "dummyname"
  ]
  [
    if( gs-log-file-name = "dummyname" )
      [ show "No log file is open.  Cannot close it." ]
  ]
  
  ;; End of f-close-log-file
end 

;;-----------------------------------------------------------------------------|
;; Select an already opened log file.

to f-select-log-file
  ;; This routine is to be executed by the observer.
  
  ifelse ( file-exists? gs-log-file-name )
  [
    ;; Ensure the file is selected.
    file-open gs-log-file-name
    
    ;; Ensure it is open for writing.
    LOG-TO-FILE ""
    LOG-TO-FILE "SELECTED"    
  ]
  [
    show word gs-log-file-name " is not open.  Cannot select it."
  ]
  
  ;; End of f-select-log-file
end 

;;-----------------------------------------------------------------------------|
;; Change the debug mode from on to off, or vice versa.

to f-toggle-debug
  ;; This routine is to be executed by the observer, and is activated by a 
  ;;   button.
  
  ifelse( gb-debug-on = 1 )
  [
    ;; Debug is On, turn it Off.
    ;; Close the file before turning debug logging off.
    f-close-log-file
    set gs-debug-status "0 (Off)"  ;; This appears in the monitor.
    set gb-debug-on 0              ;; But this controls the debug feature.
  ]
  [
    ;; Debug is Off, turn it On.
    set gs-debug-status "1 (On)"   ;; This appears in the monitor.
    set gb-debug-on 1              ;; But this controls the debug feature.
    ;; The switches, if needed, are reset manually by the user.
    ;; Open the log file after turning debug logging on.
    f-open-log-file
  ]
  
  ;; End of f-toggle-debug
end 

;;-----------------------------------------------------------------------------|
;; 'Show' a string in a debug log.

to LOG-TO-FILE [ log-this-string ]
  ;; This routine may be executed by observer or turtle.
  ;; It should be invoked as a debug routine only, and would not be used for 
  ;;    normal output.  It sends output to the debug log file, or, optionally,
  ;;    also to the command centre.
  
  ;; gb-debug-on is a global Boolean and has value 1 (true) or 0 (false).
  if( gb-debug-on = 1 )
  [
    ;; gb-debug-flow-on is declared as a global Boolean variable, and its value 
    ;;   is 0 ( false ) or 1 ( true ) and is set on or off at the beginning of each 
    ;;   function ( each do-step ).  It is controlled by the chooser that selects 'all' 
    ;;   or a specific do-function.
    ;; 
    ;; When it is 'on' you can assume the debug log file exists and is open for
    ;;   write.
    
    if( gb-debug-flow-on = 1 )
    [
      file-show log-this-string
      show log-this-string
    ] 
  ]
  
  ;; End of LOG-TO-FILE
end 

;;-----------------------------------------------------------------------------|
;; This replicates the effect of an 'ASSERTION' in C++

to ASSERT [ error-test error-string error-who ]
;; This routine can be run by any of observer or turtle (I think).

if( error-test = false )
[
  show ( word error-test " " error-string " " error-who )
  ;; Cause a run-time error and display a message.
  error ( word "Agent: " error-who " - " error-string )
]

  ;; End of ASSERT
end 


;;-----------------------------------------------------------------------------|
;; Check whether the agents are all valid.

to-report frb-agents-are-all-valid 
;; This routine can be run by the observer.

  let b-agents-are-all-valid true
  
  if( gb-debug-on = 1 )
  [
    ;; Do the check only if debug is on.
    
    ;; Check the heads.
    ask heads
    [
      if( frb-head-is-valid = false ) [ set b-agents-are-all-valid false ]
    ]
    
    ;; Check the bodies.
    ask bodies
    [
      if( frb-body-is-valid = false ) [ set b-agents-are-all-valid false ]
    ]
    
    ;; Check the tails.
    ask tails
    [
      if( frb-tail-is-valid = false ) [ set b-agents-are-all-valid false ]
    ]
  ]
  
  report b-agents-are-all-valid
  
  ;; End of frb-agents-are-all-valid
end 

;;-----------------------------------------------------------------------------|
;; Check whether a head is valid.

to-report frb-head-is-valid 
;; This routine can be run by a head.

  let b-head-is-valid true
  
  if( index-into-chains-lib < 0 ) 
  [ 
    set b-head-is-valid false 
    LOG-TO-FILE ( word "index-into-chains-lib = " index-into-chains-lib "; at tick = " ticks )
  ]
  
  report b-head-is-valid
  
  ;; End of frb-head-is-valid
end 

;;-----------------------------------------------------------------------------|
;; Check whether a body is valid.

to-report frb-body-is-valid 
;; This routine can be run by a body.

  let b-body-is-valid true

  if( mass < 0 ) 
  [ 
    set b-body-is-valid false 
    LOG-TO-FILE ( word "mass = " mass "; at tick = " ticks )
  ]
  
  report b-body-is-valid
  
  ;; End of frb-body-is-valid
end 

;;-----------------------------------------------------------------------------|
;; Check whether a tail is valid.

to-report frb-tail-is-valid 
;; This routine can be run by a tail.

  let b-tail-is-valid true
  if( mass < 0 ) 
  [ 
    set b-tail-is-valid false 
    LOG-TO-FILE ( word "mass = " mass "; at tick = " ticks )
  ]
 
  report b-tail-is-valid
  
  ;; End of frb-tail-is-valid
end 

;;-----------------------------------------------------------------------------|
;; DISPLAY MONITOR MECHANISMS
;;-----------------------------------------------------------------------------|

;;-----------------------------------------------------------------------------|
;; Reports the fitness measure of the system based on the current choice of
;;   fitness measures, i.e. the active fitness regime.

to-report fr-get-active-fitness-measure 
  ;; This routine is to be executed by the observer.

  let active-fitness-measure 1
  
  if( g-fitness-number = 0 ) [ set active-fitness-measure g-geo-Mj ]
  if( g-fitness-number = 1 ) [ set active-fitness-measure g-geo-Mt ]
  if( g-fitness-number = 2 ) [ set active-fitness-measure g-geo-Eu ]
  
  report active-fitness-measure
  
  ;; End of fr-get-active-fitness-measure
end 

;;-----------------------------------------------------------------------------|
;; SPECIAL SCENARIO
;;-----------------------------------------------------------------------------|

;; This is for a special scenario in which all tails are the same, all heads
;;   are the same, and there is mixed efficiency at start.  There is a button
;;   that invokes the g-set-all-heads-at-max, a monitor that displays 
;;   g-max-all-heads, and an input control that allows you to choose what
;;   value all heads will be set to.  You are expected to set the chooser to
;;   'energy' fitness measure and 'Mixed Odum Efficiency' yourself. 

;;-----------------------------------------------------------------------------|
;;  This routine is used by a monitor to report the maximum mass in all heads.

to-report fr-get-max-head-size 
  ;; This routine is to be executed by the observer.

  set g-max-head-size ( max [mass] of heads )
  report g-max-head-size
  
  ;; End of fr-get-max-head-size
end 

;;-----------------------------------------------------------------------------|
;;  This routine is used by a monitor to report the minimum mass in all tails.

to-report fr-get-min-tail-size 
  ;; This routine is to be executed by the observer.

  set g-min-tail-size ( min [mass] of tails )
    
  report g-min-tail-size
  ;; End of fr-get-min-tail-size
end 

;;-----------------------------------------------------------------------------|
;;  This routine is used by a button to increase the size of the mass of 
;;    all heads to the value in an input box.

to f-make-all-heads-the-same 
;; This routine can be run by the observer.

  ;; Note the current value.
  let max-head-size-is ( fr-get-max-head-size )
  
  ;; Check whether a higher value has been entered into the input box.
  ifelse( g-set-max-head-size > max-head-size-is )
  [
    ;; Effect the change.
    ask heads
    [
      set mass ( g-set-max-head-size )
    ]
    ;; Recalculate all drop times, efficiencies, and fitness measures.
    f-compute-energetics-of-chains
    ;; Update the aggregates again, after energetics computed.
    f-update-aggregates  ;; Totals and averages.
    clear-all-plots
    setup-plots
   
    ;; Return the input box to its default status.
    set g-set-max-head-size -1
  ]
  ;; else
  [
    ;; Case of invalid input.
    ;; Return the input box to its default status.
    set g-set-max-head-size -2
  ]
  ;; End else

  ;; End of f-make-all-heads-the-same
end 

;;-----------------------------------------------------------------------------|
;; PLOT MANAGEMENT MECHANISMS
;;-----------------------------------------------------------------------------|

  ;; nil
  

There is only one version of this model, created over 8 years ago by Garvin Boyle.

Attached files

File Type Description Last updated
02 OamLab V1.10.png preview Preview for '02 OamLab V1.10' over 8 years ago, by Garvin Boyle Download
141129 NTF - NetLogo Stds for OrrerySW R2.pdf pdf Prepared standards for Orrery Software for NetLogo projects. over 8 years ago, by Garvin Boyle Download
150101 NTF Atwood's Machine R4.pdf pdf An analysis of the functioning of Atwood's Machine. over 8 years ago, by Garvin Boyle Download
150105 NTF AM Shape Study R1.pdf pdf A study of the shape of the power vs efficiency curve of Atwood's Machine. over 8 years ago, by Garvin Boyle Download
150113 NTF Atwoods Machine Revisited R4.pdf pdf More thoughts on the operations of Atwood's Machine as a model for energy transfers. over 8 years ago, by Garvin Boyle Download
150418 NTF Three Shapes of AM Revisited R2.pdf pdf A more detailed study of the power vs efficiency curves associated with Atwood's Machine. over 8 years ago, by Garvin Boyle Download
170328 NTF OamLab Change Diary.pdf pdf The most recent change diary. over 8 years ago, by Garvin Boyle Download
170330 NTF High-Level Design - OAMLab R5.pdf pdf A high-level technical description of the model. over 8 years ago, by Garvin Boyle Download

This model does not have any ancestors.

This model does not have any descendants.