Use of the online exposure age calculators as a web service

In addition to just responding to browser requests with web pages, the online exposure age calculators are more general “web services.” This means you can send them a HTTP request as if you were a web browser submitting a form, and they will respond with either a web page (a string of text in HTML format) or, alternatively, a string of text in XML format that is simpler for a program to extract desired information from.

For programmatic use, you most likely want the XML output. Nearly all programming languages have XML parsers that you can use to unpack the XML object and get useful information out of it.

The URLs for use of the calculators as a web service are http://hess.ess.washington.edu/cgi-bin/matweb for the original server at UW, or http://stoneage.ice-d.org/cgi-bin/matweb for the mirror.

Online exposure age calculator for mostly-spallogenic nuclides (not Cl-36)

The normal version of the online exposure age calculator computes exposure ages for He-3 in pyroxene or olivine as well as He-3, Be-10, C-14, Ne-21, and Al-26 in quartz. The fields that can be attached to an HTTP request to this calculator are as follows:

Field name Description
text_blockA text string containing input text in calculators v3 input format
mlmfile'age_input_v3' (identifies script to be used on server)
reportType'HTML' or 'XML' to control output format
plotFlag'yes' or 'no' to enable or disable plot generation
resultType'short' returns only results with time-constant ('St') scaling; 'long' includes time-dependent scaling results
summary'yes' or 'no' to enable or disable outlier detection, averaging, and summary plot generation

For example, suppose the request has the following field values (the single quotes are not part of the field values, they are just indicating that they are text strings):

text_block
'PH-1	41.3567	-70.7348	91	std	4.5	2.65	1	0.00008	1999;
PH-1	Be-10	quartz	123453	3717	KNSTD;
PH-1	Al-26	quartz	712408	31238	KNSTD;'
mlmfile'age_input_v3'
reportType'XML'
plotFlag'no'
resultType'long'
summary'no'

The XML response will be as follows:

<calcs_v3_age_data>
	<exposureAgeResult>
		<sample_name>PH-1</sample_name>
		<t10quartz_St>28196</t10quartz_St>
		<delt10quartz_int_St>871</delt10quartz_int_St>
		<delt10quartz_ext_St>2446</delt10quartz_ext_St>
		<Nnorm10quartz_St>27491</Nnorm10quartz_St>
		<delNnorm10quartz_int_St>828</delNnorm10quartz_int_St>
		<delNnorm10quartz_ext_St>2287</delNnorm10quartz_ext_St>
		<t10quartz_Lm>26948</t10quartz_Lm>
		<delt10quartz_int_Lm>832</delt10quartz_int_Lm>
		<delt10quartz_ext_Lm>2232</delt10quartz_ext_Lm>
		<Nnorm10quartz_Lm>26296</Nnorm10quartz_Lm>
		<delNnorm10quartz_int_Lm>792</delNnorm10quartz_int_Lm>
		<delNnorm10quartz_ext_Lm>2125</delNnorm10quartz_ext_Lm>
		<t10quartz_LSDn>28857</t10quartz_LSDn>
		<delt10quartz_int_LSDn>892</delt10quartz_int_LSDn>
		<delt10quartz_ext_LSDn>1963</delt10quartz_ext_LSDn>
		<Nnorm10quartz_LSDn>28110</Nnorm10quartz_LSDn>
		<delNnorm10quartz_int_LSDn>846</delNnorm10quartz_int_LSDn>
		<delNnorm10quartz_ext_LSDn>1862</delNnorm10quartz_ext_LSDn>
		<t26quartz_St>25713</t26quartz_St>
		<delt26quartz_int_St>1162</delt26quartz_int_St>
		<delt26quartz_ext_St>2990</delt26quartz_ext_St>
		<Nnorm26quartz_St>24975</Nnorm26quartz_St>	
		<delNnorm26quartz_int_St>1095</delNnorm26quartz_int_St>
		<delNnorm26quartz_ext_St>2761</delNnorm26quartz_ext_St>
		<t26quartz_Lm>24607</t26quartz_Lm>
		<delt26quartz_int_Lm>1110</delt26quartz_int_Lm>
		<delt26quartz_ext_Lm>2626</delt26quartz_ext_Lm>
		<Nnorm26quartz_Lm>23921</Nnorm26quartz_Lm>
		<delNnorm26quartz_int_Lm>1049</delNnorm26quartz_int_Lm>
		<delNnorm26quartz_ext_Lm>2481</delNnorm26quartz_ext_Lm>
		<t26quartz_LSDn>26056</t26quartz_LSDn>
		<delt26quartz_int_LSDn>1178</delt26quartz_int_LSDn>
		<delt26quartz_ext_LSDn>2592</delt26quartz_ext_LSDn>
		<Nnorm26quartz_LSDn>25288</Nnorm26quartz_LSDn>
		<delNnorm26quartz_int_LSDn>1109</delNnorm26quartz_int_LSDn>
		<delNnorm26quartz_ext_LSDn>2441</delNnorm26quartz_ext_LSDn>
	</exposureAgeResult>
	<diagnostics>
		No diagnostics
	</diagnostics>
	<version>
		<wrapper>3.0.2</wrapper>
		<validate>validate_v3_input.m - 3.0</validate>
		<get_age>3.0.2</get_age>
		<muons>1A, alpha = 1</muons>
		<consts>2020-08-26</consts>
	</version>
