Commits

petermr  committed d774fe9

created repository

  • Participants

Comments (0)

Files changed (20)

+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry excluding="main/java/org/xmlcml/declaratron/stmml/|main/|test/|main/java/|main/java/|test/java/|test/java/|main/resources/|main/resources/|test/resources/|test/resources/" kind="src" path="src"/>
+	<classpathentry kind="src" path="src/main/java"/>
+	<classpathentry kind="src" path="src/test/java"/>
+	<classpathentry kind="src" path="src/main/resources"/>
+	<classpathentry kind="src" path="src/test/resources"/>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+	<classpathentry kind="output" path="bin"/>
+</classpath>
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>declaratron-stm</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.m2e.core.maven2Builder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.m2e.core.maven2Nature</nature>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+	</natures>
+</projectDescription>

File .settings/org.eclipse.m2e.core.prefs

+#Tue Jan 22 17:15:37 GMT 2013
+activeProfiles=
+eclipse.preferences.version=1
+resolveWorkspaceProjects=true
+version=1

File bin/META-INF/declaratron

+org.xmlcml.cml.declaratron.chem.amber.AmberConverters

File bin/log4j.properties

+log4j.rootLogger=DEBUG, A1
+log4j.appender.A1=org.apache.log4j.ConsoleAppender
+log4j.appender.A1.layout=org.apache.log4j.PatternLayout
+log4j.appender.A1.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n
+log4j.logger.uk.ac.cam=DEBUG
+
+log4j.logger.org.xmlcml.cml.converters.marker = INFO

File bin/org/xmlcml/declaratron/chem/chemistry/classList.xml

+<classList>
+	<class tag="arrayTool"    name="org.xmlcml.cml.chemistry.ArrayToolVisitable" />
+	<class tag="atomTypeTool" name="org.xmlcml.cml.chemistry.AtomTypeToolVisitable" />
+	<class tag="energy"       name="org.xmlcml.cml.chemistry.EnergyVisitable" />
+	<class tag="geometry"     name="org.xmlcml.cml.chemistry.GeometryVisitable" />
+	<class tag="moleculeTool" name="org.xmlcml.cml.chemistry.MoleculeToolVisitable" />
+	<class tag="units"        name="org.xmlcml.cml.units.UnitsVisitor" />
+</classList>
+		

File bin/org/xmlcml/declaratron/stmml/stmml/ArrayToolVisitable.class

Binary file added.

File bin/org/xmlcml/declaratron/stmml/stmml/ArrayToolVisitorTest.class

Binary file added.

File bin/org/xmlcml/declaratron/stmml/stmml/CMLClassVisitor.class

Binary file added.

File bin/org/xmlcml/declaratron/stmml/stmml/TableToolVisitable.class

Binary file added.

File bin/org/xmlcml/declaratron/stmml/units/UnitsVisitor.class

