1 //////////////////////////////////////////////////////////////////////////////////////
2 // This file is distributed under the University of Illinois/NCSA Open Source License.
3 // See LICENSE file in top directory for details.
4 //
5 // Copyright (c) 2020 QMCPACK developers.
6 //
7 // File developed by: Ken Esler, kpesler@gmail.com, University of Illinois at Urbana-Champaign
8 // Jeremy McMinnis, jmcminis@gmail.com, University of Illinois at Urbana-Champaign
9 // Jeongnim Kim, jeongnim.kim@gmail.com, University of Illinois at Urbana-Champaign
10 // Mark A. Berrill, berrillma@ornl.gov, Oak Ridge National Laboratory
11 //
12 // File created by: Jeongnim Kim, jeongnim.kim@gmail.com, University of Illinois at Urbana-Champaign
13 //////////////////////////////////////////////////////////////////////////////////////
14
15
16 #include <string>
17 #include <vector>
18 #include <utility>
19 #include <iostream>
20 #include <fstream>
21 #include "OhmmsData/FileUtility.h"
22 #include "OhmmsData/AttributeSet.h"
23 #include "OhmmsData/ParameterSet.h"
24 #include "ParticleIO/ParticleLayoutIO.h"
25 #include "XMLParticleIO.h"
26 #include "ParticleIO/ParticleIOUtility.h"
27 #include "ParticleBase/RandomSeqGenerator.h"
28 #include "Utilities/ProgressReportEngine.h"
29 namespace qmcplusplus
30 {
31 /** set the property of a SpeciesSet
32 * @param tspecies SpeciesSet
33 * @param sid id of the species whose properties to be set
34 *
35 * Need unit handlers but for now, everything is in AU:
36 * m_e=1.0, hartree and bohr and unit="au"
37 * Example to define C(arbon)
38 * <group name="C">
39 * <parameter name="mass" unit="amu">12</parameter>
40 * <parameter name="charge">-6</parameter>
41 * </group>
42 * Note that unit="amu" is given for the mass.
43 * When mass is not given, they are set to the electron mass.
44 */
setSpeciesProperty(SpeciesSet & tspecies,int sid,xmlNodePtr cur)45 void setSpeciesProperty(SpeciesSet& tspecies, int sid, xmlNodePtr cur)
46 {
47 const double proton_mass = 1822.888530063;
48 cur = cur->xmlChildrenNode;
49 while (cur != NULL)
50 {
51 std::string cname((const char*)cur->name);
52 if (cname == "parameter")
53 {
54 std::string pname;
55 std::string unit_name("au"); //hartree, bohr & me=1
56 OhmmsAttributeSet pAttrib;
57 pAttrib.add(pname, "name");
58 pAttrib.add(unit_name, "unit");
59 pAttrib.put(cur);
60 if (pname.size())
61 {
62 int iproperty = tspecies.addAttribute(pname);
63 double ap = 0.0;
64 double unit_conv = 1.0;
65 putContent(ap, cur);
66 if (pname == "mass")
67 {
68 if (unit_name == "amu")
69 unit_conv = proton_mass;
70 }
71 tspecies(iproperty, sid) = ap * unit_conv;
72 }
73 }
74 cur = cur->next;
75 }
76 }
77
78
XMLParticleParser(Particle_t & aptcl,Tensor<int,OHMMS_DIM> & tmat,bool donotresize)79 XMLParticleParser::XMLParticleParser(Particle_t& aptcl, Tensor<int, OHMMS_DIM>& tmat, bool donotresize)
80 : AssignmentOnly(donotresize), ref_(aptcl), TileMatrix(tmat)
81 {
82 //add ref particle attributes
83 ref_.createAttributeList(ref_AttribList);
84 }
85
86 /**reading particleset node from a file
87 *@param fname_in a file name to open
88 *@param pformat_in the format of the file, not used
89 *@return true, if successful
90 *
91 *Check the type of the external source to work on.
92 *The external source itself can be an xml file.
93 */
put(const std::string & fname_in,const std::string & fext_in)94 bool XMLParticleParser::put(const std::string& fname_in, const std::string& fext_in)
95 {
96 xmlDocPtr doc = NULL;
97 // build an XML tree from a the file;
98 doc = xmlParseFile(fname_in.c_str());
99 if (doc == NULL)
100 {
101 ERRORMSG(fname_in << " does not exist")
102 return false;
103 }
104 ///using XPath instead of recursive search
105 xmlXPathContextPtr context;
106 xmlXPathObjectPtr result;
107 context = xmlXPathNewContext(doc);
108 result = xmlXPathEvalExpression((const xmlChar*)"//particleset", context);
109 if (xmlXPathNodeSetIsEmpty(result->nodesetval))
110 {
111 app_error() << fname_in << " does not contain any ParticleSet" << std::endl;
112 }
113 else
114 {
115 xmlNodePtr cur = result->nodesetval->nodeTab[0];
116 std::string fname, pformat;
117 OhmmsAttributeSet pAttrib;
118 pAttrib.add(fname, "src");
119 pAttrib.add(fname, "href");
120 pAttrib.add(pformat, "srctype");
121 pAttrib.put(cur);
122 if (fname.size())
123 pformat = getExtension(fname);
124 if (pformat.empty())
125 putSpecial(cur);
126 //else
127 //{
128 // if(pformat == "h5") {
129 // HDFParticleParser ahandle(ref_);
130 // ahandle.put(cur);
131 // } else {
132 // app_error() << " Unknown file extension " << pformat << std::endl;
133 // }
134 //}
135 }
136 //free local objects
137 xmlXPathFreeObject(result);
138 xmlXPathFreeContext(context);
139 xmlFreeDoc(doc);
140 return true;
141 }
142
143 /** process xmlnode <particleset/>
144 *@param cur the xmlnode to work on
145 *
146 *If the node has src or href attribute, use an external file.
147 */
put(xmlNodePtr cur)148 bool XMLParticleParser::put(xmlNodePtr cur)
149 {
150 ///process attributes: type or format
151 std::string fname, pformat("xml");
152 OhmmsAttributeSet pAttrib;
153 pAttrib.add(fname, "src");
154 pAttrib.add(fname, "href");
155 pAttrib.add(pformat, "srctype");
156 pAttrib.put(cur);
157 if (fname.empty())
158 return putSpecial(cur);
159 else
160 {
161 //overwrite the format
162 pformat = getExtension(fname);
163 return put(fname, pformat);
164 }
165 }
166
167
168 /** process xmlnode <particleset/> which contains everything about the particle set to initialize
169 *@param cur the xmlnode to work on
170 *
171 */
putSpecial(xmlNodePtr cur)172 bool XMLParticleParser::putSpecial(xmlNodePtr cur)
173 {
174 ReportEngine PRE("XMLParticleParser", "putSpecial");
175 std::string pname("none");
176 //xmlDocPtr doc = cur->doc;
177 //the number of particles that are initialized by <attrib/>
178 int nat = 0;
179 std::string randomizeR("no");
180 OhmmsAttributeSet pAttrib;
181 pAttrib.add(randomizeR, "random");
182 pAttrib.add(nat, "size");
183 pAttrib.add(pname, "name");
184 pAttrib.put(cur);
185 ///count the number of atom added one by one
186 xmlNodePtr cur0 = cur->xmlChildrenNode;
187 //total count of the particles to be created
188 int ntot = 0;
189 int ng = 0, ng_in = 0;
190 std::vector<int> nat_group;
191 std::vector<xmlNodePtr> atom_ptr;
192 //pre-process the nodes to count the number of particles to be added
193 while (cur0 != NULL)
194 {
195 std::string cname((const char*)cur0->name);
196 if (cname == "atom")
197 {
198 ntot++;
199 atom_ptr.push_back(cur0);
200 }
201 else if (cname == "group")
202 {
203 int nat_per_group = 0;
204 OhmmsAttributeSet gAttrib;
205 gAttrib.add(nat_per_group, "size");
206 gAttrib.put(cur0);
207 nat_group.push_back(nat_per_group);
208 ng_in += nat_per_group;
209 ntot += nat_per_group;
210 ng++;
211 }
212 else if (cname == attrib_tag)
213 {
214 int size_att = 0;
215 OhmmsAttributeSet aAttrib;
216 aAttrib.add(size_att, "size");
217 aAttrib.put(cur0);
218 if (size_att)
219 {
220 if (size_att != nat)
221 {
222 app_warning() << "\tOverwriting the size of the particle by //particleset/attrib/@size=" << size_att
223 << std::endl;
224 nat = size_att;
225 }
226 }
227 }
228 cur0 = cur0->next;
229 }
230 ntot += nat;
231 ref_.setName(pname.c_str());
232 int nloc = ref_.getTotalNum();
233 //treat assignment only differently
234 if (AssignmentOnly)
235 {
236 ntot = 0;
237 nloc = 0;
238 for (int iat = 0; iat < ref_.getTotalNum(); iat++)
239 ref_.ID[iat] = iat;
240 }
241 if (ntot)
242 {
243 if (ng_in)
244 {
245 ref_.create(nat_group);
246 }
247 else
248 {
249 ref_.create(ntot);
250 }
251 //assign default ID
252 int nloci = nloc;
253 for (int iat = 0; iat < ntot; iat++, nloci++)
254 ref_.ID[iat] = nloci;
255 }
256 //TinyVector<int,OHMMS_DIM> uc_grid(1);
257 SpeciesSet& tspecies(ref_.getSpeciesSet()); //SpeciesCollection::getSpecies();
258 cur = cur->xmlChildrenNode;
259 //reset the group counter
260 ng = 0;
261 while (cur != NULL)
262 {
263 std::string cname((const char*)(cur->name));
264 if (cname.find("ell") < cname.size()) //accept UnitCell, unitcell, supercell
265 {
266 //if(cname == "UnitCell" || cname == "unitcell") {
267 LatticeParser lat(ref_.Lattice);
268 lat.put(cur);
269 //ParameterSet params;
270 //params.add(uc_grid,"uc_grid");
271 //params.put(cur);
272 }
273 else if (cname == attrib_tag)
274 {
275 getPtclAttrib(cur, nat, nloc);
276 }
277 else if (cname == "group")
278 //found group
279 {
280 std::string sname;
281 OhmmsAttributeSet gAttrib;
282 gAttrib.add(sname, "name");
283 gAttrib.put(cur);
284 if (sname.size()) //only if name is found
285 {
286 int sid = tspecies.addSpecies(sname);
287 setSpeciesProperty(tspecies, sid, cur);
288 xmlNodePtr tcur = cur->xmlChildrenNode;
289 while (tcur != NULL)
290 {
291 std::string tcname((const char*)tcur->name);
292 if (nat_group[ng] && tcname == attrib_tag)
293 {
294 getPtclAttrib(tcur, nat_group[ng], nloc);
295 }
296 tcur = tcur->next;
297 }
298 for (int iat = 0; iat < nat_group[ng]; iat++, nloc++)
299 ref_.GroupID[nloc] = sid;
300 ng++;
301 }
302 }
303 cur = cur->next;
304 }
305
306 //copy ID -> PCID
307 ref_.PCID = ref_.ID;
308
309 expandSuperCell(ref_, TileMatrix);
310 if (ref_.Lattice.SuperCellEnum)
311 {
312 if (randomizeR == "yes")
313 {
314 makeUniformRandom(ref_.R);
315 ref_.R.setUnit(PosUnit::Lattice);
316 ref_.convert2Cart(ref_.R);
317 #if !defined(QMC_CUDA)
318 makeUniformRandom(ref_.spins);
319 ref_.spins *= 2 * M_PI;
320 #endif
321 }
322 else // put them [0,1) in the cell
323 ref_.applyBC(ref_.R);
324 }
325
326 //this sets Mass, Z
327 ref_.resetGroups();
328 ref_.createSK();
329
330 return true;
331 }
332
333 /** process xmlnode to reset the properties of a particle set
334 * @param cur current node
335 * @return true, if successful
336 *
337 * This resets or adds new attributes to a particle set.
338 * It cannot modify the size of the particle set.
339 */
reset(xmlNodePtr cur)340 bool XMLParticleParser::reset(xmlNodePtr cur)
341 {
342 ReportEngine PRE("XMLParticleParser", "reset");
343 SpeciesSet& tspecies(ref_.getSpeciesSet());
344 cur = cur->xmlChildrenNode;
345 while (cur != NULL)
346 {
347 std::string cname((const char*)cur->name);
348 if (cname == "group")
349 {
350 std::string sname;
351 OhmmsAttributeSet gAttrib;
352 gAttrib.add(sname, "name");
353 gAttrib.put(cur);
354 if (sname.size())
355 {
356 int sid = tspecies.addSpecies(sname);
357 setSpeciesProperty(tspecies, sid, cur);
358 }
359 }
360 cur = cur->next;
361 }
362 // //@todo Will add a member function to ParticleSet to handle these
363 // int massind=tspecies.addAttribute("mass");
364 // for(int iat=0; iat<ref_.getTotalNum(); iat++)
365 // ref_.Mass[iat]=tspecies(massind,ref_.GroupID[iat]);
366 //
367 // int qind=tspecies.addAttribute("charge");
368 // for(int iat=0; iat<ref_.getTotalNum(); iat++)
369 // ref_.Z[iat]=tspecies(qind,ref_.GroupID[iat]);
370 //
371 return true;
372 }
373
374 template<typename PAT>
375 struct ParticleAttribXmlNode
376 {
377 PAT& ref_;
378
ParticleAttribXmlNodeqmcplusplus::ParticleAttribXmlNode379 inline ParticleAttribXmlNode(PAT& a, PosUnit utype) : ref_(a) { ref_.InUnit = utype; }
380
putqmcplusplus::ParticleAttribXmlNode381 inline bool put(xmlNodePtr cur, int n_in, int start)
382 {
383 typedef typename PAT::Type_t data_type;
384 std::vector<data_type> data_in(n_in);
385 putContent(data_in, cur);
386 copy(data_in.begin(), data_in.end(), ref_.begin() + start);
387 return true;
388 }
389 };
390
getPtclAttrib(xmlNodePtr cur,int nat,int nloc)391 void XMLParticleParser::getPtclAttrib(xmlNodePtr cur, int nat, int nloc)
392 {
393 std::string oname, otype;
394 int utype = 0;
395 int size_in = 0;
396 OhmmsAttributeSet pAttrib;
397 pAttrib.add(otype, datatype_tag); //datatype
398 pAttrib.add(oname, "name"); //name
399 pAttrib.add(utype, condition_tag); //condition
400 pAttrib.add(size_in, "size"); //size
401 pAttrib.put(cur);
402 if (oname.empty() || otype.empty())
403 {
404 app_error() << " Missing attrib/@name or attrib/@datatype " << std::endl;
405 app_error() << " <attrib name=\"aname\" datatype=\"atype\"/>" << std::endl;
406 return;
407 }
408 int t_id = ref_AttribList.getAttribType(otype);
409
410 if (oname == ionid_tag)
411 {
412 if (otype == stringtype_tag)
413 {
414 int nloci = nloc;
415 std::vector<std::string> d_in(nat);
416 putContent(d_in, cur);
417 for (int iat = 0; iat < d_in.size(); iat++, nloci++)
418 {
419 ref_.GroupID[nloci] = ref_.getSpeciesSet().addSpecies(d_in[iat]);
420 }
421 }
422 else
423 {
424 ParticleAttribXmlNode<ParticleIndex_t> a(ref_.GroupID, static_cast<PosUnit>(utype));
425 a.put(cur, nat, nloc);
426 }
427 }
428 else
429 {
430 //very permissive in that a unregistered attribute will be created and stored by ParticleSet
431 //cloning is not going to work
432 if (t_id == PA_IndexType)
433 {
434 ParticleIndex_t* obj = nullptr;
435 obj = ref_AttribList.getAttribute(otype, oname, obj);
436 ParticleAttribXmlNode<ParticleIndex_t> a(*obj, static_cast<PosUnit>(utype));
437 a.put(cur, nat, nloc);
438 }
439 else if (t_id == PA_ScalarType)
440 {
441 ParticleScalar_t* obj = nullptr;
442 obj = ref_AttribList.getAttribute(otype, oname, obj);
443 ParticleAttribXmlNode<ParticleScalar_t> a(*obj, static_cast<PosUnit>(utype));
444 a.put(cur, nat, nloc);
445 }
446 else if (t_id == PA_PositionType)
447 {
448 ParticlePos_t* obj = nullptr;
449 obj = ref_AttribList.getAttribute(otype, oname, obj);
450 ParticleAttribXmlNode<ParticlePos_t> a(*obj, static_cast<PosUnit>(utype));
451 a.put(cur, nat, nloc);
452 }
453 else if (t_id == PA_TensorType)
454 {
455 ParticleTensor_t* obj = nullptr;
456 obj = ref_AttribList.getAttribute(otype, oname, obj);
457 ParticleAttribXmlNode<ParticleTensor_t> a(*obj, static_cast<PosUnit>(utype));
458 a.put(cur, nat, nloc);
459 }
460 }
461 }
462
463
XMLSaveParticle(Particle_t & pin)464 XMLSaveParticle::XMLSaveParticle(Particle_t& pin) : ref_(pin) {}
465
~XMLSaveParticle()466 XMLSaveParticle::~XMLSaveParticle() {}
467
reset(const char * fileroot,bool append)468 void XMLSaveParticle::reset(const char* fileroot, bool append)
469 {
470 //append is ignored
471 FileRoot = fileroot;
472 FileName = fileroot;
473 FileName.append(".xml");
474 SpeciesName = ref_.getSpeciesSet().speciesName;
475 }
476
report(int iter)477 void XMLSaveParticle::report(int iter)
478 {
479 // writing a meta file
480 std::ofstream fxml(FileName.c_str()); // always overwrite
481 fxml << "<?xml version=\"1.0\"?>" << std::endl;
482 get(fxml, 1);
483 fxml.close();
484 }
485
get(std::ostream & fxml,int olevel) const486 void XMLSaveParticle::get(std::ostream& fxml, int olevel) const
487 {
488 ref_.begin_node(fxml);
489 fxml.setf(std::ios::scientific);
490 fxml.precision(15);
491 LatticeXMLWriter latticeout(ref_.Lattice);
492 latticeout.get(fxml);
493 for (int i = 0; i < SpeciesName.size(); i++)
494 {
495 fxml << "<group name=\"" << SpeciesName[i] << "\"/>" << std::endl;
496 }
497 //only write the local particles
498 int nloc = ref_.getTotalNum();
499 if (olevel)
500 {
501 /*
502 Particle_t::PAListIterator it = ref_.first_attrib();
503 while(it != ref_.last_attrib())
504 {
505 OhmmsObject* ooref= (*it).second;
506 // if(ooref->objName() == ionid_tag) {
507 // IonName.begin_node(fxml);
508 // for(int iat=0; iat<nloc; iat++) {
509 // fxml << IonName[iat] << " ";
510 // if(iat%20 == 19) fxml << std::endl;
511 // }
512 // IonName.end_node(fxml);
513 // } else {
514 int t_id = ref_AttribList.getAttribType(otype);
515 int o_id = ooref->id();
516 ooref->begin_node(fxml);
517 if(t_id == PA_IndexType)
518 {
519 const ParticleIndex_t* itmp=dynamic_cast<ParticleIndex_t*>(ooref);
520 for(int iat=0; iat<nloc; iat++)
521 {
522 fxml << (*itmp)[iat] << " ";
523 if(iat%20 == 19)
524 fxml << std::endl;
525 }
526 }
527 else if(t_id == PA_ScalarType)
528 {
529 fxml.precision(6);
530 const ParticleScalar_t* stmp=dynamic_cast<ParticleScalar_t*>(ooref);
531 for(int iat=0; iat<nloc; iat++)
532 {
533 fxml << (*stmp)[iat] << " ";
534 if(iat%5 == 4)
535 fxml << std::endl;
536 }
537 if(nloc%5 != 0)
538 fxml<< std::endl;
539 }
540 else if (t_id == PA_PositionType)
541 {
542 fxml.precision(15);
543 const ParticlePos_t* rtmp=dynamic_cast<ParticlePos_t*>(ooref);
544 for(int iat=0; iat<nloc; iat++)
545 {
546 fxml << (*rtmp)[iat] << std::endl;
547 }
548 }
549 else if (t_id == PA_TensorType)
550 {
551 fxml.precision(15);
552 const ParticleTensor_t* ttmp=dynamic_cast<ParticleTensor_t*>(ooref);
553 for(int iat=0; iat<nloc; iat++)
554 {
555 fxml << (*ttmp)[iat];
556 }
557 }
558 ooref->end_node(fxml);
559 // }
560 it++;
561 }
562 */
563 }
564 else
565 {
566 ref_.R.begin_node(fxml);
567 for (int iat = 0; iat < nloc; iat++)
568 fxml << ref_.R[iat] << std::endl;
569 ref_.R.end_node(fxml);
570 ref_.GroupID.begin_node(fxml);
571 for (int iat = 0; iat < nloc; iat++)
572 {
573 fxml << ref_.GroupID[iat] << " ";
574 if (iat % 20 == 19)
575 fxml << std::endl;
576 }
577 if (nloc % 20 != 19)
578 fxml << std::endl;
579 ref_.GroupID.end_node(fxml);
580 }
581 ref_.end_node(fxml);
582 }
583
put(xmlNodePtr cur)584 bool XMLSaveParticle::put(xmlNodePtr cur) { return true; }
585
586 /** create particleset node
587 * @param addlattice if true, add unitcell
588 */
createNode(bool addlattice)589 xmlNodePtr XMLSaveParticle::createNode(bool addlattice)
590 {
591 if (SpeciesName.size() != ref_.getSpeciesSet().getTotalNum())
592 {
593 SpeciesName = ref_.getSpeciesSet().speciesName;
594 }
595 //if(addlattice) {
596 // ref_.Lattice.print(std::cout);
597 //}
598 xmlNodePtr cur = xmlNewNode(NULL, (const xmlChar*)"particleset");
599 xmlNewProp(cur, (const xmlChar*)"name", (const xmlChar*)ref_.getName().c_str());
600 if (ref_.groups() > 1)
601 {
602 const SpeciesSet& mySpecies(ref_.getSpeciesSet());
603 int nitem(mySpecies.numAttributes());
604 int nspecies(mySpecies.getTotalNum());
605 for (int is = 0; is < nspecies; is++)
606 {
607 std::ostringstream ng;
608 ng << ref_.last(is) - ref_.first(is);
609 xmlNodePtr g = xmlNewNode(NULL, (const xmlChar*)"group");
610 xmlNewProp(g, (const xmlChar*)"name", (const xmlChar*)SpeciesName[is].c_str());
611 xmlNewProp(g, (const xmlChar*)"size", (const xmlChar*)ng.str().c_str());
612 for (int item = 0; item < nitem; item++)
613 {
614 std::ostringstream prop;
615 prop << mySpecies(item, is);
616 xmlNodePtr p = xmlNewTextChild(g, NULL, (const xmlChar*)"parameter", (const xmlChar*)prop.str().c_str());
617 xmlNewProp(p, (const xmlChar*)"name", (const xmlChar*)mySpecies.attribName[item].c_str());
618 }
619 std::ostringstream pos;
620 pos.setf(std::ios_base::scientific);
621 pos << "\n";
622 for (int iat = ref_.first(is); iat < ref_.last(is); iat++)
623 {
624 pos << ref_.R[iat] << std::endl;
625 }
626 xmlNodePtr posPtr = xmlNewTextChild(g, NULL, (const xmlChar*)"attrib", (const xmlChar*)pos.str().c_str());
627 xmlNewProp(posPtr, (const xmlChar*)"name", (const xmlChar*)"position");
628 xmlNewProp(posPtr, (const xmlChar*)"datatype", (const xmlChar*)"posArray");
629 xmlAddChild(cur, g);
630 }
631 }
632 else
633 {
634 std::ostringstream nat;
635 nat << ref_.getTotalNum();
636 xmlNewProp(cur, (const xmlChar*)"size", (const xmlChar*)nat.str().c_str());
637 const SpeciesSet& mySpecies(ref_.getSpeciesSet());
638 int nitem(mySpecies.numAttributes());
639 int nspecies(mySpecies.getTotalNum());
640 for (int is = 0; is < nspecies; is++)
641 {
642 xmlNodePtr g = xmlNewNode(NULL, (const xmlChar*)"group");
643 xmlNewProp(g, (const xmlChar*)"name", (const xmlChar*)SpeciesName[is].c_str());
644 for (int item = 0; item < nitem; item++)
645 {
646 std::ostringstream prop;
647 prop << mySpecies(item, is);
648 xmlNodePtr p = xmlNewTextChild(g, NULL, (const xmlChar*)"parameter", (const xmlChar*)prop.str().c_str());
649 xmlNewProp(p, (const xmlChar*)"name", (const xmlChar*)mySpecies.attribName[item].c_str());
650 }
651 xmlAddChild(cur, g);
652 }
653 std::ostringstream pos, gid;
654 pos.setf(std::ios_base::scientific);
655 pos << "\n";
656 for (int iat = 0; iat < ref_.getTotalNum(); iat++)
657 {
658 pos << ref_.R[iat] << std::endl;
659 }
660 xmlNodePtr posPtr = xmlNewTextChild(cur, NULL, (const xmlChar*)"attrib", (const xmlChar*)pos.str().c_str());
661 xmlNewProp(posPtr, (const xmlChar*)"name", (const xmlChar*)"position");
662 xmlNewProp(posPtr, (const xmlChar*)"datatype", (const xmlChar*)"posArray");
663 gid << "\n ";
664 for (int iat = 0; iat < ref_.getTotalNum(); iat++)
665 {
666 gid << SpeciesName[ref_.GroupID[iat]] << " ";
667 }
668 gid << std::endl;
669 xmlNodePtr gPtr = xmlNewTextChild(cur, NULL, (const xmlChar*)"attrib", (const xmlChar*)gid.str().c_str());
670 xmlNewProp(gPtr, (const xmlChar*)"name", (const xmlChar*)"ionid");
671 xmlNewProp(gPtr, (const xmlChar*)"datatype", (const xmlChar*)"stringArray");
672 }
673 return cur;
674 }
675 } // namespace qmcplusplus
676