</calcs_v3_age_data>

The content of the XML response may vary depending on (i) the contents of the 'summarize' field; (ii) how many samples are present; (iii) whether there are multiple-nuclide data for any samples; and (iv) possibly other factors. It's probably a good idea to try out the expected possibilities that your code is expected to generate to make sure that you are getting the right information out of the XML.

Elements that are always present:

<exposureAgeResult>…</exposureAgeResult> elements. Each one of these blocks contains all the exposure-age results, for all scaling methods, with uncertainties, for one sample. In the example above, there is one sample with two measurements, and resultType was set to 'long', so there are three scaling methods. Each scaling method generates an age with internal and external uncertainties, so the exposure age results comprise 2 x 3 x 3 = 18 XML elements. The element tags contain the nuclide/mineral pair (t10quartz or t26quartz in this case), the scaling method ('St,' 'Lm,' 'LSDn') and what it is ('t' for age, 'del…int' for internal uncertainties, etc.). In this case there is one set of t10quartz results and one set of t26quartz results. If two Be-10 measurements were submitted for the same sample there would be two sets of t10quartz elements. In most cases, the <exposureAgeResult> element will also include normalized nuclide concentrations (the <Nnorm…> blocks for each scaling method), which can be used for plotting on a two-nuclide diagram.

<diagnostics>…</diagnostics> element. Contains either 'no diagnostics' or the error text that you would see in the normal exposure age calculator output.

<version>…</version> element. Contains identifying information for the various bits of code that were used for the calculation.

Elements that are sometimes present:

Blocks having to do with images generated on the remote server. If plotFlag is set, the XML will contain elements that look like this:

<ploturlstub>http://hess.ess.washington.edu/scratch/splotv3_355173</ploturlstub>

These contain URL stubs for plots that have been generated on the remote server. Add '.ps', '.gmt', or '.png' to the end to obtain the complete URL for the GMT script, Postscript image, or PNG image. These are the same plots that are normally generated by the online exposure age calculator. Note that they only live on the server for an hour before being deleted.

A block reporting summary data is present if 'summary' is set. Here is an example of what this would look like if you sent the input text from here with resultType = 'short' and summary = 'yes.'

