Skip to content. | Skip to navigation


I've made my first novel, Ventus, available as a free download, as well as excerpts from two of the Virga books.  I am looking forward to putting up a number of short stories in the near future.

Complete novel:  Ventus


To celebrate the August, 2007 publication of Queen of Candesce, I decided to re-release my first novel as an eBook. You can download it from this page. Ventus was first published by Tor Books in 2000, and and you can still buy it; to everyone who would just like to sample my work, I hope you enjoy this version.

I've released this book under a Creative Commons license, which means you can read it and distribute it freely, but not make derivative works or sell it.

Book Excerpts:  Sun of Suns and Pirate Sun

I've made large tracts of these two Virga books available.  If you want to find out what the Virga universe is all about, you can check it out here:

Major Foresight Project:  Crisis in Zefra

In spring 2005, the Directorate of Land Strategic Concepts of National Defense Canada (that is to say, the army) hired me to write a dramatized future military scenario.  The book-length work, Crisis in Zefra, was set in a mythical African city-state, about 20 years in the future, and concerned a group of Canadian peacekeepers who are trying to ready the city for its first democratic vote while fighting an insurgency.  The project ran to 27,000 words and was published by the army as a bound paperback book.

If you'd like to read Crisis in Zefra, you can download it in PDF form.

Personal tools

Carbon Cycle Simulator File & Code

carbon_cycle.html — HTML, 7Kb

