/*
Copyright (C) 2000-2004
Code contributed by Greg Collecutt, Joseph Hope and Paul Cochrane
This file is part of xmds.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*
$Id: xsilfield.cc,v 1.22 2005/05/19 03:42:00 joehope Exp $
*/
/*! @file xsilfield.cc
@brief XSIL format parsing classes and methods
More detailed explanation...
*/
#include<string>
#include<ctype.h>
#include<xmlbasics.h>
#include<dom3.h>
#include<xmdsutils.h>
#include<xsilfield.h>
#define DEBUG 0
// ******************************************************************************
// ******************************************************************************
// xsilField public
// ******************************************************************************
// ******************************************************************************
long nxsilFields=0; //!< The number of xsil fields
// ******************************************************************************
xsilField::xsilField() {
if(DEBUG) {
nxsilFields++;
printf("xsilField::xsilField\n");
printf("nxsilFields=%li\n",nxsilFields);
}
};
// ******************************************************************************
xsilField::~xsilField() {
if(DEBUG) {
nxsilFields--;
printf("xsilField::~xsilField\n");
printf("nxsilFields=%li\n",nxsilFields);
}
};
// ******************************************************************************
void xsilField::processElement(
const Element *const yourElement) {
if(DEBUG) {
printf("xsilField::processElement\n");
}
fieldName="";
nIndependentVariables=0;
variableNamesList.clear();
latticeList.clear();
const NodeList* candidateElements;
const NamedNodeMap* elementAttributes;
const Node* attributeNode;
list<XMLString> anXMLStringList;
// ************************************
// find name
elementAttributes = yourElement->attributes();
attributeNode = elementAttributes->getNamedItem("Name");
if(attributeNode != 0) {
fieldName = *attributeNode->nodeValue();
}
else {
throw xmdsException(yourElement,"Where is my Name='...' attribute?");
}
// ************************************
// find n_independent Param assignment
candidateElements = yourElement->getElementsByTagName("Param",0);
if(candidateElements->length()>1) {
throw xmdsException(yourElement,"Only one <Param> element expected ");
}
elementAttributes = candidateElements->item(0)->attributes();
attributeNode = elementAttributes->getNamedItem("Name");
if(attributeNode != 0) {
if(*attributeNode->nodeValue() == "n_independent") {
if(!candidateElements->item(0)->textContent(0)->asULong(nIndependentVariables)) {
throw xmdsException(candidateElements->item(0),"Invalid positive integer format");
}
}
else {
throw xmdsException(candidateElements->item(0),"Unknown <Param> element");
}
}
else {
throw xmdsException(candidateElements->item(0),"Where is my Name='...' attribute?");
}
// ************************************
// find Arrays
candidateElements = yourElement->getElementsByTagName("Array",0);
if(candidateElements->length() != 2) {
throw xmdsException(yourElement,"Exactly two <Array> elements expected ");
}
// ************************************
// find variables Array
elementAttributes = candidateElements->item(0)->attributes();
attributeNode = elementAttributes->getNamedItem("Name");
if(attributeNode != 0) {
if(*attributeNode->nodeValue() != "variables") {
sprintf(errorMessage(),"Unknown <Array> element '%s'",attributeNode->nodeValue()->c_str());
throw xmdsException(yourElement,errorMessage());
}
}
else
throw xmdsException(candidateElements->item(0),"Where is my Name='...' attribute?");
const Element* myVariablesArrayElement = dynamic_cast<const Element*>(candidateElements->item(0));
// ************************************
// find data Array
elementAttributes = candidateElements->item(1)->attributes();
attributeNode = elementAttributes->getNamedItem("Name");
if(attributeNode != 0) {
if(*attributeNode->nodeValue() != "data") {
sprintf(errorMessage(),"Unknown <Array> element '%s'",attributeNode->nodeValue()->c_str());
throw xmdsException(yourElement,errorMessage());
}
}
else {
throw xmdsException(candidateElements->item(1),"Where is my Name='...' attribute?");
}
const Element* myDataArrayElement = dynamic_cast<const Element*>(candidateElements->item(1));
// ************************************
// process variables Array
unsigned long nVariables;
candidateElements = myVariablesArrayElement->getElementsByTagName("Dim",0);
if(candidateElements->length()>1) {
throw xmdsException(myVariablesArrayElement,"Only one <Dim> element expected ");
}
if(!candidateElements->item(0)->textContent(0)->asULong(nVariables)) {
throw xmdsException(candidateElements->item(0),"Invalid positive integer format");
}
getAssignmentStrings(myVariablesArrayElement,"Stream",1,nVariables,variableNamesList);
// ************************************
// process data Array
candidateElements = myDataArrayElement->getElementsByTagName("Dim",0);
if(candidateElements->length() != nIndependentVariables + 1) {
sprintf(errorMessage(),"Exactly %li <Dim> elements expected",nIndependentVariables + 1);
throw xmdsException(myDataArrayElement,errorMessage());
}
for(unsigned long i=0 ; i<candidateElements->length(); i++) {
unsigned long nextDim;
if(!candidateElements->item(i)->textContent(0)->asULong(nextDim)) {
throw xmdsException(candidateElements->item(i),"Invalid positive integer format");
}
latticeList.push_back(nextDim);
}
candidateElements = myDataArrayElement->getElementsByTagName("Stream",0);
if(candidateElements->length() != 1) {
throw xmdsException(myDataArrayElement,"A <Stream> element expected");
}
const Element* myStreamElement = dynamic_cast<const Element*>(candidateElements->item(0));
// get the Metalink tags
candidateElements = myDataArrayElement->getElementsByTagName("Metalink",1);
if (candidateElements->length() != 1) {
throw xmdsException(myDataArrayElement,"<Metalink> element expected");
}
// get the Format attribute
elementAttributes = candidateElements->item(0)->attributes();
attributeNode = elementAttributes->getNamedItem("Format");
if(attributeNode != 0) {
if(*attributeNode->nodeValue() != "Text" && *attributeNode->nodeValue() != "Binary") {
sprintf(errorMessage(),"Unknown <Metalink> attribute '%s'",attributeNode->nodeValue()->c_str());
throw xmdsException(yourElement,errorMessage());
}
}
else {
throw xmdsException(candidateElements->item(0),"Where is my Format='...' attribute?");
}
// determine the stream format and work out where the data is
streamFormat = *attributeNode->nodeValue();
if(streamFormat == "Text") {
// ok then, the data is ascii, go get it tiger!
data = *myStreamElement->textContent(0);
}
else if (streamFormat == "Binary") {
// data is binary, the textContent of the Stream element is the datafile filename
binDatFname = *myStreamElement->textContent(0);
// try to remove whitespace chars
std::string tmp = binDatFname.c_str();
std::string tmp2;
for (unsigned long int i=0; i<tmp.length(); i++) {
if (!isspace(tmp[i])) {
tmp2 += tmp[i];
}
}
// biff the temporary variable into the binary data filename
binDatFname = tmp2.c_str();
// need to check what encoding the data is in
// is it big or little endian??
attributeNode = elementAttributes->getNamedItem("Encoding");
if (attributeNode != 0) {
if (*attributeNode->nodeValue() != "LittleEndian" && *attributeNode->nodeValue() != "BigEndian") {
sprintf(errorMessage(),"Unknown <Metalink> attribute '%s'", attributeNode->nodeValue()->c_str());
throw xmdsException(yourElement,errorMessage());
}
}
else {
throw xmdsException(candidateElements->item(0),"Where is my Encoding='...' attribute?");
}
// the binary encoding of the data file
binEncoding = *attributeNode->nodeValue();
// get the precision attribute
elementAttributes = candidateElements->item(0)->attributes();
attributeNode = elementAttributes->getNamedItem("precision");
if(attributeNode != 0) {
if(*attributeNode->nodeValue() != "single" && *attributeNode->nodeValue() != "double") {
sprintf(errorMessage(),"Unknown <Metalink> attribute '%s'",attributeNode->nodeValue()->c_str());
throw xmdsException(yourElement,errorMessage());
}
}
else {
throw xmdsException(candidateElements->item(0),"Where is my precison='...' attribute?");
}
// the precison of the binary data
binPrecision = *attributeNode->nodeValue();
// get the UnsignedLong attribute
elementAttributes = candidateElements->item(0)->attributes();
attributeNode = elementAttributes->getNamedItem("UnsignedLong");
if(attributeNode != 0) {
if(*attributeNode->nodeValue() != "ulong" && *attributeNode->nodeValue() != "uint32" && *attributeNode->nodeValue() != "uint64") {
sprintf(errorMessage(),"Unknown <Metalink> attribute '%s'",attributeNode->nodeValue()->c_str());
throw xmdsException(yourElement,errorMessage());
}
ulongType = *attributeNode->nodeValue();
}
else {
ulongType = "ulong";
printf("Defaulting to ulong\n");
}
}
};
// ******************************************************************************
void xsilField::writeAsFormat(
FILE *const outfile,
const outputFormatEnum& format,
const long& iD,
const char *datFileNameBase) {
if(DEBUG) {
printf("xsilField::writeAsFormat\n");
}
if (streamFormat == "Text") {
// dump data as ascii file
char datFileName[64];
sprintf(datFileName,"%s%li.dat",datFileNameBase,iD);
FILE *tempfile=fopen(datFileName,"w");
// write header row (this doesn't work for matlab!)
if(format != FORMAT_MATLAB) {
for(list<XMLString>::const_iterator pXMLString = variableNamesList.begin(); pXMLString != variableNamesList.end(); pXMLString++) {
fprintf(tempfile," %s ",pXMLString->c_str());
}
}
// write data
fprintf(tempfile,"%s",data.c_str());
fclose(tempfile);
// initialise variables
list<XMLString>::iterator pXMLString = variableNamesList.begin();
for(unsigned long i=0;i<variableNamesList.size();i++) {
// need to format variable names to remove any non alpha-numeric characters
pXMLString->goLatinAlphaNumeric();
char tempString[64];
sprintf(tempString,"_%li",iD);
*pXMLString += tempString;
if(nIndependentVariables==0) {
fprintf(outfile,"%s = zeros(1,1);\n",pXMLString->c_str());
}
else if(nIndependentVariables==1) {
if(i==0) {
fprintf(outfile,"temp_d1 = zeros(1,%li);\n",lattice(0));
}
else {
fprintf(outfile,"%s = zeros(1,%li);\n",pXMLString->c_str(),lattice(0));
}
}
else {
if(i<nIndependentVariables) {
fprintf(outfile,"temp_d%li = zeros(%li",i+1,lattice(nIndependentVariables-1));
}
else {
fprintf(outfile,"%s = zeros(%li",pXMLString->c_str(),lattice(nIndependentVariables-1));
}
for(unsigned long j=nIndependentVariables-1;j>0;j--) {
fprintf(outfile,",%li",lattice(j-1));
}
fprintf(outfile,");\n");
}
if(i<nIndependentVariables) {
fprintf(outfile,"%s = zeros(1,%li);\n",pXMLString->c_str(),lattice(i));
}
pXMLString++;
}
fprintf(outfile,"\n");
// load in temp file
if(format==FORMAT_SCILAB) {
fprintf(outfile,"%s%li = fscanfMat('%s');\n",datFileNameBase,iD,datFileName);
}
else {
fprintf(outfile,"load %s -ascii\n",datFileName);
}
for(unsigned long i=0;i<nIndependentVariables;i++) {
fprintf(outfile,"temp_d%li(:) = %s%li(:,%li);\n",i+1,datFileNameBase,iD,i+1);
}
for(unsigned long i=nIndependentVariables;i<variableNamesList.size();i++) {
fprintf(outfile,"%s(:) = %s%li(:,%li);\n",variableName(i)->c_str(),datFileNameBase,iD,i+1);
}
// work out coordinates
for(unsigned long i=0;i<nIndependentVariables;i++) {
fprintf(outfile,"%s(:) = temp_d%li(",variableName(i)->c_str(),i+1);
if(i==(nIndependentVariables-1)) {
fprintf(outfile,":");
}
else {
fprintf(outfile,"1");
}
for(unsigned long j=nIndependentVariables-1;j>0;j--) {
if((j-1)==i) {
fprintf(outfile,",:");
}
else {
fprintf(outfile,",1");
}
}
fprintf(outfile,");\n");
}
fprintf(outfile,"\n");
// clear excess variables
fprintf(outfile,"clear %s%li",datFileNameBase,iD);
for(unsigned long i=0;i<nIndependentVariables;i++) {
fprintf(outfile," temp_d%li",i+1);
}
fprintf(outfile,"\n");
fprintf(outfile,"\n");
}
else if (streamFormat == "Binary") {
if (format == FORMAT_MATLAB) {
// work out how matlab will interpret endian-ness
std::string machineFormat;
if (binEncoding == "BigEndian") {
machineFormat = "ieee-be";
}
else if (binEncoding == "LittleEndian") {
machineFormat = "ieee-le";
}
else {
machineFormat = "native";
}
fprintf(outfile,"fpDat = fopen('%s','r','%s');\n",binDatFname.c_str(),machineFormat.c_str());
fprintf(outfile,"if (fpDat < 0)\n");
fprintf(outfile," disp('Cannot open binary data file: %s')\n",binDatFname.c_str());
fprintf(outfile," return\n");
fprintf(outfile,"end\n");
unsigned long int k = 0;
for(list<XMLString>::iterator pXMLString = variableNamesList.begin(); pXMLString != variableNamesList.end(); pXMLString++) {
char tempString[64];
sprintf(tempString,"_%li",iD);
*pXMLString += tempString;
if (k < nIndependentVariables) {
fprintf(outfile,"%sLen = fread(fpDat,1,'%s');\n",pXMLString->c_str(),ulongType.c_str());
fprintf(outfile,"%s = zeros(1,%sLen);\n",pXMLString->c_str(),pXMLString->c_str());
fprintf(outfile,"%s(:) = fread(fpDat,%sLen,'%s');\n",pXMLString->c_str(),pXMLString->c_str(),binPrecision.c_str());
}
else if (k >= nIndependentVariables) {
fprintf(outfile,"%sLen = fread(fpDat,1,'%s');\n",pXMLString->c_str(),ulongType.c_str());
if (nIndependentVariables == 1) {
fprintf(outfile,"%s = fread(fpDat,%sLen,'%s');\n",pXMLString->c_str(),
variableNamesList.begin()->c_str(),binPrecision.c_str());
}
else if (nIndependentVariables == 2) {
fprintf(outfile,"%s = fread(fpDat,[%sLen,%sLen],'%s');\n",pXMLString->c_str(),
(++variableNamesList.begin())->c_str(),variableNamesList.begin()->c_str(),binPrecision.c_str());
}
else if (nIndependentVariables > 2) {
// now we need to create a multi-dimensional matrix,
// and this is harder to do...
// we need to read in a matrix-sized (ie 2D) block at a time,
// and append this to the other dimensions the number of
// independent variables determines the dimensions of the
// N-D matrix to produce
// construct the for loop to loop over the third and subsequent dimensions
list<XMLString>::iterator pIndepVars = variableNamesList.begin();
for (unsigned long int inumIndepVars=2; inumIndepVars<nIndependentVariables; inumIndepVars++) {
fprintf(outfile, "for index%li = 1:%sLen\n",inumIndepVars-2,pIndepVars->c_str());
pIndepVars++;
}
// generate the first part of the string, which is the array to be assigned into
fprintf(outfile, "%s(:,:,",pXMLString->c_str());
pIndepVars = variableNamesList.begin();
for (unsigned long int inumIndepVars=nIndependentVariables-1; inumIndepVars>=2; inumIndepVars--) {
fprintf(outfile, "index%li",inumIndepVars-2);
// need to append a comma if not the last index to append
if (inumIndepVars != 2) {
fprintf(outfile,",");
}
}
// generate the fread statement
// to do this, I have to work out what the last and second-to-last
// independent variable names are this is because, for some reason,
// one can't inspect a given element of a list
// first, the last one
pIndepVars = variableNamesList.begin();
XMLString lastIndepVar;
for (unsigned long int inumIndepVars=0; inumIndepVars<nIndependentVariables; inumIndepVars++) {
lastIndepVar = *pIndepVars;
pIndepVars++;
}
// now the second to last one
XMLString secondLastIndepVar;
pIndepVars = variableNamesList.begin();
for (unsigned long int inumIndepVars=1; inumIndepVars<nIndependentVariables; inumIndepVars++) {
secondLastIndepVar = *pIndepVars;
pIndepVars++;
}
fprintf(outfile, ") = fread(fpDat,[%sLen,%sLen],'%s');\n",lastIndepVar.c_str(),
secondLastIndepVar.c_str(),binPrecision.c_str());
// finish off the for loop
for (unsigned long int inumIndepVars=2; inumIndepVars<nIndependentVariables; inumIndepVars++) {
fprintf(outfile,"end\n");
}
}
}
k++;
}
// clean up a bit
fprintf(outfile,"fclose(fpDat);\n");
fprintf(outfile,"clear fpDat ");
for(list<XMLString>::iterator pXMLString = variableNamesList.begin(); pXMLString != variableNamesList.end(); pXMLString++) {
fprintf(outfile, "%sLen ",pXMLString->c_str());
}
for (unsigned long int inumIndepVars=2; inumIndepVars<nIndependentVariables; inumIndepVars++) {
fprintf(outfile, "index%li ",inumIndepVars-2);
}
fprintf(outfile, "\n");
}
else if (format == FORMAT_SCILAB) {
// as far as I can tell, scilab can't handle binary data input,
// so barf, and tell why, and give some alternative.
printf("\nFatal error: Sorry, but at the time of this version of xmds,\n"
"scilab cannot handle binary input. To be able to use scilab,\n"
"please change your output format to ascii (in the <output> tag).\n"
"Exiting...\n");
exit(254);
}
else {
throw(xmdsException("Unknown format. I only accept Matlab or Scilab at present\n"));
}
}
else {
throw(xmdsException("Stream format is neither Text or Binary, something has seriously gone wrong!\n"));
}
};
// ******************************************************************************
// ******************************************************************************
// xsilField private
// ******************************************************************************
// ******************************************************************************
// ******************************************************************************
unsigned long xsilField::lattice(
const unsigned long& index) const {
if(DEBUG) {
printf("xsilField::lattice\n");
}
if(index>=latticeList.size()) {
throw xmdsException("Internal range error in xsilField::lattice");
}
list<unsigned long>::const_iterator pULong = latticeList.begin();
for(unsigned long i=0; i<index; i++) {
pULong++;
}
return *pULong;
};
// ******************************************************************************
const XMLString* xsilField::variableName(
const unsigned long& index) const {
if(DEBUG) {
printf("xsilField::varaibleName\n");
}
if(index>=variableNamesList.size()) {
throw xmdsException("Internal range error in xsilField::variableName");
}
list<XMLString>::const_iterator pXMLString = variableNamesList.begin();
for(unsigned long i=0; i<index; i++) {
pXMLString++;
}
return &*pXMLString;
};
syntax highlighted by Code2HTML, v. 0.9.1