<summary>
	<all>
		<St>
			<mean>1.7729e+04</mean>
			<sd>2.1628e+02</sd>
			<ewmean>1.7737e+04</ewmean>
			<ewse>1.5711e+02</ewse>
			<chi2>1.9938e+00</chi2>
			<dof>9.0000e+00</dof>
			<pchi2>9.9157e-01</pchi2>
			<text>All data: mean 17729; SD 216; chi-squared p-value is 0.9916....Pruned 0 outliers. ...Remaining data have p greater than 0.05; using error-weighted mean. ... Summary value is 17737 +/- 157 (1416)....If this is a moraine, the probability that it is Younger Dryas age is 0.00....The probability it belongs to the Antarctic Cold Reversal is 0.02.</text>
			<strip>
				<mean>1.7729e+04</mean>
				<sd>2.1628e+02</sd>
				<ewmean>1.7737e+04</ewmean>
				<ewse>1.5711e+02</ewse>
				<chi2>1.9963e+00</chi2>
				<dof>9.0000e+00</dof>
				<pchi2>9.9153e-01</pchi2>
			</strip>
			<sumval>1.7737e+04</sumval>
			<sumdel_int>1.5711e+02</sumdel_int>
			<sumdel_ext>1.4162e+03</sumdel_ext>
			<prob_ACR>1.5582e-02</prob_ACR>
			<prob_YD>3.0815e-04</prob_YD>
		</St>
	</all>
	<N10quartz>
		<St>
			<mean>1.7729e+04</mean>
			<sd>2.1628e+02</sd>
			<ewmean>1.7737e+04</ewmean>		
			<ewse>1.5711e+02</ewse>
			<chi2>1.9938e+00</chi2>	
			<dof>9.0000e+00</dof>
			<pchi2>9.9157e-01</pchi2>
			<text>All data: mean 17729; SD 216; chi-squared p-value is 0.9916....Pruned 0 outliers. ...Remaining data have p greater than 0.05; using error-weighted mean. ... Summary value is 17737 +/- 157 (1416)....If this is a moraine, the probability that it is Younger Dryas age is 0.00....The probability it belongs to the Antarctic Cold Reversal is 0.02.</text>
			<strip>
				<mean>1.7729e+04</mean>
				<sd>2.1628e+02</sd>
				<ewmean>1.7737e+04</ewmean>
				<ewse>1.5711e+02</ewse>
				<chi2>1.9963e+00</chi2>
				<dof>9.0000e+00</dof>
				<pchi2>9.9153e-01</pchi2>
			</strip>
			<sumval>1.7737e+04</sumval>
			<sumdel_int>1.5711e+02</sumdel_int>
			<sumdel_ext>1.4162e+03</sumdel_ext>
			<prob_ACR>1.5582e-02</prob_ACR>
			<prob_YD>3.0815e-04</prob_YD>
		</St>
	</N10quartz>
</summary>

To get an idea of what is in all these blocks, you can enter the same data into this page with the 'These data are from a single landform' box checked, and match the XML up with the grouped and labeled results. Setting summary to 'yes' and plotFlag to 'yes' should return URLs for the camel plots.

XML object if an error is encountered:

If the calculator code encounters an error in the input data, it should return a lot of zeros in the exposure age fields and a description of the error in the diagnostics field. Note that there may be a bug in which the XML tags containing zeros get scrambled, or only the diagnostics element might be present. A sensible fix would be to set an <error>…</error> block that would be easily recognized, but that has not been done. In any case, if you process the XML and you can't find any exposure ages greater than zero, that should be interpreted as an error and one would want to look in the diagnostics block to see what happened. In addition, there are some errors that will just cause the calculator to fail and return nothing, so there should be a timeout.

Example of how to do this in MATLAB

This example uses the MATLAB 'webread' function to interact with the web service. Of course, the calculations code is already written in MATLAB, so if you want to do this a lot (like hundreds or thousands of calculations at once) you could install that locally, which would be much faster. However, that can be kind of a pain in the neck for various reasons, so if you don't need to calculate exposure ages all that often, it is easy to use the web service.

Note that the example uses a hokey regular expression match to get the needed information out of the XML object. Recent versions of MATLAB have a real XML processor.

% Text string in version 3 format

text_string = ['PH-1	41.3567	-70.7348	91	std	4.5	2.65	1	0.00008	1999;' ...
    'PH-1	Be-10	quartz	123453	3717	KNSTD;' ...
    'PH-1	Al-26	quartz	712408	31238	KNSTD;'];

% URL of service
calc_url = 'http://hess.ess.washington.edu/cgi-bin/matweb';