File contents

	Documentation for the LineChart API is here:
	<title>Carbon Exchange Cycle</title>
    <script type="text/javascript" src=""></script>
    <script type="text/javascript">
	var Parameters = 
		runtime: 20,	// length of simulation in years
		year: 2010,		// starting year
		temperature: 14,	// global average temperature (Celsius)
		temperatureAdjustmentDelay: 10, // delay in years taken for temperature to adjust to changes caused by Radiative Forcing
		atmosphericCO2: 824,	// 824 Gt (billion tonnes)
		emissionsCO2: 7.5, 	// net rate of 7.5 Gt/year of CO2 put into the atmosphere by human activity
		climateSensitivity: 1.46,	// parameter to Radiative Forcing equation (see wikipedia "Radiative Forcing")
		oceanSourcedCO2: 90, // 90 Gt/year from oceans
		oceanSinkedCO2: 92, // 92 Gt/year from oceans
		landSourcedCO2: 120, // 120 Gt/year from land
		landSinkedCO2: 120,	 // 120 Gt/year from land
		mitigationStartTime: 10,	// number of years into simulation at which point mitigation efforts begin
		reducedEmissionsCO2: 3,	// mitigated net rate of 3 Gt/year of CO2 put into the atmosphere by human activity
		artificialSinkedCO2: 0	// eg from carbon air capture or geo-engineering efforts

    google.load("visualization", "1", {packages:["linechart"]});
	function onReady()
		// init fields from param defaults
		for(var p in Parameters)
			var field = document.getElementById('text_' + p);
				field.value = Parameters[p];
		document.getElementById('buttonPlot').disabled = false;
	function onPlot()
		// update params from fields
		for(var p in Parameters)
			var field = document.getElementById('text_' + p);
				Parameters[p] = parseFloat(field.value);
	function runSimulation() {

		function co2Sources(t) { return oceanSources(t) + landSources(t) + co2Emissions(t); }
		function co2Sinks(t) { return oceanSinks(t) + landSinks(t) + artificialSinks(t); }
		function oceanSources(t) { return Parameters.oceanSourcedCO2; }
		function oceanSinks(t) { return Parameters.oceanSinkedCO2; }
		function landSources(t) { return Parameters.landSourcedCO2; }
		function landSinks(t) { return Parameters.landSinkedCO2; }

		function co2Emissions(t) { return t < Parameters.mitigationStartTime ? Parameters.emissionsCO2 : Parameters.reducedEmissionsCO2; }
		function artificialSinks(t) { return t < Parameters.mitigationStartTime ? 0 : Parameters.artificialSinkedCO2; }
		// compute temp difference due to Radiative Forcing (from wikipedia "Radiative Forcing")
		function tempChange(co2) { return Parameters.climateSensitivity * 5.35 * Math.log(co2/Parameters.atmosphericCO2); }
		function smooth(func, t, delay) {
			// compute a moving average of func, over the range of the delay
			var values = [];
			for(var i = t; i >= 0 && values.length <= delay; i--)
			return avg(values);

		var years = [Parameters.year];
		var co2s = [Parameters.atmosphericCO2];
		var temps = [Parameters.temperature];
		var dtemps = [0.0];

		for(var t=1; t < Parameters.runtime; t++)
			years[t] = years[t-1] + 1;
			var dco2 = co2Sources(t) - co2Sinks(t);
			co2s[t] = co2s[t-1] + dco2;
			dtemps[t] = tempChange(co2s[t]);
			// temperature does not "accumulate" - is always computed as offset from the starting temperature
			temps[t] = Parameters.temperature + smooth(function(t) { return dtemps[t]; }, t, Parameters.temperatureAdjustmentDelay);

			{ title: "Atmospheric CO2", xLabel: "year", yLabel: "co2 (Gt)" }
			{ title: "Temperature", xLabel: "year", yLabel: "temp (C)" }
		divContainer - HTML div element to hold the graph
		xSeries - array of data for x axis
		ySeries - array of data for y axis
		options - 
			xLabel - label for x axis
			yLabel - label for y axis
			other options as defined by linechart documentation (
	function plot(divContainer, xSeries, ySeries, options)
		var data = new google.visualization.DataTable();
		// set some default options if not specified
		options.width = options.width || 400;
		options.height = options.height || 240;
		options.titleX = options.titleX || options.xLabel;
		options.titleY = options.titleY || options.yLabel;
		options.legend = options.legend || 'none';

		// add a column for each data label
		data.addColumn('string', options.xLabel);
		data.addColumn('number', options.yLabel);
		// set number of rows
		// populate the table
		for(var i = 0; i < xSeries.length; i++)
			data.setValue(i, 0, xSeries[i].toString());
			data.setValue(i, 1, ySeries[i]);

		// draw the chart
		var chart = new google.visualization.LineChart(divContainer);
		chart.draw(data, options);
	function avg(values) {
		var sum = 0;
		for(var i = 0; i < values.length; i++)
			sum += values[i];
		return sum/values.length;

	Carbon Exchange Cycle simulation
			<td>Runtime (years):</td>
			<td><input id="text_runtime" type="text" size="2"/></td>
			<td>length of simulation in years</td>
			<td>Natural CO2 land sources (Gt/yr):</td>
			<td><input id="text_landSourcedCO2" type="text" size="2"/></td>
			<td>net rate of CO2 naturally sourced into the atmosphere from land</td>
			<td>Natural CO2 land sinks (Gt/yr):</td>
			<td><input id="text_landSinkedCO2" type="text" size="2"/></td>
			<td>net rate of CO2 naturally sinked into land</td>
			<td>Natural CO2 ocean sources (Gt/yr):</td>
			<td><input id="text_oceanSourcedCO2" type="text" size="2"/></td>
			<td>net rate of CO2 naturally sourced into the atmosphere from ocean</td>
			<td>Natural CO2 ocean sinks (Gt/yr):</td>
			<td><input id="text_oceanSinkedCO2" type="text" size="2"/></td>
			<td>net rate of CO2 naturally sinked into ocean</td>
			<td>CO2 emissions (Gt/yr):</td>
			<td><input id="text_emissionsCO2" type="text" size="2"/></td>
			<td>net rate of CO2 put into the atmosphere by human activity</td>
			<td>Mitigation efforts start time (year, 0 - runtime):</td>
			<td><input id="text_mitigationStartTime" type="text" size="2"/></td>
			<td>year at which mitigation efforts begin</td>
			<td>Reduced CO2 emissions (Gt/yr):</td>
			<td><input id="text_reducedEmissionsCO2" type="text" size="2"/></td>
			<td>net rate of CO2 put into the atmosphere by human activity, after reduction efforts implemented</td>
			<td>Artificial CO2 sinks (carbon air capture, geo-engineering) (Gt/yr):</td>
			<td><input id="text_artificialSinkedCO2" type="text" size="2"/></td>
			<td>net rate of CO2 removed from atmosphere by artifical means</td>
			<td>Temperature Adjustment Delay (years):</td>
			<td><input id="text_temperatureAdjustmentDelay" type="text" size="2"/></td>
			<td>delay in years for temperature to adjust to changes caused by CO2 concentration</td>
			<input id="buttonPlot" type="button" value="Plot" onclick="javascript:onPlot()" disabled="true"/>
    <span id="co2_div"></span>
    <span id="temp_div"></span>
Document Actions
« March 2017 »