Binary file added.
+<?xml version="1.0" encoding="UTF-8"?>
+<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>cml</groupId>
+        <artifactId>declaratron</artifactId>
+        <version>0.1-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>declaratron-stmml</artifactId>
+    <packaging>pom</packaging>
+    <name>declaratron-stmml</name>
+    
+
+    <dependencyManagement>
+        <dependencies>
+            <dependency>
+                <groupId>${jumbo.groupId}</groupId>
+                <artifactId>cmlxom</artifactId>
+                <version>${cmlxom.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>${jumbo.groupId}</groupId>
+                <artifactId>jumbo-testutil</artifactId>
+                <version>${jumbotestutil.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>${jumbo.groupId}</groupId>
+                <artifactId>jumbo</artifactId>
+                <version>${jumbo.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>log4j</groupId>
+                <artifactId>log4j</artifactId>
+                <version>1.2.13</version>
+            </dependency>
+            <dependency>
+                <groupId>xom</groupId>
+                <artifactId>xom</artifactId>
+                <version>1.2.5</version>
+            </dependency>
+
+<!-- the other declaratrons, core is essential, others are optional-->
+            <dependency>
+                <groupId>cml</groupId>
+                <artifactId>declaratron-core</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>junit</groupId>
+                <artifactId>junit</artifactId>
+                <version>4.8.2</version>
+            </dependency>
+            <dependency>
+                <groupId>org.mockito</groupId>
+                <artifactId>mockito-core</artifactId>
+                <version>1.8.0</version>
+            </dependency>
+        </dependencies>
+    </dependencyManagement>
+
+
+</project>
+
+

File src/main/java/org/xmlcml/declaratron/stmml/stmml/ArrayToolVisitable.java

+package org.xmlcml.declaratron.stmml.stmml;
+
+import java.util.ArrayList;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import nu.xom.Attribute;
+import nu.xom.Element;
+import nu.xom.Nodes;
+
+import org.xmlcml.cml.base.CMLElement;
+import org.xmlcml.cml.element.CMLArray;
+import org.xmlcml.cml.element.CMLList;
+import org.xmlcml.cml.tools.ArrayTool;
+import org.xmlcml.euclid.RealArray;
+import org.xmlcml.mathml.Context;
+import org.xmlcml.mathml.MathMLDoubleElement;
+import org.xmlcml.mathml.MathVisitable;
+import org.xmlcml.semantic.AbstractExecutableElement;
+import org.xmlcml.semantic.NodeUtils;
+import org.xmlcml.semantic.visitors.Executable;
+
+import scala.actors.threadpool.Arrays;
+
+public class ArrayToolVisitable extends AbstractExecutableElement implements Executable
+{
+	private static final String PARAMETER_SWEEP = "parameterSweep";
+	private static final String VAR = "var";
+	private static final String MATH_PATH = "//*[local-name()='math']";
+	private static final String PARAM = "param-";
+	private static final String FUNCTION_REF = "functionRef";
+	private static final String FUNCTION_VAR = "functionVar";
+	private static final String APPLY_FUNCTION = "applyFunction";
+	private static final String JUNK = "junk";
+	private static final String CREATE_DOUBLES = "createDoubles";
+	private static final String COUNT = "count";
+	private static final String DELTA = "delta";
+	private static final String START = "start";
+	
+	public static final String TAG = "arrayTool";
+
+	private List<CMLArray> arrayList;
+	private ArrayTool arrayTool;
+	private Integer count;
+	private Double start;
+	private Double delta;
+	private CMLArray array;
+	private String functionRef;
+	private Map<String, Double> paramValueMap;
+	private String functionVar;
+	private Map<Integer, String> varMap;
+	private Map<Integer, String> xpathMap;
+	private Element function;
+
+	public ArrayToolVisitable( )
+	{
+		this( new Element(TAG));
+	}
+
+	public ArrayToolVisitable( Element e )
+	{
+		super( e , TAG);
+		log.debug(e.toXML());
+	}
+
+	public Element runTreeVisit() {
+		processAttributes();
+		if (arrayList == null || arrayList.size() == 0) {
+			// these methods create an array
+			if (CREATE_DOUBLES.equals(method)) {
+				result = createDoubles();
+			} else if (PARAMETER_SWEEP.equals(method)) {
+				result = applyFunction();
+			} else {
+				
+			}
+		} else {
+			for (CMLArray a : arrayList) {
+				array = a;
+				arrayTool = ArrayTool.getOrCreateTool(array);
+				if (APPLY_FUNCTION.equals(method)) {
+					result = applyFunction();
+		  		} else {
+		  			throw new RuntimeException("Unknown method: "+method);
+		  		}
+			}
+		}
+		return result;
+	}
+
+	private Element applyFunction() {
+		getFunction();
+		getFunctionVars();
+		getVars();
+		getXPaths();
+		if (functionVar == null && varMap.size() == 0) {
+			throw new RuntimeException("Must give @functionVar or @var-n");
+		}
+		if (xpath == null && xpathMap.size() == 0) {
+			throw new RuntimeException("Must give @xpath or @xpath-n");
+		}
+		if (xpathMap.size() > 0 || varMap.size() > 0) {
+			return runSweep();
+		} else {
+			return runSingleParameter(array);
+		}
+	}
+
+	private Element runSweep() {
+		CMLList cmlList = new CMLList();
+		List<String> varList = makeList(varMap);
+		List<String> xpathList = makeList(xpathMap);
+		if (xpathList.size() != varList.size()){
+			throw new RuntimeException("vars ("+varList.size()+") do not match xpaths ("+xpathList.size()+")");
+		}
+		if (xpathList.size() != 2) {
+			throw new RuntimeException("Only 2-D sweep at present "+xpathList.size());
+		}
+		array = (CMLArray) CMLElement.createCMLElement((Element)this.query(xpathList.get(0)).get(0));
+		functionVar = varList.get(0);
+		CMLArray array1 = (CMLArray) CMLElement.createCMLElement((Element)this.query(xpathList.get(1)).get(0));
+		double[] doubles1 = array1.getDoubles();
+		for (Double d : doubles1) {
+			CMLArray newArray = runSingleParameter(array, varList.get(1), d);
+			cmlList.appendChild(newArray);
+		}
+		return cmlList;
+	}
+
+	private List<String> makeList(Map<Integer, String> map) {
+		Set<Integer> intSet = map.keySet();
+		List<Integer> intList = (List<Integer>) Arrays.asList(intSet.toArray(new Integer[0]));
+		Collections.sort(intList);
+		List<String> valueList = new ArrayList<String>();
+		int j = 1;
+		for (Integer ii : intList) {
+			if (ii !=j++) {
+				throw new RuntimeException("Missing number att name: "+ii+" != "+j);
+			}
+			valueList.add(map.get(ii));
+		}
+		return valueList;
+	}
+
+	private Element runSingleParameter(CMLArray theArray) {
+		return runSingleParameter(theArray, null, null);
+	}
+
+	private CMLArray runSingleParameter(CMLArray theArray, String pname, Double pval) {
+		Set<String> ciNames = MathVisitable.getCiNames(this, function, MATH_PATH);
+		if (functionVar != null) ciNames.add(functionVar);
+		checkEqualSets(ciNames, paramValueMap.keySet());
+		MathMLDoubleElement func = MathVisitable.getEvaluatableFunction(this, function, MATH_PATH);
+		Context mathContext = new Context();
+		if (pname != null) {
+			mathContext.setVar(pname,  pval);
+		}
+		for (String par : paramValueMap.keySet()) {
+			Double dd = paramValueMap.get(par);
+			mathContext.setVar(par, dd);
+		}
+		// capture results in realArray
+		RealArray realArray = new RealArray();
+		for (Double d : theArray.getDoubles()) {
+			// set value of current parameter
+			mathContext.setVar( functionVar, d);
+			Double dd = (Double) func.eval(mathContext);
+			realArray.addElement(dd);
+		}
+		CMLArray newArray = new CMLArray(realArray);
+		return newArray;
+	}
+
+	private boolean checkEqualSets(Set<String> varNames, Set<String> paramNames) {
+		boolean equals = true;
+		Set<String> varNames1 = new HashSet<String>(varNames);
+		Set<String> paramNames1 = new HashSet<String>(paramNames);
+		varNames1.removeAll(paramNames);
+		if (varNames1.size() > 0 ) {
+			equals = false;
+			log.error("ci names not found in parameters "+varNames1);
+		}
+		paramNames1.removeAll(varNames);
+		if (paramNames1.size() > 0 ) {
+			equals = false;
+			log.error("parameters don't map to ci names "+paramNames1);
+		}
+		return equals;
+	}
+
+	private Element getFunction() {
+		getFunctionRef();
+		if (functionRef == null) {
+			throw new RuntimeException("Must give @functionRef");
+		}
+		function = NodeUtils.getElementFromURL(functionRef);
+		if (function == null) {
+			throw new RuntimeException("Cannot find/parse: "+functionRef);
+		}
+		return function;
+	}
+
+	private Element createDoubles() {
+		array = new CMLArray();
+		arrayTool = ArrayTool.getOrCreateTool(array);
+		if (count == null) {
+			throw new RuntimeException("must give count for doubles");
+		}
+		start = (start == null) ? 0.0 : start;
+		delta = (delta == null) ? 0.0 : delta;
+		arrayTool.createDoubleArray(count, start, delta);
+		array = arrayTool.getArray();
+		return array;
+	}
+
+	private Integer getCount() {
+		count = getIntegerAttributeValue(COUNT);
+		return count;
+	}
+
+	private Double getDelta() {
+		delta = getDoubleAttributeValue(DELTA);
+		return delta;
+	}
+
+	private Double getStart() {
+		start = getDoubleAttributeValue(START);
+		return start;
+	}
+
+	private String getFunctionRef() {
+		functionRef = getAttributeValue(FUNCTION_REF);
+		return functionRef;
+	}
+
+	private String getFunctionVars() {
+		functionVar = getAttributeValue(FUNCTION_VAR);
+		return functionVar;
+	}
+	private void getParams() {
+		paramValueMap = new HashMap<String, Double>();
+		for (int i = 0; i < this.getAttributeCount(); i++) {
+			Attribute att = this.getAttribute(i);
+			String name = att.getLocalName();
+			if (name.startsWith(PARAM)) {
+				name = name.substring(PARAM.length());
+				String attValue =att.getValue();
+				try {
+					Double dValue = new Double(attValue);
+					paramValueMap.put(name, dValue);
+				} catch (Exception e) {
+					log.error("cannot parse parameter as double "+att);
+				}
+			}
+		}
+		System.err.println(paramValueMap);
+	}
+	
+	private void getVars() {
+		varMap = getNumberedAttributes(VAR+"-");
+	}
+
+	private void getXPaths() {
+		xpathMap = getNumberedAttributes(XPATH+"-");
+	}
+
+	private Map<Integer, String> getNumberedAttributes(String prefix) {
+		Map<Integer, String> map = new HashMap<Integer, String>();
+		for (int i = 0; i < this.getAttributeCount(); i++) {
+			Attribute att = this.getAttribute(i);
+			String localName = att.getLocalName();
+			if (localName.startsWith(prefix)) {
+				String name = localName.substring(prefix.length());
+				try {
+					String attValue = att.getValue();
+					Integer attInt = new Integer(name);
+					map.put(attInt, attValue);
+				} catch (Exception e){
+					throw new RuntimeException("Cannot parse as numbered attribute name: "+localName);
+				}
+			}
+		}
+		System.err.println(map);
+		return map;
+	}
+	
+	private void processAttributes() {
+
+		Element cmlContext = getComputationalContext();
+		getXpath(false);
+		getSetId();
+		getCount();
+		getDelta();
+		getMethod( true );
+		getStart();
+		getParams();
+		getFunctionVars();
+		if (cmlContext != null) {
+			List<Element> elements = queryElementsNS(cmlContext, xpath);
+			arrayList = CMLArray.extractArrays(elements);
+		} else {
+			if (xpath != null) {
+				Nodes nodes = this.query(xpath);
+				if (nodes.size() > 0) {
+					arrayList = new ArrayList<CMLArray>();
+					for (int i = 0; i < nodes.size(); i++) {
+						Element element = (Element) nodes.get(i);
+						CMLArray array = (CMLArray) CMLElement.createCMLElement(element);
+						if (array != null) {
+							arrayList.add(array);
+						}
+					}
+				}
+			}
+		}
+	}
+
+}

File src/main/java/org/xmlcml/declaratron/stmml/stmml/CMLClassVisitor.java

+package org.xmlcml.declaratron.stmml.stmml;
+
+import nu.xom.Element;
+
+import org.xmlcml.cml.base.CMLConstants;
+import org.xmlcml.cml.base.CMLElement;
+import org.xmlcml.semantic.NodeUtils;
+import org.xmlcml.semantic.visitors.AbstractElementVisitor;
+import org.xmlcml.semantic.visitors.Executable;
+
+public class CMLClassVisitor extends AbstractElementVisitor {
+	String namespace = CMLConstants.CML_NS;
+
+	public final static String TAG = "cmlClassVisitor";
+	
+	public CMLClassVisitor( ) {
+		this (new Element(TAG));
+	}
+	
+	public CMLClassVisitor( Element e )	{
+		super( e , TAG);
+	}
+
+	public Element visitElementWithoutDescent( Element e) {
+		visitedNodesList.add(e);
+		//If we're namespaced and it's wrong, do nothing
+		if( namespace != null && ! namespace.equals(e.getNamespaceURI())) return e;
+		if( e instanceof CMLElement ) return e;
+		try {
+			CMLElement newElement = CMLElement.createCMLElement( e );
+			NodeUtils.copyAttributes( e, newElement );
+			changedNodesList.add(e);
+			return newElement;
+		} catch( Exception ex )	{
+			failedNodesList.add(e);
+			log.fatal("Couldn't make CML element: " + e.toXML(), ex );
+		}
+		return e;
+	}
+}

File src/main/java/org/xmlcml/declaratron/stmml/stmml/TableToolVisitable.java

+package org.xmlcml.declaratron.stmml.stmml;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import nu.xom.Attribute;
+import nu.xom.Element;
+import nu.xom.Nodes;
+
+import org.xmlcml.cml.base.CMLElement;
+import org.xmlcml.cml.element.CMLArray;
+import org.xmlcml.cml.element.CMLScalar;
+import org.xmlcml.cml.element.CMLTable;
+import org.xmlcml.cml.tools.TableTool;
+import org.xmlcml.mathml.Context;
+import org.xmlcml.mathml.MathMLDoubleElement;
+import org.xmlcml.mathml.MathVisitable;
+import org.xmlcml.semantic.AbstractExecutableElement;
+import org.xmlcml.semantic.NodeUtils;
+import org.xmlcml.semantic.visitors.Executable;
+
+/** supports table functions.
+ * 
+ * has many similarities to ArrayTool and may overlap.
+ * Still in early development
+ * 
+ * @author pm286
+ *
+ */
+public class TableToolVisitable extends AbstractExecutableElement implements Executable
+{
+	private static final String VAR = "var";
+	private static final String MATH_PATH = "//*[local-name()='math']";
+	private static final String PARAM = "param-";
+	private static final String FUNCTION_REF = "functionRef";
+	private static final String FUNCTION_VAR = "functionVar";
+	private static final String APPLY_FUNCTION = "applyFunction";
+	
+	public static final String TAG = "tableTool";
+
+	private List<CMLTable> tableList;
+	private TableTool tableTool;
+	private CMLTable table;
+	private String functionRef;
+	private Map<String, Double> paramValueMap;
+	private String functionVar;
+	private Map<Integer, String> varMap;
+	private Map<Integer, String> xpathMap;
+	private Element function;
+	private List<String> varList;
+	private List<String> xpathList;
+	private Map<String, List<Double>> doubleListByVarName;
+
+	public TableToolVisitable( )
+	{
+		this( new Element(TAG));
+	}
+
+	public TableToolVisitable( Element e )
+	{
+		super( e , TAG);
+		log.debug(e.toXML());
+	}
+
+	public Element runTreeVisit() {
+		processAttributes();
+		if (tableList == null || tableList.size() == 0) {
+			System.out.println("no table");
+			// these methods create an table
+//			if (CREATE_DOUBLES.equals(method)) {
+//				result = createDoubles();
+//			} else if (PARAMETER_SWEEP.equals(method)) {
+//				result = applyFunction();
+//			} else {
+//				
+//			}
+		} else {
+			for (CMLTable t : tableList) {
+				table = t;
+				tableTool = TableTool.getOrCreateTool(table);
+				if (APPLY_FUNCTION.equals(method)) {
+					result = applyFunction();
+		  		} else {
+		  			throw new RuntimeException("Unknown method: "+method);
+		  		}
+			}
+		}
+		return result;
+	}
+
+	private Element applyFunction() {
+		if (functionVar == null && varMap.size() == 0) {
+			throw new RuntimeException("Must give @functionVar or @var-n");
+		}
+		if (xpath == null && xpathMap.size() == 0) {
+			throw new RuntimeException("Must give @xpath or @xpath-n");
+		}
+		return runSingleParameter(table, null, null);
+	}
+
+	private List<String> makeList(Map<Integer, String> map) {
+		Set<Integer> intSet = map.keySet();
+		List<Integer> intList = (List<Integer>) Arrays.asList(intSet.toArray(new Integer[0]));
+		Collections.sort(intList);
+		List<String> valueList = new ArrayList<String>();
+		int j = 1;
+		for (Integer ii : intList) {
+			if (ii !=j++) {
+				throw new RuntimeException("Missing number att name: "+ii+" != "+j);
+			}
+			valueList.add(map.get(ii));
+		}
+		return valueList;
+	}
+
+	private Element runSingleParameter(CMLTable theTable, String pname, Double pval) {
+		Set<String> ciNames = MathVisitable.getCiNames(this, function, MATH_PATH);
+		if (functionVar != null) ciNames.add(functionVar);
+		checkEqualSets(ciNames, paramValueMap.keySet());
+		MathMLDoubleElement func = MathVisitable.getEvaluatableFunction(this, function, MATH_PATH);
+		Context mathContext = new Context();
+		if (pname != null) {
+			mathContext.setVar(pname,  pval);
+		}
+		for (String par : paramValueMap.keySet()) {
+			Double dd = paramValueMap.get(par);
+			mathContext.setVar(par, dd);
+		}
+		for (String selectorName :  doubleListByVarName.keySet()) {
+			List<Double> dList = doubleListByVarName.get(selectorName);
+			System.out.println("S "+selectorName+" "+dList);
+			mathContext.setVar(selectorName, dList);
+		}
+		Double d = (Double) func.eval(mathContext);
+		CMLScalar scalar = new CMLScalar(d);
+		return scalar;
+	}
+
+	private boolean checkEqualSets(Set<String> varNames, Set<String> paramNames) {
+		boolean equals = true;
+		Set<String> varNames1 = new HashSet<String>(varNames);
+		Set<String> paramNames1 = new HashSet<String>(paramNames);
+		varNames1.removeAll(paramNames);
+		if (varNames1.size() > 0 ) {
+			equals = false;
+			log.error("ci names not found in parameters "+varNames1);
+		}
+		paramNames1.removeAll(varNames);
+		if (paramNames1.size() > 0 ) {
+			equals = false;
+			log.error("parameters don't map to ci names "+paramNames1);
+		}
+		return equals;
+	}
+
+	private Element getFunction() {
+		getFunctionRef();
+		if (functionRef == null) {
+			throw new RuntimeException("Must give @functionRef");
+		}
+		function = NodeUtils.getElementFromURL(functionRef);
+		if (function == null) {
+			throw new RuntimeException("Cannot find/parse: "+functionRef);
+		}
+		return function;
+	}
+
+	private String getFunctionRef() {
+		functionRef = getAttributeValue(FUNCTION_REF);
+		return functionRef;
+	}
+
+	private String getFunctionVars() {
+		functionVar = getAttributeValue(FUNCTION_VAR);
+		return functionVar;
+	}
+	private void getParams() {
+		paramValueMap = new HashMap<String, Double>();
+		for (int i = 0; i < this.getAttributeCount(); i++) {
+			Attribute att = this.getAttribute(i);
+			String name = att.getLocalName();
+			if (name.startsWith(PARAM)) {
+				name = name.substring(PARAM.length());
+				String attValue =att.getValue();
+				try {
+					Double dValue = new Double(attValue);
+					paramValueMap.put(name, dValue);
+				} catch (Exception e) {
+					log.error("cannot parse parameter as double "+att);
+				}
+			}
+		}
+		System.err.println(paramValueMap);
+	}
+	
+	private void getVars() {
+		varMap = getNumberedAttributes(VAR+"-");
+	}
+
+	private void getXPaths() {
+		xpathMap = getNumberedAttributes(XPATH+"-");
+	}
+
+	private void makeDoubleListsByName() {
+		doubleListByVarName = new HashMap<String, List<Double>>();
+		varList = makeList(varMap);
+		xpathList = makeList(xpathMap);
+		if (xpathList.size() != varList.size()){
+			throw new RuntimeException("vars ("+varList.size()+") do not match xpaths ("+xpathList.size()+")");
+		}
+		for (int i = 0; i < xpathList.size(); i++) {
+			Element xpathElem = (Element) this.query(xpathList.get(i)).get(0);
+			CMLArray array = (CMLArray) CMLElement.createCMLElement(xpathElem);
+			double[] doubles = array.getDoubles();
+			List<Double> dList = new ArrayList<Double>();
+			// we shall be counting from ONE
+			// this is tacky and dangerous
+			dList.add(Double.NaN);
+			for (double d : doubles) {
+				dList.add(d);
+			}
+			doubleListByVarName.put(varList.get(i), dList);
+		}
+	}
+
+	private Map<Integer, String> getNumberedAttributes(String prefix) {
+		Map<Integer, String> map = new HashMap<Integer, String>();
+		for (int i = 0; i < this.getAttributeCount(); i++) {
+			Attribute att = this.getAttribute(i);
+			String localName = att.getLocalName();
+			if (localName.startsWith(prefix)) {
+				String name = localName.substring(prefix.length());
+				try {
+					String attValue = att.getValue();
+					Integer attInt = new Integer(name);
+					map.put(attInt, attValue);
+				} catch (Exception e){
+					throw new RuntimeException("Cannot parse as numbered attribute name: "+localName);
+				}
+			}
+		}
+		System.err.println(map);
+		return map;
+	}
+	
+	private void processAttributes() {
+
+		Element cmlContext = getComputationalContext();
+		getXpath(false);
+		getSetId();
+		getMethod( true );
+		getFunction();
+		getVars();
+		getXPaths();
+		getParams();
+		getFunctionVars();
+		makeDoubleListsByName();
+		if (cmlContext != null) {
+			List<Element> elements = queryElementsNS(cmlContext, xpath);
+			tableList = CMLTable.extractTables(elements);
+		} else {
+			if (xpath != null) {
+				Nodes nodes = this.query(xpath);
+				if (nodes.size() > 0) {
+					tableList = new ArrayList<CMLTable>();
+					for (int i = 0; i < nodes.size(); i++) {
+						Element element = (Element) nodes.get(i);
+						CMLTable table = (CMLTable) CMLElement.createCMLElement(element);
+						if (table != null) {
+							tableList.add(table);
+						}
+					}
+				}
+			}
+		}
+	}
+
+}

File src/main/java/org/xmlcml/declaratron/stmml/units/UnitsVisitor.java

+package org.xmlcml.declaratron.stmml.units;
+
+import java.util.List;
+
+import org.xmlcml.cml.base.CMLConstants;
+import org.xmlcml.cml.element.CMLScalar;
+import org.xmlcml.euclid.Angle;
+import org.xmlcml.semantic.AbstractExecutableElement;
+
+import nu.xom.*;
+
+/** this is ad hoc till we recreate units
+ * 
+ * I think this is a true visitor. It should iterate over the tree and when it comes to a 
+ * node decide whether to change the units.
+ * 
+ * Needs more work
+ * 
+ * @author pm286
+ *
+ */
+public class UnitsVisitor extends AbstractExecutableElement
+{
+	
+	private static final String UNITS_RADIAN = "units:radian";
+	private static final String UNITS_DEGREE = "units:degree";
+	private static final String DEGREES2_RADIANS = "degrees2Radians";
+
+	public static final String TAG = "unitsVisitor";
+	
+	private List<Element> elements;
+	private CMLScalar scalar;
+	private String units;
+	private Double doubleValue;
+	
+	public UnitsVisitor( )
+	{
+		this( new Element(TAG));
+	}
+
+	public UnitsVisitor( Element e )
+	{
+		super( e , TAG);
+		log.debug(e.toXML());
+	}
+
+	public Element runTreeVisit() {
+		processAttributes();
+		for (Element e : elements) {
+			getScalarDouble(e);
+			getUnits();
+			if (DEGREES2_RADIANS.equals(method)) {
+				radians2Degrees(e);
+	  		} else {
+	  			throw new RuntimeException("Unknown method: "+method);
+	  		}
+		}
+		return result;
+	}
+
+	private String getUnits() {
+		units = scalar.getUnits();
+		if (units == null) {
+  			throw new RuntimeException("Has no units "+scalar.toXML());
+  		}
+		return units;
+	}
+
+	private CMLScalar getScalarDouble(Element e) {
+		if(!(e instanceof CMLScalar)) {
+			throw new RuntimeException("Not a scalar: "+e.toXML());
+		}
+		scalar = (CMLScalar) e;
+		if(!CMLConstants.XSD_DOUBLE.equals(scalar.getDataType())) {
+			throw new RuntimeException("Not a double: "+e.toXML());
+		}
+		doubleValue = scalar.getDouble();
+		return scalar;
+	}
+
+	private void radians2Degrees(Element e) {
+		if (units.equals(UNITS_DEGREE)) {
+			double radians = doubleValue / Angle.DEGREES_IN_RADIAN;
+			scalar.setValue(radians);
+			scalar.setUnits(UNITS_RADIAN);
+		} else {
+			throw new RuntimeException("Bad units: "+units);
+		}
+	}
+
+	private void processAttributes() {
+		getXpath( true );
+		getMethod(true);
+		getArgs(false);
+		elements = queryElementsNS(getComputationalContext(), xpath);
+	}
+	
+
+}

File src/main/resources/META-INF/declaratron

+org.xmlcml.cml.declaratron.chem.amber.AmberConverters

File src/main/resources/log4j.properties

+log4j.rootLogger=DEBUG, A1
+log4j.appender.A1=org.apache.log4j.ConsoleAppender
+log4j.appender.A1.layout=org.apache.log4j.PatternLayout
+log4j.appender.A1.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n
+log4j.logger.uk.ac.cam=DEBUG
+
+log4j.logger.org.xmlcml.cml.converters.marker = INFO

File src/main/resources/org/xmlcml/declaratron/chem/chemistry/classList.xml

+<classList>
+	<class tag="arrayTool"    name="org.xmlcml.cml.chemistry.ArrayToolVisitable" />
+	<class tag="atomTypeTool" name="org.xmlcml.cml.chemistry.AtomTypeToolVisitable" />
+	<class tag="energy"       name="org.xmlcml.cml.chemistry.EnergyVisitable" />
+	<class tag="geometry"     name="org.xmlcml.cml.chemistry.GeometryVisitable" />
+	<class tag="moleculeTool" name="org.xmlcml.cml.chemistry.MoleculeToolVisitable" />
+	<class tag="units"        name="org.xmlcml.cml.units.UnitsVisitor" />
+</classList>
+		

File src/test/java/org/xmlcml/declaratron/stmml/stmml/ArrayToolVisitorTest.java

+package org.xmlcml.declaratron.stmml.stmml;
+
+import nu.xom.Element;
+
+import org.junit.Ignore;
+import org.junit.Test;
+import org.xmlcml.cml.forcefield.Fixtures;
+import org.xmlcml.cml.testutil.JumboTestUtils;
+import org.xmlcml.semantic.NodeUtils;
+import org.xmlcml.semantic.visitors.ExecutableVisitor;
+import org.xmlcml.stmml.ArrayToolVisitable;
+import org.xmlcml.stmml.TableToolVisitable;
+
+public class ArrayToolVisitorTest {
+
+	
+	@Test
+	public void testArrayTool() {
+		
+		Element element = NodeUtils.parseResource(Fixtures.MATHML_DIR+"arrayTest.xml");
+		Element arrayToolElement = (Element) element.query("//*[local-name()='arrayTool']").get(0);
+		ArrayToolVisitable visitable = new ArrayToolVisitable(arrayToolElement);
+		ExecutableVisitor visitor = new ExecutableVisitor();
+		Element newElement = visitor.visitElement(visitable);
+		JumboTestUtils.assertEqualsIncludingFloat("test compare", 
+				NodeUtils.parseResource(Fixtures.MATHML_DIR+"arrayTestOut.xml"), 
+				newElement, true, 0.00001);		
+	}
+
+	@Test
+	public void testArrayToolMath() {
+		
+		Element element = NodeUtils.parseResource(Fixtures.MATHML_DIR+"arrayTestMath.xml");
+		Element arrayToolElement = (Element) element.query("//*[local-name()='arrayTool']").get(0);
+		ArrayToolVisitable visitable = new ArrayToolVisitable(arrayToolElement);
+		ExecutableVisitor visitor = new ExecutableVisitor();
+		Element newElement = visitor.visitElement(visitable);
+		JumboTestUtils.assertEqualsIncludingFloat("test compare", 
+				NodeUtils.parseResource(Fixtures.MATHML_DIR+"arrayTestMathOut.xml"), 
+				newElement, true, 0.0001);		
+	}
+
+//	@Test
+//	public void testArrayToolKKLJ() {
+//		
+//		Element element = NodeUtils.parseResource("org/xmlcml/cml/chemistry/kkljArrayTest.xml");
+//		Element arrayToolElement = (Element) element.query("//*[local-name()='arrayTool']").get(0);
+//		ArrayToolVisitable visitable = new ArrayToolVisitable(arrayToolElement);
+//		ExecutableVisitor visitor = new ExecutableVisitor();
+//		Element newElement = visitor.visitElement(visitable);
+//		JumboTestUtils.assertEqualsIncludingFloat("test compare", 
+//				NodeUtils.parseResource("org/xmlcml/cml/chemistry/kkljOut.xml"), 
+//				newElement, true, 0.0001);		
+//	}
+//	
+//	
+//	@Test
+//	public void testArrayToolKKExp() {
+//		
+//		Element element = NodeUtils.parseResource("org/xmlcml/cml/chemistry/kkExpArrayTest.xml");
+//		Element arrayToolElement = (Element) element.query("//*[local-name()='arrayTool']").get(0);
+//		ArrayToolVisitable visitable = new ArrayToolVisitable(arrayToolElement);
+//		ExecutableVisitor visitor = new ExecutableVisitor();
+//		Element newElement = visitor.visitElement(visitable);
+//		JumboTestUtils.assertEqualsIncludingFloat("test compare", 
+//				NodeUtils.parseResource("org/xmlcml/cml/chemistry/kkExpOut.xml"), 
+//				newElement, true, 0.0001);		
+//	}
+	
+
+	@Test
+	@Ignore
+	public void testParameterSweep2() {
+		
+		Element element = NodeUtils.parseResource(Fixtures.MATHML_DIR+"parameterSweep.xml");
+		Element arrayToolElement = (Element) element.query("//*[local-name()='arrayTool']").get(0);
+		ArrayToolVisitable visitable = new ArrayToolVisitable(arrayToolElement);
+		ExecutableVisitor visitor = new ExecutableVisitor();
+		Element newElement = visitor.visitElement(visitable);
+		JumboTestUtils.assertEqualsIncludingFloat("test compare", 
+				NodeUtils.parseResource(Fixtures.MATHML_DIR+"parameterSweepOut.xml"), 
+				newElement, true, 0.0001);		
+	}
+
+	@Ignore
+	@Test
+	public void testPotentialEnergy() {
+		
+		Element element = NodeUtils.parseResource("org/xmlcml/cml/chemistry/potentialEnergyTestSelector.xml");
+		Element tableToolElement = (Element) element.query("//*[local-name()='tableTool']").get(0);
+		TableToolVisitable visitable = new TableToolVisitable(tableToolElement);
+		ExecutableVisitor visitor = new ExecutableVisitor();
+		Element newElement = visitor.visitElement(visitable);
+		JumboTestUtils.assertEqualsIncludingFloat("test compare", 
+				NodeUtils.parseResource("org/xmlcml/cml/chemistry/potentialEnergyOut.xml"), 
+				newElement, true, 0.0001);		
+	}
+
+	@Test
+	public void testSimpleSelectorSum() {
+		
+		Element element = NodeUtils.parseResource(Fixtures.MATHML_DIR+"simpleSelectorSum.xml");
+		Element tableToolElement = (Element) element.query("//*[local-name()='tableTool']").get(0);
+		TableToolVisitable visitable = new TableToolVisitable(tableToolElement);
+		ExecutableVisitor visitor = new ExecutableVisitor();
+		Element newElement = visitor.visitElement(visitable);
+		JumboTestUtils.assertEqualsIncludingFloat("test compare", 
+				NodeUtils.parseResource(Fixtures.MATHML_DIR+"simpleSelectorSumOut.xml"), 
+				newElement, true, 0.0001);		
+	}
+
+}