% Script to run
calc_mfile = 'age_input_v3';

% Use webread with other inputs as name,value pairs
ages_xml = webread(calc_url,'mlmfile',calc_mfile,'text_block',text_string, ...
    'reportType','XML','resultType','long','plotFlag','no','summary','no');

% Hokey string matching to extract ages from XML
t10_string = regexp(ages_xml,['<t10quartz_St>(.*?)</t10quartz_St>'],'tokens');
t26_string = regexp(ages_xml,['<t26quartz_St>(.*?)</t26quartz_St>'],'tokens');
t10_string = t10_string{1}{1};
t26_string = t26_string{1}{1};

% Report
disp(['Be-10 exposure age is ' sprintf('%0.0f',str2num(t10_string))])
disp(['Al-26 exposure age is ' sprintf('%0.0f',str2num(t26_string))])

Example of how to do this in Python

The below uses urllib to talk to the calculator web service and then xml.etree to parse the XML. Works in Python 3.

import urllib.parse
import urllib.request
import xml.etree.ElementTree as et

# assemble form data

# s is a string in calculator input format

s = """PH-1 41.3567 -70.7348 91 std 4.5 2.65 1 0.00008 1999;
    PH-1 Be-10 quartz 123453 3717 KNSTD;
    PH-1 Al-26 quartz 712408 31238 KNSTD;"""


form_fields = {
	"mlmfile" : "age_input_v3",
	"reportType" : "XML",
	"resultType" : "long",
	"summary" : "no", 
	"plotFlag" : "no",
	"text_block" : s }

# Encode request
form_data = urllib.parse.urlencode(form_fields)
form_data = form_data.encode('ascii')

full_url = "http://hess.ess.washington.edu/cgi-bin/matweb"

# Send request
result = urllib.request.urlopen(full_url,form_data)

# Extract result
result_XML = result.read()

# Parse XML
tree = et.fromstring(result_XML)

# Spit out some results
for item in tree[0]:
	print(item.tag + ": " + item.text)

Online exposure age calculator for Cl-36

This is structured similarly to the above. The main differences in input fields are (i) of course the format for the input data is different; (ii) there is no 'resultType' switch to choose not to compute the time-dependent scaling results, and (iii) the value for 'mlmfile' needs to be different to send the request to a different script.

Field name Description
text_blockA text string containing input text in valid input form for Cl-36 data. This is explained here. Some examples are here and here.
mlmfile'Cl36_input_v3' (identifies script to be used on server)
reportType'HTML' or 'XML' to control output format
plotFlag'yes' or 'no' to enable or disable plot generation
summary'yes' or 'no' to enable or disable outlier detection, averaging, and summary plot generation

The main difference in output is that you will get different plots. Otherwise the structure of the XML is similar.

Note: this is only installed on stoneage.ice-d.org. It is not installed on hess.ess.washington.edu, so sending this request to http://hess.ess.washington.edu/cgi-bin/matweb will fail.

Online erosion rate calculator for mostly-spallogenic nuclides (not Cl-36)

Again, this is similar to the exposure age calculations described in detail above. The main difference in the input fields is that the 'summary' flag is not available.

Field name Description
text_blockA text string containing input text in valid v3 calculator input form. Note that this input format is the same for both exposure age and erosion rate calculations.
mlmfile'erosion_input_v3' (identifies script to be used on server)
reportType'HTML' or 'XML' to control output format
resultType'short' returns only results with time-constant ('St') scaling; 'long' includes time-dependent scaling results
plotFlag'yes' or 'no' to enable or disable plot generation

The XML output for erosion rate results is slightly different from the output for exposure-age results. If you send in the same example data from above:

PH-1	41.3567	-70.7348	91	std	4.5	2.65	1	0.00008	1999;
PH-1	Be-10	quartz	123453	3717	KNSTD;
PH-1	Al-26	quartz	712408	31238	KNSTD;

The XML result is as follows:

<calcs_v3_erosion_data>
	<erosionRateResult>
		<sample_name>PH-1</sample_name>
		<sample_density>2.65</sample_density>
		<nuclide_result>
			<nuclide>N10quartz</nuclide>	
			<E_gcm2_St>7.0664e-03</E_gcm2_St>
			<delE_gcm2_St>2.1517e-04</delE_gcm2_St>
			<delE_gcm2_St>6.0417e-04</delE_gcm2_St>
			<E_gcm2_Lm>7.3190e-03</E_gcm2_Lm>
			<delE_gcm2_Lm>2.2277e-04</delE_gcm2_Lm>
			<delE_gcm2_Lm>5.9797e-04</delE_gcm2_Lm>
			<E_gcm2_LSDn>6.8713e-03</E_gcm2_LSDn>
			<delE_gcm2_LSDn>2.0929e-04</delE_gcm2_LSDn>
			<delE_gcm2_LSDn>4.6044e-04</delE_gcm2_LSDn>
		</nuclide_result>
		<nuclide_result>
			<nuclide>N26quartz</nuclide>
			<E_gcm2_St>7.7150e-03</E_gcm2_St>
			<delE_gcm2_St>3.4519e-04</delE_gcm2_St>
			<delE_gcm2_St>8.8852e-04</delE_gcm2_St>
			<E_gcm2_Lm>7.9934e-03</E_gcm2_Lm>
			<delE_gcm2_Lm>3.5739e-04</delE_gcm2_Lm>
			<delE_gcm2_Lm>8.4543e-04</delE_gcm2_Lm>
			<E_gcm2_LSDn>7.5758e-03</E_gcm2_LSDn>
			<delE_gcm2_LSDn>3.3908e-04</delE_gcm2_LSDn>
			<delE_gcm2_LSDn>7.4651e-04</delE_gcm2_LSDn>
		</nuclide_result>
	</erosionRateResult>
	<diagnostics>No diagnostics</diagnostics>
	<version>
		<wrapper>3.0</wrapper>
		<validate>validate_v3_input.m - 3.0</validate>
		<erates>3.0</erates>
		<muons>3.1</muons>
		<consts>2020-08-26</consts>
	</version>
</calcs_v3_erosion_data>

The main difference is that each result from a different nuclide concentration measurement is in its own <nuclide_result>…</nuclide_result> block within the <erosionRateResult>…</erosionRateResult> block that corresponds to the sample. That is, you have to go down one more level to get the erosion rate results. Of course this is a better way to organize it than was originally used in the exposure age XML result. The exposure-age XML should be fixed, but that's a hassle because downstream code that uses it will also have to be fixed.

This only returns results as mass erosion rates with units of g/cm2. This is because that's the thing that you actually measured. It also returns whatever density you input for each sample so that there is enough information within the XML response to convert to linear units (e.g., m/Myr).

At the moment this doesn't return normalized nuclide concentrations (Nnorm…) for plotting on two-isotope diagrams. That's mainly because it's not really clear how to calculate these for erosion-rate data.

Note: there is no erosion rate calculation service for Cl-36.

Online exposure age calculator for mostly-spallogenic nuclides (not Cl-36), used for production rate calibration

The (non-Cl-36) exposure age calculator can also be used in reverse mode for production rate calibration by setting the mlmfile field to 'cal_input_v3'.

This requires different input that includes the independent age information. Suitable calibration data in the correct input format can be obtained from http://calibration.ice-d.org. It also generates different output – obviously, the XML will contain production rate estimates for each sample, not exposure ages.

Note: you can only calibrate the production rate for one nuclide at a time. So the input data can only have measurements of one nuclide; otherwise generates an error.

Here is an example in MATLAB that (i) scrapes calibration data in the appropriate input form from the ICE-D:CALIBRATION website; (ii) sends those data to the web service to generate calibrated production rate parameters; and (iii) uses those calibrated parameters to calculate exposure ages of some unknown-age data.

This is somewhat complicated but if you are familiar with how the exposure age calculators work, and have gotten through all the previous examples, it should be fairly straightforward.

% This gets calibration data from the ICE-D:CALIBRATION website, obtains
% calibrated production rate parameters with it, and uses those calibrated
% production rate parameters to compute exposure ages at an unknown-age
% site. 

