diff --git a/src/xmlwrite.cpp b/src/xmlwrite.cpp new file mode 100644 --- /dev/null +++ b/src/xmlwrite.cpp @@ -0,0 +1,1603 @@ +/* + * + * This file is part of the Virtual Leaf. + * + * The Virtual Leaf 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 3 of the License, or + * (at your option) any later version. + * + * The Virtual Leaf 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 the Virtual Leaf. If not, see . + * + * Copyright 2010 Roeland Merks. + * + */ + +#include "mesh.h" +#include "parameter.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "xmlwrite.h" +#include "nodeset.h" +#include "warning.h" +#include "output.h" + +static const std::string _module_id("$Id$"); + +using namespace MyWarning; + +void ThrowStringStream(stringstream &s) { + + static char *msg = 0; + msg = (char *)malloc((1+s.str().length())*sizeof(char)); + strcpy(msg,s.str().c_str()); + throw(msg); +} + + +// Add this cell to the XML tree +void Cell::XMLAdd(xmlNodePtr cells_node) const { + + // Save the cell to a stream so we can reconstruct its state later + xmlNodePtr xmlcell = xmlNewChild(cells_node, NULL, BAD_CAST "cell",NULL); + XMLAddCore(xmlcell); + +} + +void BoundaryPolygon::XMLAdd(xmlNodePtr parent_node) const { + + xmlNodePtr xmlcell = xmlNewChild(parent_node, NULL, BAD_CAST "boundary_polygon",NULL); + XMLAddCore(xmlcell); + +} + +void NodeSet::XMLAdd(xmlNode *root) const { + + xmlNode *xmlnodeset = xmlNewChild(root, NULL, BAD_CAST "nodeset", NULL); + + for (list::const_iterator i=begin();i!=end();i++) { + { + ostringstream text; + xmlNodePtr node_xml = xmlNewChild(xmlnodeset, NULL, BAD_CAST "node", NULL); + text << (*i)->Index(); + xmlNewProp(node_xml, BAD_CAST "n", BAD_CAST text.str().c_str()); + } + } + +} + + + + +void Cell::XMLAddCore(xmlNodePtr xmlcell) const { + + // properties + + { + ostringstream text; + text << index; + xmlNewProp(xmlcell, BAD_CAST "index" , BAD_CAST text.str().c_str() ); + } + { + ostringstream text; + text << area; + xmlNewProp(xmlcell, BAD_CAST "area", BAD_CAST text.str().c_str()); + } + + { + ostringstream text; + text << target_area; + xmlNewProp(xmlcell, BAD_CAST "target_area", BAD_CAST text.str().c_str()); + } + + + { + ostringstream text; + text << target_length; + xmlNewProp(xmlcell, BAD_CAST "target_length", BAD_CAST text.str().c_str()); + } + + { + ostringstream text; + text << lambda_celllength; + xmlNewProp(xmlcell, BAD_CAST "lambda_celllength", BAD_CAST text.str().c_str()); + } + + { + ostringstream text; + text << stiffness; + xmlNewProp(xmlcell, BAD_CAST "stiffness", BAD_CAST text.str().c_str()); + } + + { + ostringstream text; + text << bool_name(fixed); + xmlNewProp(xmlcell, BAD_CAST "fixed", BAD_CAST text.str().c_str()); + } + + { + ostringstream text; + text << bool_name(pin_fixed); + xmlNewProp(xmlcell, BAD_CAST "pin_fixed", BAD_CAST text.str().c_str()); + } + + { + ostringstream text; + text << bool_name(at_boundary); + xmlNewProp(xmlcell, BAD_CAST "at_boundary", BAD_CAST text.str().c_str()); + } + + + { + ostringstream text; + text << bool_name(dead); + xmlNewProp(xmlcell, BAD_CAST "dead", BAD_CAST text.str().c_str()); + } + + { + ostringstream text; + text << bool_name(source); + xmlNewProp(xmlcell, BAD_CAST "source", BAD_CAST text.str().c_str()); + } + + + { + ostringstream text; + text << boundary_type_names[boundary]; + xmlNewProp(xmlcell, BAD_CAST "boundary", BAD_CAST text.str().c_str()); + } + + { + ostringstream text; + text << div_counter; + xmlNewProp(xmlcell, BAD_CAST "div_counter", BAD_CAST text.str().c_str()); + } + + { + ostringstream text; + text << cell_type; + xmlNewProp(xmlcell, BAD_CAST "cell_type", BAD_CAST text.str().c_str()); + } + + for (list::const_iterator i=nodes.begin();i!=nodes.end();i++) { + { + ostringstream text; + xmlNodePtr node_xml = xmlNewChild(xmlcell, NULL, BAD_CAST "node", NULL); + text << (*i)->Index(); + xmlNewProp(node_xml, BAD_CAST "n", BAD_CAST text.str().c_str()); + } + } + + for (list::const_iterator i=walls.begin();i!=walls.end();i++) { + { + ostringstream text; + xmlNodePtr wall_xml = xmlNewChild(xmlcell, NULL, BAD_CAST "wall", NULL); + //text <walls.begin(), m->walls.end(), *i ); + xmlNewProp(wall_xml, BAD_CAST "w", BAD_CAST text.str().c_str()); + } + } + + + + + xmlNodePtr chem_xml = xmlNewChild(xmlcell, NULL, BAD_CAST "chem", NULL); + { + ostringstream text; + text << NChem(); + xmlNewProp(chem_xml, BAD_CAST "n", BAD_CAST text.str().c_str()); + } + + for (int i=0;inode_sets.begin(),m->node_sets.end(),node_set); + xmlNewProp(xmlnode, BAD_CAST "nodeset", BAD_CAST text.str().c_str()); + } + + +} + +void Neighbor::XMLAdd(xmlNodePtr neighbors_node) const { + + xmlNodePtr xmlnode = xmlNewChild(neighbors_node, NULL, BAD_CAST "neighbor",NULL); + { + ostringstream text; + text << cell->Index(); + xmlNewProp(xmlnode, BAD_CAST "cell", BAD_CAST text.str().c_str()); + } + + { + ostringstream text; + text << nb1->Index(); + xmlNewProp(xmlnode, BAD_CAST "nb1", BAD_CAST text.str().c_str()); + } + + { + ostringstream text; + text << nb2->Index(); + xmlNewProp(xmlnode, BAD_CAST "nb2", BAD_CAST text.str().c_str()); + } + +} + + +// from example code on www.libxml.org: +xmlXPathObjectPtr +getnodeset (xmlDocPtr doc, xmlChar *xpath){ + + xmlXPathContextPtr context; + xmlXPathObjectPtr result; + + context = xmlXPathNewContext(doc); + if (context == NULL) { + //printf("Error in xmlXPathNewContext\n"); + return NULL; + } + result = xmlXPathEvalExpression(xpath, context); + xmlXPathFreeContext(context); + if (result == NULL) { + //printf("Error in xmlXPathEvalExpression\n"); + return NULL; + } + if(xmlXPathNodeSetIsEmpty(result->nodesetval)){ + xmlXPathFreeObject(result); + // printf("No result\n"); + return NULL; + } + return result; +} + + + +int Cell::XMLRead(xmlNode *cur) { + + xmlNode *n = cur->xmlChildrenNode; + + vector tmp_nodes; + + while(n!=NULL) { + if ((!xmlStrcmp(n->name, (const xmlChar *)"node"))) { + xmlChar *nc = xmlGetProp(n, BAD_CAST "n"); + + if (nc==0) { + unique_warning("Token \"n\" not found in xmlwrite.cpp at or around line no. 966"); + } + tmp_nodes.push_back(atoi( (char *)nc)); + xmlFree(nc); + + } + n = n->next; + } + + int nnodes = tmp_nodes.size(); + for (int i=0;iAddNodeToCell( this, + m->nodes[tmp_nodes[i]], + m->nodes[tmp_nodes[(nnodes+i-1)%nnodes]], + m->nodes[tmp_nodes[(i+1)%nnodes]] ); + + } + + n = cur->xmlChildrenNode; + while(n!=NULL) { + if ((!xmlStrcmp(n->name, (const xmlChar *)"chem"))) { + xmlChar *v_str = xmlGetProp(n, BAD_CAST "n"); + xmlNode *v_node = n->xmlChildrenNode; + int nv=0; + while (v_node!=NULL) { + if ((!xmlStrcmp(v_node->name, (const xmlChar *)"val"))) { + + + if (nv>=Cell::NChem()) { + { + stringstream text; + text << "Exception in Mesh::XMLRead: Too many chemical values given for cell(s). Ignoring remaining values."; + //ThrowStringStream(text); + unique_warning(text.str().c_str()); + break; + } + } + + xmlChar *nc = xmlGetProp(v_node, (const xmlChar *) "v"); + + if (nc==0) { + unique_warning("Token \"v\" not found in xmlwrite.cpp at or around line no. 1002"); + } + double v = strtod( (char *)nc, 0 ); + chem[nv++]=v; + xmlFree(nc); + } + v_node = v_node->next; + } + } + n = n->next; + } + + // read cell properties + { + xmlChar *v_str = xmlGetProp(cur, BAD_CAST "area"); + + if (v_str==0) { + unique_warning("Token \"area\" not found in xmlwrite.cpp at or around line no. 1018"); + } + if (v_str != NULL) { + area = strtod( (char *)v_str, 0); + xmlFree(v_str); + } + } + + { + xmlChar *v_str = xmlGetProp(cur, BAD_CAST "target_area"); + + if (v_str==0) { + unique_warning("Token \"target_area\" not found in xmlwrite.cpp at or around line no. 1029"); + } + if (v_str != NULL) { + target_area = strtod( (char *)v_str, 0); + xmlFree(v_str); + } + } + + + { + xmlChar *v_str = xmlGetProp(cur, BAD_CAST "target_length"); + + if (v_str==0) { + unique_warning("Token \"target_length\" not found in xmlwrite.cpp at or around line no. 1041"); + } + if (v_str != NULL) { + target_length = strtod( (char *)v_str, 0); + xmlFree(v_str); + } + } + + { + xmlChar *v_str = xmlGetProp(cur, BAD_CAST "lambda_celllength"); + + if (v_str==0) { + unique_warning("Token \"lambda_celllength\" not found in xmlwrite.cpp at or around line no. 1052"); + } + if (v_str != NULL) { + lambda_celllength = strtod( (char *)v_str, 0); + xmlFree(v_str); + } + } + + { + xmlChar *v_str = xmlGetProp(cur, BAD_CAST "stiffness"); + + if (v_str==0) { + unique_warning("Token \"stiffness\" not found in xmlwrite.cpp at or around line no. 1063"); + } + if (v_str != NULL) { + stiffness = strtod( (char *)v_str, 0); + xmlFree(v_str); + } + } + + + { + xmlChar *v_str = xmlGetProp(cur, BAD_CAST "fixed"); + + if (v_str==0) { + unique_warning("Token \"fixed\" not found in xmlwrite.cpp at or around line no. 1075"); + } + if (v_str != NULL) { + fixed = strtobool( (char *)v_str); + xmlFree(v_str); + } + } + + { + xmlChar *v_str = xmlGetProp(cur, BAD_CAST "pin_fixed"); + + if (v_str==0) { + unique_warning("Token \"pin_fixed\" not found in xmlwrite.cpp at or around line no. 1086"); + } + if (v_str != NULL) { + pin_fixed = strtobool( (char *)v_str); + xmlFree(v_str); + } + } + + { + xmlChar *v_str = xmlGetProp(cur, BAD_CAST "at_boundary"); + + if (v_str==0) { + unique_warning("Token \"at_boundary\" not found in xmlwrite.cpp at or around line no. 1097"); + } + if (v_str != NULL) { + at_boundary = strtobool( (char *)v_str); + xmlFree(v_str); + } + } + + { + xmlChar *v_str = xmlGetProp(cur, BAD_CAST "dead"); + + if (v_str==0) { + unique_warning("Token \"dead\" not found in xmlwrite.cpp at or around line no. 1108"); + } + if (v_str != NULL) { + dead = strtobool( (char *)v_str); + xmlFree(v_str); + } + } + + { + xmlChar *v_str = xmlGetProp(cur, BAD_CAST "source"); + + if (v_str==0) { + unique_warning("Token \"source\" not found in xmlwrite.cpp at or around line no. 1119"); + } + if (v_str != NULL) { + source = strtobool( (char *)v_str); + xmlFree(v_str); + } + } + + { + xmlChar *v_str = xmlGetProp(cur, BAD_CAST "boundary"); + + if (v_str==0) { + unique_warning("Token \"boundary\" not found in xmlwrite.cpp at or around line no. 1130"); + } + if (v_str != NULL) { + for (int i=0;i<4;i++) { + if (!xmlStrcmp( v_str, (const xmlChar *)Cell::boundary_type_names[i])) { + boundary=(Cell::boundary_type)i; + break; + } + } + xmlFree(v_str); + } + } + + { + xmlChar *v_str = xmlGetProp(cur, BAD_CAST "div_counter"); + + if (v_str==0) { + unique_warning("Token \"div_counter\" not found in xmlwrite.cpp at or around line no. 1119"); + } + if (v_str != NULL) { + div_counter = atoi( (char *)v_str); + xmlFree(v_str); + } + } + + { + xmlChar *v_str = xmlGetProp(cur, BAD_CAST "cell_type"); + + if (v_str==0) { + unique_warning("Token \"cell_type\" not found in xmlwrite.cpp at or around line no. 1237"); + } + if (v_str != NULL) { + cell_type = atoi( (char *)v_str); + xmlFree(v_str); + } + } + + // Recalculate moments and area + SetIntegrals(); + return 0; + +} + +void NodeSet::XMLRead(xmlNode *root, Mesh *m) { + + xmlNode *n = root->xmlChildrenNode; + + vector tmp_nodes; + while(n!=NULL) { + if ((!xmlStrcmp(n->name, (const xmlChar *)"node"))) { + xmlChar *nc = xmlGetProp(n, BAD_CAST "n"); + + if (nc==0) { + unique_warning("Token \"n\" not found in xmlwrite.cpp at or around line no. 966"); + } + tmp_nodes.push_back(atoi( (char *)nc)); + xmlFree(nc); + } + n = n->next; + } + + int nnodes = tmp_nodes.size(); + for (int i=0;igetNode(tmp_nodes[i])) ); + } + +} + + + + +void Wall::XMLAdd(xmlNode *parent) const { + + // Save the node to a stream so we can reconstruct its state later + xmlNodePtr xmlwall = xmlNewChild(parent, NULL, BAD_CAST "wall",NULL); + + /* { + ostringstream text; + text << index; + xmlNewProp(xmlnode, BAD_CAST "index", BAD_CAST text.str().c_str()); + }*/ + + { + ostringstream text; + text << Index(); + xmlNewProp(xmlwall, BAD_CAST "index" , BAD_CAST text.str().c_str() ); + } + + { + ostringstream text; + text << c1->Index(); + xmlNewProp(xmlwall, BAD_CAST "c1", BAD_CAST text.str().c_str()); + } + + + { + ostringstream text; + text << c2->Index(); + xmlNewProp(xmlwall, BAD_CAST "c2", BAD_CAST text.str().c_str()); + } + + + { + ostringstream text; + text << n1->Index(); + xmlNewProp(xmlwall, BAD_CAST "n1", BAD_CAST text.str().c_str()); + } + + { + ostringstream text; + text << n2->Index(); + xmlNewProp(xmlwall, BAD_CAST "n2", BAD_CAST text.str().c_str()); + } + + { + ostringstream text; + text << length; + xmlNewProp(xmlwall, BAD_CAST "length", BAD_CAST text.str().c_str()); + } + + + { + ostringstream text; + text << viz_flux; + xmlNewProp(xmlwall, BAD_CAST "viz_flux", BAD_CAST text.str().c_str()); + } + + { + ostringstream text; + text << WallTypetoStr(wall_type); + xmlNewProp(xmlwall, BAD_CAST "wall_type", BAD_CAST text.str().c_str()); + } + + + xmlNodePtr tr1_xml = xmlNewChild(xmlwall, NULL, BAD_CAST "transporters1", NULL); + // { + // ostringstream text; + // text << Cell::nchem; + // xmlNewProp(tr1_xml, BAD_CAST "n", BAD_CAST text.str().c_str()); + // } + + if (transporters1) { + for (int i=0;i XMLIO::XMLReadValArray(xmlNode *cur) { + + vector result; + + xmlNode *valarray_node = cur->xmlChildrenNode; + while (valarray_node!=NULL) { + if (!xmlStrcmp(valarray_node->name, (const xmlChar *)"val")) { + xmlChar *vc = xmlGetProp(valarray_node, BAD_CAST "v"); + if (vc) { + result.push_back(strtod( (const char *)vc, 0)); + xmlFree(vc); + } + + } + valarray_node = valarray_node->next; + } + return result; +} + +void Mesh::XMLSave(const char *docname, xmlNode *options) const +{ + + // based on libxml2 example code "tree2.c" + + xmlDocPtr doc = NULL; /* document pointer */ + xmlNodePtr root_node = NULL;/* node pointers */ + //xmlDtdPtr dtd = NULL; /* DTD pointer */ + + // LIBXML_TEST_VERSION; + + /* + * Creates a new document, a node and set it as a root node + */ + doc = xmlNewDoc(BAD_CAST "1.0"); + root_node = xmlNewNode(NULL, BAD_CAST "leaf"); + xmlDocSetRootElement(doc, root_node); + + /* + * xmlNewProp() creates attributes, which is "attached" to an node. + * It returns xmlAttrPtr, which isn't used here. + */ + xmlNewProp(root_node, BAD_CAST "name", BAD_CAST docname); + + time_t t; + std::time(&t); + // asctime_r(localtime(&t),tstring); //Doesn't work for MinGW + char *tstring = strdup(asctime(localtime(&t))); // but this does + // replace "end of line character by '\0' + char *eol=strchr(tstring,'\n'); + if (eol!=NULL) + *eol='\0'; + + xmlNewProp(root_node, BAD_CAST "date", BAD_CAST tstring); + free(tstring); + + + QString simtime = QString("%1").arg(time); + xmlNewProp(root_node, BAD_CAST "simtime", BAD_CAST simtime.toStdString().c_str()); + /* + * Creates a DTD declaration. Isn't mandatory. + */ + //dtd = xmlCreateIntSubset(doc, BAD_CAST "root", NULL, BAD_CAST "tree2.dtd"); + par.XMLAdd(root_node); + XMLIO::XMLWriteLeafSourceCode(root_node); + XMLIO::XMLWriteReactionsCode(root_node); + + xmlNodePtr xmlnodes = xmlNewChild(root_node, NULL, BAD_CAST "nodes",NULL); + { ostringstream text; + text << NNodes(); + xmlNewProp(xmlnodes, BAD_CAST "n", BAD_CAST text.str().c_str()); + } + + { ostringstream text; + text << Node::target_length; + xmlNewProp(xmlnodes, BAD_CAST "target_length", BAD_CAST text.str().c_str()); + } + + + + for (vector::const_iterator i=nodes.begin(); + i!=nodes.end(); + i++) { + (*i)->XMLAdd(xmlnodes) ; + } + + + /* + * xmlNewChild() creates a new node, which is "attached" as child node + * of root_node node. + */ + xmlNodePtr xmlcells = xmlNewChild(root_node, NULL, BAD_CAST "cells",NULL); + { + ostringstream text; + text << NCells(); + xmlNewProp(xmlcells, BAD_CAST "n", BAD_CAST text.str().c_str()); + } + { + ostringstream text; + text << Cell::offset[0]; + xmlNewProp(xmlcells, BAD_CAST "offsetx", BAD_CAST text.str().c_str()); + } + + { + ostringstream text; + text << Cell::offset[1]; + xmlNewProp(xmlcells, BAD_CAST "offsety", BAD_CAST text.str().c_str()); + } + + { + ostringstream text; + text << Cell::factor; + xmlNewProp(xmlcells, BAD_CAST "magnification", BAD_CAST text.str().c_str()); + } + + { + ostringstream text; + text << cells.front()->BaseArea(); + xmlNewProp(xmlcells, BAD_CAST "base_area", BAD_CAST text.str().c_str()); + } + + { + ostringstream text; + text << Cell::NChem(); + xmlNewProp(xmlcells, BAD_CAST "nchem", BAD_CAST text.str().c_str()); + } + + for (vector::const_iterator i=cells.begin(); + i!=cells.end(); + i++) { + (*i)->XMLAdd(xmlcells) ; + } + + boundary_polygon->XMLAdd(xmlcells); + + xmlNodePtr xmlwalls = xmlNewChild(root_node, NULL, BAD_CAST "walls",NULL); + { + ostringstream text; + text << walls.size(); + xmlNewProp(xmlwalls, BAD_CAST "n", BAD_CAST text.str().c_str()); + } + + + for (list::const_iterator i=walls.begin(); + i!=walls.end(); + i++) { + (*i)->XMLAdd(xmlwalls) ; + } + + + xmlNodePtr xmlnodesets = xmlNewChild(root_node, NULL, BAD_CAST "nodesets",NULL); + { + ostringstream text; + text << node_sets.size(); + xmlNewProp(xmlnodesets, BAD_CAST "n", BAD_CAST text.str().c_str()); + } + + + for_each( node_sets.begin(), node_sets.end(), + bind2nd ( + mem_fun( &NodeSet::XMLAdd ), + xmlnodesets + ) ); + + + // Add option tree for interactive application + if (options) { + xmlAddChild(root_node, options); + } + + + + + /* + * Dumping document to stdio or file + */ + xmlSetDocCompressMode(doc,9); + xmlSaveFormatFileEnc(docname, doc, "UTF-8", 1); + + /*free the document */ + xmlFreeDoc(doc); + + /* + *Free the global variables that may + *have been allocated by the parser. + */ + xmlCleanupParser(); + + /* + * this is to debug memory for regression tests + */ + //xmlMemoryDump(); +} + + + +void Mesh::XMLReadSimtime(const xmlNode *a_node) { + + xmlNode *root_node; + root_node = (xmlNode *)a_node; + xmlNode *cur; + xmlChar *strsimtime = xmlGetProp(root_node, BAD_CAST "simtime"); + if (strsimtime) { + double simtime = strtod((const char *)strsimtime, 0); + time = simtime; + cerr << "Simtime = " << strsimtime << endl; + } else { + cerr << "No simtime found in file \n"; + time =0; + } +} + +void Mesh::XMLReadPars(const xmlNode * a_node) { + xmlNode *root_node; + root_node = (xmlNode *)a_node; + par.XMLRead(root_node); + Seed(par.rseed); + MakeDir(par.datadir); +} + +void Mesh::XMLReadGeometry(const xmlNode * a_node) +{ + xmlNode *root_node; + root_node = (xmlNode *)a_node; + xmlNode *cur; + + // allocate Nodes + cur = root_node->xmlChildrenNode; + while (cur!=NULL) { + if ((!xmlStrcmp(cur->name, (const xmlChar *)"nodes"))){ + XMLReadNodes(cur); + } + cur=cur->next; + } + + cur = root_node->xmlChildrenNode; + while (cur!=NULL) { + if ((!xmlStrcmp(cur->name, (const xmlChar *)"nodesets"))) { + XMLReadNodeSets(cur); + } + cur=cur->next; + } + + cur=root_node->xmlChildrenNode; + while (cur!=NULL) { + if ((!xmlStrcmp(cur->name, (const xmlChar *)"nodes"))) { + XMLReadNodeSetsToNodes(cur); + } + cur = cur->next; + } + + //cur = root_node; + + // allocate Cells + cur = root_node; + + // allocate Cells + cur = cur->xmlChildrenNode; + while (cur!=NULL) { + if ((!xmlStrcmp(cur->name, (const xmlChar *)"cells"))){ + xmlChar *offsetxc = xmlGetProp(cur, BAD_CAST "offsetx"); + xmlChar *offsetyc = xmlGetProp(cur, BAD_CAST "offsety"); + double ox = strtod((const char*)offsetxc, 0); + double oy = strtod((const char*)offsetyc, 0); + + Cell::setOffset(ox, oy); + xmlFree(offsetxc); + xmlFree(offsetyc); + + xmlChar *magnificationc = xmlGetProp(cur, BAD_CAST "magnification"); + Cell::SetMagnification(strtod((const char*)magnificationc, 0 )); + xmlFree(magnificationc); + + xmlChar *baseareac = xmlGetProp(cur, BAD_CAST "base_area"); + Cell::BaseArea()= strtod((const char *)baseareac, 0 ); + xmlFree(baseareac); + + + XMLReadCells(cur); + } + cur=cur->next; + } + + // allocate Walls (we need to have read the cells before constructing walls) + vector tmp_walls; + cur = root_node->xmlChildrenNode; + while (cur!=NULL) { + if ((!xmlStrcmp(cur->name, (const xmlChar *)"walls"))){ + XMLReadWalls(cur, &tmp_walls); + } + cur=cur->next; + } + + // read walls to cells and boundary_polygon + cur = root_node->xmlChildrenNode; + while (cur!=NULL) { + if ((!xmlStrcmp(cur->name, (const xmlChar *)"cells"))) { + XMLReadWallsToCells(cur, &tmp_walls); + } + cur=cur->next; + } + + boundary_polygon->ConstructNeighborList(); + boundary_polygon->ConstructConnections(); + + for (vector::iterator c=cells.begin(); + c!=cells.end(); + c++) { + + (*c)->ConstructNeighborList(); + (*c)->ConstructConnections(); + + } + + shuffled_cells.clear(); + shuffled_cells = cells; + + MyUrand r(shuffled_cells.size()); + random_shuffle(shuffled_cells.begin(),shuffled_cells.end(),r); + +} + +void Mesh::XMLParseTree(const xmlNode *root_node) { + + XMLReadSimtime(root_node); + XMLReadPars(root_node); + XMLReadGeometry(root_node); + +} + + +void Mesh::XMLReadNodes(xmlNode *root) { + + xmlNode *cur = root; + cur = cur->xmlChildrenNode; + + for (vector::iterator i=nodes.begin(); + i!=nodes.end(); + i++) { + delete *i; + } + + nodes.clear(); + Node::nnodes=0; + + xmlChar *tlc = xmlGetProp(root, BAD_CAST "target_length"); + + if (tlc != 0) { + Node::target_length = strtod( (const char *)tlc, 0 ); + xmlFree(tlc); + } else { + // note that libxml2 also defines a token "warning" + MyWarning::unique_warning("Warning: value found in XML file for Node::target_length."); + } + + while (cur!=NULL) { + if ((!xmlStrcmp(cur->name, (const xmlChar *)"node"))){ + + xmlChar *xc = xmlGetProp(cur, BAD_CAST "x"); + + if (xc==0) { + unique_warning("Token \"x\" not found in xmlwrite.cpp at or around line no. 722"); + } + + xmlChar *yc = xmlGetProp(cur, BAD_CAST "y"); + + if (yc==0) { + unique_warning("Token \"y\" not found in xmlwrite.cpp at or around line no. 727"); + } + + xmlChar *fixedc = xmlGetProp(cur, BAD_CAST "fixed"); + if (fixedc==0) { + unique_warning("Token \"fixed\" not found in xmlwrite.cpp at or around line."); + } + + xmlChar *boundaryc = xmlGetProp(cur, BAD_CAST "boundary"); + if (boundaryc==0) { + unique_warning("Token \"boundary\" not found in xmlwrite.cpp at or around line."); + } + + xmlChar *samc = xmlGetProp(cur, BAD_CAST "sam"); + if (samc==0) { + unique_warning("Token \"sam\" not found in xmlwrite.cpp at or around line."); + } + + double x = strtod( (char *)xc , 0); + double y = strtod( (char *)yc , 0 ); + + Node *new_node = new Node(x,y); + nodes.push_back(new_node); + + new_node->m = this; + new_node->fixed = strtobool( (char *)fixedc); + new_node->boundary = strtobool( (char *)boundaryc ); + new_node->sam = strtobool ( (char *)samc); + new_node->node_set = 0; + + xmlFree(xc); + xmlFree(yc); + xmlFree(boundaryc); + xmlFree(fixedc); + xmlFree(samc); + + + } + cur=cur->next; + } + + shuffled_nodes.clear(); + shuffled_nodes = nodes; + + MyUrand r(shuffled_nodes.size()); + random_shuffle(shuffled_nodes.begin(),shuffled_nodes.end(),r); + +} + +void Mesh::XMLReadWalls(xmlNode *root, vector *tmp_walls) { + + xmlNode *cur = root; + cur = cur->xmlChildrenNode; + + for (list::iterator i=walls.begin(); + i!=walls.end(); + i++) { + delete *i; + } + + walls.clear(); + Wall::nwalls = 0; + tmp_walls->clear(); + //Node::nnodes=0; + + + while (cur!=NULL) { + + vector tmp_nodes; + while(cur!=NULL) { + if ((!xmlStrcmp(cur->name, (const xmlChar *)"wall"))) { + + xmlChar *nc = xmlGetProp(cur, BAD_CAST "c1"); + + if (nc==0) { + unique_warning("Token \"c1\" not found in xmlwrite.cpp at or around line no. 777"); + } + int c1 = atoi( (char *)nc); + xmlFree(nc); + + nc = xmlGetProp(cur, BAD_CAST "c2"); + + if ( nc==0) { + unique_warning("Token \"c2\" not found in xmlwrite.cpp at or around line no. 785"); + } + int c2 = atoi( (char *)nc); + xmlFree(nc); + + nc = xmlGetProp(cur, BAD_CAST "n1"); + + if ( nc==0) { + unique_warning("Token \"n1\" not found in xmlwrite.cpp at or around line no. 793"); + } + int n1 = atoi( (char *)nc); + xmlFree(nc); + + nc = xmlGetProp(cur, BAD_CAST "n2"); + + if ( nc==0) { + unique_warning("Token \"n2\" not found in xmlwrite.cpp at or around line no. 801"); + } + int n2 = atoi( (char *)nc); + xmlFree(nc); + + nc = xmlGetProp(cur, BAD_CAST "length"); + + if ( nc==0) { + unique_warning("Token \"length\" not found in xmlwrite.cpp at or around line no. 809"); + } + double length = strtod( (char *)nc, 0); + xmlFree(nc); + + + nc = xmlGetProp(cur, BAD_CAST "viz_flux"); + + double viz_flux; + if (nc!=0) { + viz_flux = strtod( (char *)nc, 0); + } else { + // if the info is not there, we really don't care. + // It is just for visualization anyhow. + viz_flux = 0.; + } + xmlFree(nc); + + Wall::WallType wall_type; + { + xmlChar *v_str = xmlGetProp(cur, BAD_CAST "wall_type"); + + if (v_str != 0) { + + if (!xmlStrcmp(v_str, (const xmlChar *)"aux_source")) { + wall_type = Wall::AuxSource; + } else { + if (!xmlStrcmp(v_str, (const xmlChar *)"aux_sink")) { + wall_type = Wall::AuxSink; + } else { + wall_type = Wall::Normal; + } + } + xmlFree(v_str); + + } else { + wall_type = Wall::Normal; + } + } + + bool dead = false; + { + // Note: property "delete" is used to manually clean up wall lists in XML files + // Simply add property 'delete="true"' to the wall and it will be removed from + // the mesh. (This saves us from manually reindexing the file). Otherwise do not use it. + xmlChar *v_str = xmlGetProp(cur, BAD_CAST "delete"); + + if (v_str != 0) { + dead = strtobool( (char *)v_str); + xmlFree(v_str); + } + + } + + Cell *cc1 = c1 != -1 ? cells[c1] : boundary_polygon; + Cell *cc2 = c2 != -1 ? cells[c2] : boundary_polygon; + + Wall *w = new Wall( nodes[n1], nodes[n2], cc1, cc2); + w->length = length; + w->viz_flux = viz_flux; + w->wall_type = wall_type; + w->dead = dead; + tmp_walls->push_back(w); + walls.push_back(w); + + xmlNode *w_node = cur->xmlChildrenNode; + while (w_node!=NULL) { + if ((!xmlStrcmp(w_node->name, (const xmlChar *)"transporters1"))) { + + xmlNode *v_node = w_node->xmlChildrenNode; + int nv=0; + while (v_node!=NULL) { + + if ((!xmlStrcmp(v_node->name, (const xmlChar *)"val"))) { + if (nv>=Cell::NChem()) { + { + stringstream text; + text << "Exception in Mesh::XMLRead: Too many transporter values given for wall(s). Ignoring remaining values."; + //ThrowStringStream(text); + unique_warning(text.str().c_str()); + break; + } + } + xmlChar *nc = xmlGetProp(v_node, (const xmlChar *) "v"); + + if (nc==0) { + unique_warning("Token \"v\" not found in xmlwrite.cpp at or around line no. 835"); + } + double v = strtod( (char *)nc, 0 ); + w->transporters1[nv++]=v; + xmlFree(nc); + + } + v_node = v_node->next; + } + + } + + + if ((!xmlStrcmp(w_node->name, (const xmlChar *)"transporters2"))) { + + xmlNode *v_node = w_node->xmlChildrenNode; + int nv=0; + while (v_node!=NULL) { + if ((!xmlStrcmp(v_node->name, (const xmlChar *)"val"))) { + if (nv>=Cell::NChem()) { + { + stringstream text; + text << "Exception in Mesh::XMLRead: Too many transporter values given for wall(s). Ignoring remaining values."; + unique_warning(text.str().c_str()); + break; + // ThrowStringStream(text); + } + } + + xmlChar *nc = xmlGetProp(v_node, (const xmlChar *) "v"); + + if (nc==0) { + unique_warning("Token \"v\" not found in xmlwrite.cpp at or around line no. 861"); + } + double v = strtod( (char *)nc, 0 ); + w->transporters2[nv++]=v; + xmlFree(nc); + } + v_node = v_node->next; + } + + } + + if ((!xmlStrcmp(w_node->name, (const xmlChar *)"apoplast"))) { + + xmlNode *v_node = w_node->xmlChildrenNode; + int nv=0; + while (v_node!=NULL) { + + if ((!xmlStrcmp(v_node->name, (const xmlChar *)"val"))) { + if (nv>=Cell::NChem()) { + { + stringstream text; + text << "Exception in Mesh::XMLRead: Too many transporter values given for wall(s). Ignoring remaining values."; + //ThrowStringStream(text); + unique_warning(text.str().c_str()); + break; + } + } + xmlChar *nc = xmlGetProp(v_node, (const xmlChar *) "v"); + + if (nc==0) { + unique_warning("Token \"v\" not found in xmlwrite.cpp at or around line no. 887"); + } + double v = strtod( (char *)nc, 0 ); + w->apoplast[nv++]=v; + xmlFree(nc); + } + v_node = v_node->next; + } + + } + w_node=w_node->next; + } + + } + cur = cur->next; + } + + } + // CleanUpWalls(); +} + + +void Mesh::XMLReadWallsToCells(xmlNode *root, vector *tmp_walls) { + + // Add the walls to the cells (do this after reading the walls; read walls after reading cells...) + // 1. Read Nodes + // 2. Read Cells + // 3. Read Walls + // 4. Read Walls into Cells + + xmlNode *cur = root->xmlChildrenNode; + int ci=0; // cell index + + while (cur!=NULL) { + + //Cell *new_cell=0; + + if ((!xmlStrcmp(cur->name, (const xmlChar *)"cell")) || + (!xmlStrcmp(cur->name, (const xmlChar *)"boundary_polygon" ))) { + + vector tmp_walls_ind; + xmlNode *n = cur->xmlChildrenNode; + + while(n!=NULL) { + + if ((!xmlStrcmp(n->name, (const xmlChar *)"wall"))) { + xmlChar *nc = xmlGetProp(n, BAD_CAST "w"); + + if (nc==0) { + unique_warning("Token \"w\" not found in xmlwrite.cpp at or around line no. 931"); + } + tmp_walls_ind.push_back(atoi( (char *)nc)); + xmlFree(nc); + } + n = n->next; + } + + if (!xmlStrcmp(cur->name, (const xmlChar *)"boundary_polygon")) { + + int nwalls = tmp_walls_ind.size(); + for (int i=0;iwalls.push_back((*tmp_walls)[tmp_walls_ind[i]]); + } + } else { + + int nwalls = tmp_walls_ind.size(); + for (int i=0;iwalls.push_back((*tmp_walls)[tmp_walls_ind[i]]); + } + + ci++; + } + + } + cur=cur->next; + } + + +} + + +void Mesh::XMLReadNodeSetsToNodes(xmlNode *root) { + + xmlNode *cur = root->xmlChildrenNode; + int ci=0; // cell index + + while (cur!=NULL) { + + + + if ((!xmlStrcmp(cur->name, (const xmlChar *)"node"))) { + + xmlNode *n = cur->xmlChildrenNode; + + while(n!=NULL) { + + xmlChar *nc = xmlGetProp(n, BAD_CAST "nodeset"); + + if (nc!=0) { + int nodeset_n = atoi( (char *)nc); + nodes[ci]->node_set = node_sets[nodeset_n]; + xmlFree(nc); + } else { + nodes[ci]->node_set = 0; + } + + n = n->next; + } + + ci++; + + } + cur=cur->next; + } + + +} + + +void Mesh::XMLReadNodeSets(xmlNode *root) { + + for (vector::iterator i=node_sets.begin(); + i!=node_sets.end(); + i++) { + delete *i; + } + + node_sets.clear(); + + xmlNode *cur = root->xmlChildrenNode; + + while (cur!=NULL) { + + NodeSet *new_nodeset=0; + + if ((!xmlStrcmp(cur->name, (const xmlChar *)"nodeset"))){ + new_nodeset = new NodeSet(); + node_sets.push_back(new_nodeset); + } + + if (new_nodeset == 0) { + cur = cur->next; + continue; + } + new_nodeset->XMLRead(cur, this); + cur=cur->next; + } + +} + +void Mesh::XMLReadCells(xmlNode *root) { + + for (vector::iterator i=cells.begin(); + i!=cells.end(); + i++) { + delete *i; + } + + cells.clear(); + Cell::NCells() = 0; + + delete boundary_polygon; + + + xmlNode *cur = root->xmlChildrenNode; + + while (cur!=NULL) { + + Cell *new_cell=0; + static int count=0; + if ((!xmlStrcmp(cur->name, (const xmlChar *)"cell"))){ + + new_cell = new Cell(0,0); + new_cell->m = this; + cells.push_back(new_cell); + } else { + if ((!xmlStrcmp(cur->name, (const xmlChar *)"boundary_polygon"))) { + new_cell = boundary_polygon = new BoundaryPolygon(0,0); + boundary_polygon->m = this; + } + } + + if (new_cell == 0) { + cur = cur->next; + continue; + } + + new_cell->XMLRead(cur); + cur=cur->next; + } + +} + +void Mesh::XMLRead(const char *docname, xmlNode **settings, bool geometry, bool pars, bool simtime) { + + xmlDocPtr doc = xmlParseFile(docname); + if (doc == NULL ) { + throw("Document not parsed successfully."); + return; + } + + xmlNodePtr cur = xmlDocGetRootElement(doc); + + if (cur == NULL) { + throw("Document is empty"); + xmlFreeDoc(doc); + return; + } + + if (xmlStrcmp(cur->name, (const xmlChar *) "leaf")) { + throw("XML file of the wrong type, it is not a leaf."); + xmlFreeDoc(doc); + return; + } + + /*Get the root element node */ + xmlNode *root_element = xmlDocGetRootElement(doc); + + //XMLParseTree(root_element); + if (geometry) XMLReadGeometry(root_element); + if (pars) XMLReadPars(root_element); + if (simtime) XMLReadSimtime(root_element); + //print_element_names(root_element); + + // If pointer settings defined, return a copy of the settings tree + if (settings) { + xmlNode *cur = root_element->xmlChildrenNode; + // if settings field is not found, *settings will be returned 0. + *settings = 0; + while (cur!=NULL) { + if ((!xmlStrcmp(cur->name, (const xmlChar *)"settings"))){ + *settings = xmlCopyNode(cur,1); + } + cur=cur->next; + } + } + xmlFreeDoc(doc); + + /* + *Free the global variables that may + *have been allocated by the parser. + */ + xmlCleanupParser(); + + // We're doing this so we can manually delete walls with by adding the 'delete="true"' property + CleanUpCellNodeLists(); + +} + + +/* int Mesh::XMLReadWall(xmlNode *cur) { + + + return w; + }*/ +void Parameter::XMLRead(xmlNode *root) { + + xmlNode *cur = root->xmlChildrenNode; + while (cur!=NULL) { + if ((!xmlStrcmp(cur->name, (const xmlChar *)"parameter"))){ + xmlNode *par_node = cur->xmlChildrenNode; + while (par_node!=NULL) { + { + if (!xmlStrcmp(par_node->name, (const xmlChar *)"par")) { + xmlChar *namec = xmlGetProp(par_node, BAD_CAST "name"); + xmlChar *valc = xmlGetProp(par_node, BAD_CAST "val"); + if (valc) { + AssignValToPar((const char*)namec,(const char*)valc); + } else { + /* Probably a valarray */ + xmlNode *sub_par_node = par_node->xmlChildrenNode; + vector valarray; + while (sub_par_node != NULL) { + if (!xmlStrcmp(sub_par_node->name, (const xmlChar *)"valarray")) { + valarray = XMLIO::XMLReadValArray(sub_par_node); + } + sub_par_node = sub_par_node->next; + } + AssignValArrayToPar((const char*)namec, valarray); + } + } + } + par_node = par_node->next; + } + + } + cur=cur->next; + } + +} +