clear all;

% Get some calibration data from the calibration website

cal_page_html = webread('http://calibration.ice-d.org/cds/1');

% Note: this input data must include data for only one nuclide

% Scrape the formatted text block out of the HTML
startindex = strfind(cal_page_html,'<!-- begin v3 --><pre>') + length('<!-- begin v3 --><pre>');
endindex = strfind(cal_page_html,'</pre><!-- end v3 -->') - 1;
cal_input_text = cal_page_html(startindex:endindex);

%% Send that to the online calculator and get calibration results

url = "http://hess.ess.washington.edu/cgi-bin/matweb";
cal_xml_result = webread(url,'mlmfile','cal_input_v3','reportType','XML','plotFlag','no','text_block',cal_input_text);

% Extract calibration information from XML. This is a stupid regexp
% matching scheme. In MATLAB R2021 you can use the proper XML parser. 

% First, get the name of the nuclide -- eventually you will have to send this to the
% calibration code, because you can only do a calibration for one nuclide
% at a time. 

temp = regexp(cal_xml_result,['<nuclide>(.*?)</nuclide>'],'tokens');
nuclide_string = temp{1}{1};

% Get calibrated production rate parameters
% Obviously, the below could be shortened by looping over scaling methods
temp = regexp(cal_xml_result,['<summary_value_St>(.*?)</summary_value_St>'],'tokens');
value_St_string = temp{1}{1};
temp = regexp(cal_xml_result,['<summary_uncert_St>(.*?)</summary_uncert_St>'],'tokens');
uncert_St_string = temp{1}{1};
temp = regexp(cal_xml_result,['<summary_value_Lm>(.*?)</summary_value_Lm>'],'tokens');
value_Lm_string = temp{1}{1};
temp = regexp(cal_xml_result,['<summary_uncert_Lm>(.*?)</summary_uncert_Lm>'],'tokens');
uncert_Lm_string = temp{1}{1};
temp = regexp(cal_xml_result,['<summary_value_LSDn>(.*?)</summary_value_LSDn>'],'tokens');
value_LSDn_string = temp{1}{1};
temp = regexp(cal_xml_result,['<summary_uncert_LSDn>(.*?)</summary_uncert_LSDn>'],'tokens');
uncert_LSDn_string = temp{1}{1};

%% Now we have the production rate parameters obtained from the calibration
% data. 

% Get some data from ICE-D:ALPINE to calculate the exposure age of

unknowns_page_html = webread('http://alpine.ice-d.org/site/BST');

% Get the formatted text out of the HTML 

startindex = strfind(unknowns_page_html,'<!-- begin v3 --><pre>') + length('<!-- begin v3 --><pre>');
endindex = strfind(unknowns_page_html,'</pre><!-- end v3 -->') - 1;
unknowns_input_text = unknowns_page_html(startindex:endindex);


%% Send sample info to exposure age calculator with additional options to
% force non-default Be-10 production rate

url = "https://hess.ess.washington.edu/cgi-bin/matweb";

unknowns_xml_result_calibrated = webread(url,'mlmfile','age_input_v3','reportType','XML','resultType','long','plotFlag','no',...
    'text_block',unknowns_input_text,...
    'trace_string','nothing here but this is required',...
    'calib_name','nothing here either but this is required too',...
    'nuclide_name',nuclide_string,...
    'P_St',value_St_string,'delP_St',uncert_St_string,...
    'P_Lm',value_Lm_string,'delP_Lm',uncert_Lm_string,...
    'P_LSDn',value_LSDn_string,'delP_LSDn',uncert_LSDn_string);

%% Here is what it would look like if we omit the additional calibration 
% parameters. In this case we get the results using the normal default
% production rate calibration. 

unknowns_xml_result_default = webread(url,'mlmfile','age_input_v3','reportType','XML','resultType','long','plotFlag','no',...
    'text_block',unknowns_input_text);

% We leave it as an exercise for the student to extract the exposure ages
% from unknowns_xml_result_calibrated and unknowns_xml_result_default, and
% verify that they are different.