1 """Contains the classes that are used to write to and read from restart files.
3 Copyright (C) 2013, Joshua More and Michele Ceriotti
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http.//www.gnu.org/licenses/>.
19 The classes defined in this module define the base functions which parse the
20 data in the restart files. Each restart object defined has a fields and an
21 attributes dictionary, which are filled with the tags and attributes that
22 are allowed to be present, along with their default values and data type.
24 These are then filled with the data from the xml file when the program
25 is initialised, and are filled by the values calculated in the program which
26 are then output to the checkpoint file when a restart file is required.
28 Also deals with checking for user input errors, of the form of misspelt tags,
29 bad data types, and failure to input required fields.
32 Input: Base input class.
33 InputAttribute: Input class for attribute data.
34 InputValue: Input class for scalar objects.
35 InputArray: Input class for arrays.
36 input_default: Class used to create mutable objects dynamically.
39 __all__
= ['Input', 'InputValue', 'InputAttribute', 'InputArray', 'input_default']
43 from ipi
.utils
.io
.io_xml
import *
44 from ipi
.utils
.units
import unit_to_internal
, unit_to_user
48 class input_default(object):
49 """Contains information required to dynamically create objects
51 Used so that we can define mutable default input values to various tags
52 without the usual trouble with having a class object that is also mutable,
53 namely that all members of that class share the same mutable object, so that
54 changing it for one instance of that class changes it for all others. It
55 does this by not holding the mutable default value, but instead the
56 information to create it, so that each instance of an input class can
57 have a separate instance of the default value.
60 type: Either a class type or function call from which to create the
62 args: A tuple giving positional arguments to be passed to the function.
63 kwargs: A dictionary giving key word arguments to be passed to the
67 def __init__(self
, factory
, args
= None, kwargs
= None):
68 """Initialises input_default.
71 type: The class or function to be used to create the default object.
72 args: A tuple giving the arguments to be used to initialise
74 kwargs: A dictionary giving the key word arguments to be used
75 to initialise the default value.
82 # a default will be generated by factory(*args, **kwargs)
83 # *args unpacks the tuple, and is used for positional arguments
84 # **kwargs unpacks the dictionary, and is used for keyword arguments
85 self
.factory
= factory
91 """Base class for input handling.
93 Has the generic methods for dealing with the xml input file. Parses the input
94 data, outputs the output data, and deals with storing and returning the
95 data obtained during the simulation for the restart files.
98 fields: A dictionary holding the possible tags contained within the
99 tags for this restart object, which are then turned into the objects
100 held by the object given by this restart object. The dictionary is
102 {"tag name": ( Input_object,
103 {"default": default value,
105 "options": list of available options,
107 "dimension": dimensionality of data}), ... }.
108 dynamic: A dictionary holding the possible tags contained within the
109 tags for this restart object, which are then turned into the objects
110 held by the object given by this restart object. These are used for
111 tags that can be specified more than once.
112 The dictionary is of the form:
113 {"tag name": ( Input_object,
114 {"default": default value,
116 "options": list of available options,
118 "dimension": dimensionality of data}), ... }.
119 attribs: A dictionary holding the attribute data for the tag for this
120 restart object. The dictionary is of the form:
121 {"attribute name": ( Input_object,
122 {"default": default value,
124 "options": list of available options,
126 "dimension": dimensionality of data}), ... }.
127 extra: A list of tuples ( "name", Input_object ) that may be used to
128 extend the capabilities of the class, i.e. to hold several instances of
129 a field with the same name, or to hold variable numbers of elements.
130 default_help: The default help string.
131 _help: The help string of the object. Defaults to default_help.
132 _default: Optional default value.
133 _optional: A bool giving whether the field is a required field.
134 _explicit: A bool giving whether the field has been specified by the user.
135 _text: All text written between the tags of the object.
136 _label: A label to be used to identify the class in the latex user manual.
137 _defwrite: The string which would be output if the class has its default
145 default_help
= "Generic input value"
146 default_label
= "" #used as a way to reference a particular class using
149 def __init__(self
, help=None, default
=None):
150 """Initialises Input.
152 Automatically adds all the fields and attribs names to the input object's
153 dictionary, then initialises all the appropriate input objects
154 as the corresponding values.
158 default: A default value.
161 # list of extended (dynamic) fields
165 self
._help
= self
.default_help
169 if isinstance(default
,input_default
):
170 #creates default dynamically if a suitable template is defined.
171 self
._default
= default
.factory(*default
.args
, **default
.kwargs
)
173 self
._default
= default
175 self
._optional
= not (self
._default
is None)
177 self
._label
= self
.default_label
179 #For each tag name in the fields and attribs dictionaries,
180 #creates and object of the type given, expanding the dictionary to give
181 #the arguments of the __init__() function, then adds it to the input
182 #object's dictionary.
183 for f
, v
in self
.fields
.iteritems():
184 self
.__dict
__[f
] = v
[0](**v
[1])
186 for a
, v
in self
.attribs
.iteritems():
187 self
.__dict
__[a
] = v
[0](**v
[1])
193 # stores what we would write out if the default was set
195 if not self
._default
is None:
196 self
._defwrite
= self
.write(name
="%%NAME%%")
198 def set_default(self
):
199 """Sets the default value of the object."""
201 if not self
._default
is None:
202 self
.store(self
._default
)
203 elif not hasattr(self
, 'value'):
204 self
.value
= None #Makes sure we don't get exceptions when we
207 self
._explicit
= False #Since the value was not set by the user
209 def store(self
, value
=None):
210 """Dummy function for storing data."""
212 self
._explicit
= True
216 """Dummy function to retrieve data."""
222 """Base function to check for input errors.
225 ValueError: Raised if the user does not specify a required field.
228 if not (self
._explicit
or self
._optional
):
229 raise ValueError("Uninitialized Input value of type " + type(self
).__name
__)
231 def extend(self
, name
, xml
):
232 """ Dynamically add elements to the 'extra' list.
234 Picks from one of the templates in the self.dynamic dictionary, then
238 name: The tag name of the dynamically stored tag.
239 xml: The xml_node object used to parse the data stored in the tags.
242 newfield
= self
.dynamic
[name
][0](**self
.dynamic
[name
][1])
244 self
.extra
.append((name
,newfield
))
246 def write(self
, name
="", indent
="", text
="\n"):
247 """Writes data in xml file format.
249 Writes the tag, attributes, data and closing tag appropriate to the
250 particular fields and attribs data. Writes in a recursive manner, so
251 that objects contained in the fields dictionary have their write function
252 called, so that their tags are written between the start and end tags
253 of this object, as is required for the xml format.
255 This also adds an indent to the lower levels of the xml heirarchy,
256 so that it is easy to see which tags contain other tags.
259 name: An optional string giving the tag name. Defaults to "".
260 indent: An optional string giving the string to be added to the start
261 of the line, so usually a number of tabs. Defaults to "".
262 text: Additional text to be output between the tags.
265 A string giving all the data contained in the fields and attribs
266 dictionaries, in the appropriate xml format.
269 rstr
= indent
+ "<" + name
;
270 for a
in self
.attribs
:
271 # only write out attributes that are not defaults
272 # have a very simple way to check whether they actually add something:
273 # we compare with the string that would be output if the argument was set
275 defstr
= self
.__dict
__[a
]._defwrite
.replace("%%NAME%%",a
)
276 outstr
= self
.__dict
__[a
].write(name
=a
)
281 for f
in self
.fields
:
282 #only write out fields that are not defaults
284 defstr
= self
.__dict
__[f
]._defwrite
.replace("%%NAME%%",f
)
285 if defstr
!= self
.__dict
__[f
].write(f
): # here we must compute the write string twice not to be confused by indents.
286 rstr
+= self
.__dict
__[f
].write(f
, " " + indent
)
288 for (f
,v
) in self
.extra
:
289 # also write out extended (dynamic) fields if present
290 rstr
+= v
.write(f
, " " + indent
)
292 if text
.find('\n') >= 0:
293 rstr
+= indent
+ "</" + name
+ ">\n"
295 rstr
+= "</" + name
+ ">\n"
298 def parse(self
, xml
=None, text
=""):
299 """Parses an xml file.
301 Uses the xml_node class defined in io_xml to read all the information
302 contained within the root tags, and uses it to give values for the attribs
303 and fields data recursively. It does this by giving all the data between
304 the appropriate field tag to the appropriate field restart object as a
305 string, and the appropriate attribute data to the appropriate attribs
306 restart object as a string. These data are then parsed by these objects
307 until all the information is read, or an input error is found.
310 xml: An xml_node object containing all the data for the parent
312 text: The data held between the start and end tags.
315 NameError: Raised if one of the tags in the xml input file is
317 ValueError: Raised if the user does not specify a required field.
320 # before starting, sets everything to its default -- if a default is set!
321 for a
in self
.attribs
:
322 self
.__dict
__[a
].set_default()
323 for f
in self
.fields
:
324 self
.__dict
__[f
].set_default()
327 self
._explicit
= True
331 for a
, v
in xml
.attribs
.iteritems():
332 if a
in self
.attribs
:
333 self
.__dict
__[a
].parse(text
=v
)
337 raise NameError("Attribute name '" + a
+ "' is not a recognized property of '" + xml
.name
+ "' objects")
339 for (f
, v
) in xml
.fields
: #reads all field and dynamic data.
341 self
.__dict
__[f
].parse(xml
=v
)
344 elif f
in self
.dynamic
:
347 raise NameError("Tag name '" + f
+ "' is not a recognized property of '" + xml
.name
+ "' objects")
349 #checks for missing arguments.
350 for a
in self
.attribs
:
351 va
= self
.__dict
__[a
]
352 if not (va
._explicit
or va
._optional
):
353 raise ValueError("Attribute name '" + a
+ "' is mandatory and was not found in the input for the property " + xml
.name
)
354 for f
in self
.fields
:
355 vf
= self
.__dict
__[f
]
356 if not (vf
._explicit
or vf
._optional
):
357 raise ValueError("Field name '" + f
+ "' is mandatory and was not found in the input for the property " + xml
.name
)
359 def detail_str(self
):
360 """Prints out the supplementary information about a particular input class.
362 Used to print out the dimensions, default value, possible options and data
363 type of an input value to the LaTeX helf file.
367 if hasattr(self
, '_dimension') and self
._dimension
!= "undefined": #gives dimension
368 xstr
+= "dimension: " + self
._dimension
+ "; "
370 if self
._default
!= None and issubclass(self
.__class
__, InputAttribute
):
371 #We only print out the default if it has a well defined value.
372 #For classes such as InputCell, self._default is not the value,
373 #instead it is an object that is stored to give the default value in
374 #self.value. For this reason we print out self.value at this stage,
375 #and not self._default
376 xstr
+= "default: " + self
.pprint(self
.value
) + "; "
378 if issubclass(self
.__class
__, InputAttribute
):
379 #if possible, prints out the type of data that is being used
380 xstr
+= "data type: " + self
.type_print(self
.type) + "; "
382 if hasattr(self
, "_valid"):
383 if self
._valid
is not None:
384 xstr
+= "options: " #prints out valid options, if
385 for option
in self
._valid
: #required.
386 xstr
+= "`" + str(option
) + "', "
387 xstr
= xstr
.rstrip(", ")
391 def help_latex(self
, name
="", level
=0, stop_level
=None, standalone
=True):
392 """Function to generate a LaTeX formatted help file.
395 name: Name of the tag that has to be written out.
396 level: Current level of the hierarchy being considered.
397 stop_level: The depth to which information will be given. If not given,
398 will give all information.
399 standalone: A boolean giving whether the latex file produced will be a
400 stand-alone document, or will be intended as a section of a larger
401 document with cross-references between the different sections.
404 A LaTeX formatted string.
407 #stops when we've printed out the prerequisite number of levels
408 if (not stop_level
is None and level
> stop_level
):
414 #assumes that it is a stand-alone document, so must have
416 rstr
+= r
"\documentclass[12pt,fleqn]{report}"
418 \usepackage{etoolbox}
421 \newcommand{\ipiitem}[3]{%
422 \setul{1pt}{.4pt}\ifblank{#1}{}{\ifstrequal{#1}{\underline{\smash{}}}{}{
423 {\noindent\textbf{#1}:\rule{0.0pt}{1.05\baselineskip}\quad}}}% uses a strut to add a bit of vertical space
426 { {\hfill\raggedleft\textit{\small #3}\par} }
430 \newenvironment{ipifield}[4]{%
431 \ifblank{#1}{}{\vspace{0.5em}}
432 \noindent\parskip=0pt\begin{tabular}[t]{|p{1.0\linewidth}}
434 \multicolumn{1}{@{}p{1.0\linewidth}}{
435 \ipiitem{\underline{\smash{#1}}}{#2}{}
437 \ifblank{#3}{}{{\hfill\raggedleft\textit{\small #3}}\par}}{} } \vspace{-1em}\\ %
440 { \ifblank{#3}{}{\vspace{-1em}{\hfill\raggedleft\textit{\small #3}}\par} %
441 {#4}\vspace{-1em}\\\hline } % negative vspace to undo the line break
443 \parskip=0pt\list{}{\listparindent 1.5em%
444 \leftmargin \listparindent
455 rstr
+= "\n\\begin{document}\n"
456 if self
._label
!= "" and not standalone
:
457 #assumes that it is part of a cross-referenced document, so only
458 #starts a new section.
459 rstr
+= "\\section{" + self
._label
+ "}\n"
460 rstr
+= "\\label{" + self
._label
+ "}\n"
462 rstr
+= "\\begin{ipifield}{}%\n"
464 if self
._label
!= "" and not standalone
:
465 rstr
+= "\\begin{ipifield}{\hyperref["+self
._label
+"]{"+name
+"}}%\n"
467 rstr
+= "\\begin{ipifield}{"+name
+"}%\n"
469 rstr
+= "{"+self
._help
+"}%\n"
471 rstr
+= "{"+self
.detail_str()+"}%\n"
474 # Prints out the attributes
475 if len(self
.attribs
) != 0:
476 #don't print out units if not necessary
477 if len(self
.attribs
) == 1 and (("units" in self
.attribs
) and self
._dimension
== "undefined"):
480 for a
in self
.attribs
:
481 #don't print out units if not necessary
482 if not (a
== "units" and self
._dimension
== "undefined"):
483 rstr
+= "\\ipiitem{" + a
+ "}%\n{" + self
.__dict
__[a
]._help
+ "}%\n{"+self
.__dict
__[a
].detail_str()+"}%\n" #!!MUST ADD OTHER STUFF
486 #As above, for the fields. Only prints out if we have not reached the
487 #user-specified limit.
488 if len(self
.fields
) != 0 and level
!= stop_level
:
489 for f
in self
.fields
:
490 rstr
+= self
.__dict
__[f
].help_latex(name
=f
, level
=level
+1, stop_level
=stop_level
, standalone
=standalone
)
492 if len(self
.dynamic
) != 0 and level
!= stop_level
:
493 for f
, v
in self
.dynamic
.iteritems():
494 dummy_obj
= v
[0](**v
[1])
495 rstr
+= dummy_obj
.help_latex(name
=f
, level
=level
+1, stop_level
=stop_level
, standalone
=standalone
)
497 rstr
+= "\\end{ipifield}\n"
498 if level
== 0 and standalone
:
499 #ends the created document if it is not part of a larger document
500 rstr
+= "\\end{document}"
502 #Some escape characters are necessary for the proper latex formatting
503 rstr
= rstr
.replace('_', '\\_')
504 rstr
= rstr
.replace('\\\\_', '\\_')
505 rstr
= rstr
.replace('...', '\\ldots ')
506 rstr
= rstr
.replace('<', '$<$')
507 rstr
= rstr
.replace('>', '$>$')
511 def pprint(self
, default
, indent
="", latex
= True):
512 """Function to convert arrays and other objects to human-readable strings.
515 default: The object that needs to be converted to a string.
516 indent: The indent at the beginning of a line.
517 latex: A boolean giving whether the string will be latex-format.
523 if type(default
) is np
.ndarray
:
524 if default
.shape
== (0,):
525 return " [ ] " #proper treatment of empty arrays.
527 #indents new lines for multi-D arrays properly
528 rstr
= "\n" + indent
+ " "
529 rstr
+= str(default
).replace("\n", "\n" + indent
+ " ")
531 rstr
+= "\n" + indent
+ " "
534 elif type(default
) == str:
536 return "`" + default
+ "'" #indicates that it is a string
538 return " " + default
+ " "
543 return " \\{ \\} " #again, escape characters needed for latex
547 #in most cases standard formatting will do
548 return " " + str(default
) + " "
550 def type_print(self
, dtype
):
551 """Function to convert a data types to human-readable strings.
559 elif dtype
== float or dtype
== np
.float64
:
561 elif dtype
== int or dtype
== np
.uint64
or dtype
== np
.int64
:
570 raise TypeError("Unrecognized data type " + str(dtype
))
572 def help_xml(self
, name
="", indent
="", level
=0, stop_level
=None):
573 """Function to generate an xml formatted help file.
576 name: A string giving the name of the root node.
577 indent: The indent at the beginning of a line.
578 level: Current level of the hierarchy being considered.
579 stop_level: The depth to which information will be given. If not given,
580 all information will be given
583 An xml formatted string.
586 #stops when we've printed out the prerequisite number of levels
587 if (not stop_level
is None and level
> stop_level
):
590 #these are booleans which tell us whether there are any attributes
591 #and fields to print out
592 show_attribs
= (len(self
.attribs
) != 0)
593 show_fields
= (not (len(self
.fields
) == 0 and len(self
.dynamic
) == 0)) and level
!= stop_level
596 rstr
= indent
+ "<" + name
; #prints tag name
597 for a
in self
.attribs
:
598 if not (a
== "units" and self
._dimension
== "undefined"):
599 #don't print out units if not necessary
600 rstr
+= " " + a
+ "=''" #prints attribute names
604 rstr
+= indent
+ " <help> " + self
._help
+ " </help>\n"
606 for a
in self
.attribs
:
607 if not (a
== "units" and self
._dimension
== "undefined"):
608 #information about tags is found in tags beginning with the name
610 rstr
+= indent
+ " <" + a
+ "_help> " + self
.__dict
__[a
]._help
+ " </" + a
+ "_help>\n"
612 #prints dimensionality of the object
613 if hasattr(self
, '_dimension') and self
._dimension
!= "undefined":
614 rstr
+= indent
+ " <dimension> " + self
._dimension
+ " </dimension>\n"
616 if self
._default
!= None and issubclass(self
.__class
__, InputAttribute
):
617 #We only print out the default if it has a well defined value.
618 #For classes such as InputCell, self._default is not the value,
619 #instead it is an object that is stored, putting the default value in
620 #self.value. For this reason we print out self.value at this stage,
621 #and not self._default
622 rstr
+= indent
+ " <default>" + self
.pprint(self
.value
, indent
=indent
, latex
=False) + "</default>\n"
624 for a
in self
.attribs
:
625 if not (a
== "units" and self
._dimension
== "undefined"):
626 if self
.__dict
__[a
]._default
is not None:
627 rstr
+= indent
+ " <" + a
+ "_default>" + self
.pprint(self
.__dict
__[a
]._default
, indent
=indent
, latex
=False) + "</" + a
+ "_default>\n"
629 #prints out valid options, if required.
630 if hasattr(self
, "_valid"):
631 if self
._valid
is not None:
632 rstr
+= indent
+ " <options> " + str(self
._valid
) + " </options>\n"
634 for a
in self
.attribs
:
635 if not (a
== "units" and self
._dimension
== "undefined"):
636 if hasattr(self
.__dict
__[a
], "_valid"):
637 if self
.__dict
__[a
]._valid
is not None:
638 rstr
+= indent
+ " <" + a
+ "_options> " + str(self
.__dict
__[a
]._valid
) + " </" + a
+ "_options>\n"
640 #if possible, prints out the type of data that is being used
641 if issubclass(self
.__class
__, InputAttribute
):
642 rstr
+= indent
+ " <dtype> " + self
.type_print(self
.type) + " </dtype>\n"
644 for a
in self
.attribs
:
645 if not (a
== "units" and self
._dimension
== "undefined"):
646 rstr
+= indent
+ " <" + a
+ "_dtype> " + self
.type_print(self
.__dict
__[a
].type) + " </" + a
+ "_dtype>\n"
648 #repeats the above instructions for any fields or dynamic tags.
649 #these will only be printed if their level in the hierarchy is not above
650 #the user specified limit.
652 for f
in self
.fields
:
653 rstr
+= self
.__dict
__[f
].help_xml(f
, " " + indent
, level
+1, stop_level
)
654 for f
, v
in self
.dynamic
.iteritems():
655 #we must create the object manually, as dynamic objects are
656 #not automatically added to the input object's dictionary
657 dummy_obj
= v
[0](**v
[1])
658 rstr
+= dummy_obj
.help_xml(f
, " " + indent
, level
+1, stop_level
)
660 rstr
+= indent
+ "</" + name
+ ">\n"
664 class InputAttribute(Input
):
665 """Class for handling attribute data.
667 Has the methods for dealing with attribute data of the form:
668 <tag_name attrib='data'> ..., where data is just a value. Takes the data and
669 converts it to the required data_type, so that it can be used in the
673 type: Data type of the data.
674 value: Value of data. Also specifies data type if type is None.
675 _valid: An optional list of valid options.
678 def __init__(self
, help=None, default
=None, dtype
=None, options
=None):
679 """Initialises InputAttribute.
683 default: A default value.
684 dtype: An optional data type. Defaults to None.
685 options: An optional list of valid options.
688 if not dtype
is None:
691 raise TypeError("You must provide dtype")
693 super(InputAttribute
,self
).__init
__(help, default
)
695 if options
is not None:
696 self
._valid
= options
697 if not default
is None and not self
._default
in self
._valid
:
698 #This makes sure that the programmer has set the default value
699 #so that it is a valid value.
700 raise ValueError("Default value '" + str(self
._default
) + "' not in option list " + str(self
._valid
)+ "\n" + self
._help
)
704 def parse(self
, text
=""):
705 """Reads the data for a single attribute value from an xml file.
708 text: The data held between the start and end tags.
711 super(InputAttribute
, self
).parse(text
=text
)
713 self
.value
= read_type(self
.type, self
._text
)
715 def store(self
, value
):
716 """Stores the input data.
719 value: The raw data to be stored.
721 super(InputAttribute
,self
).store(value
)
725 """Returns the stored data."""
727 super(InputAttribute
,self
).fetch()
731 """Function to check for input errors.
734 ValueError: Raised if the value chosen is not one of the valid options.
737 super(InputAttribute
,self
).check()
738 if not (self
._valid
is None or self
.value
in self
._valid
):
739 #This checks that the user has set the value to a valid value.
740 raise ValueError(str(self
.value
) + " is not a valid option (" + str(self
._valid
) + ")")
742 def write(self
, name
=""):
743 """Writes data in xml file format.
745 Writes the attribute data in the appropriate format.
748 name: An optional string giving the attribute name. Defaults to "".
751 A string giving the stored value in the appropriate format.
754 return name
+ "='" + write_type(self
.type, self
.value
) + "'"
757 class InputValue(InputAttribute
):
758 """Scalar class for input handling.
760 Has the methods for dealing with simple data tags of the form:
761 <tag_name> data </tag_name>, where data is just a value. Takes the data and
762 converts it to the required data_type, so that it can be used in the
766 units: The units that the input data is given in.
767 _dimension: The dimensionality of the data.
770 default_dimension
= "undefined"
773 attribs
= { "units" : ( InputAttribute
, { "dtype" : str, "help" : "The units the input data is given in.", "default" : default_units
} ) }
775 def __init__(self
, help=None, default
=None, dtype
=None, options
=None, dimension
=None):
776 """Initialises InputValue.
780 dimension: The dimensionality of the value.
781 default: A default value.
782 dtype: An optional data type. Defaults to None.
783 options: An optional list of valid options.
786 # a note on units handling:
787 # 1) units are only processed at parse/fetch time:
788 # internally EVERYTHING is in internal units
789 # 2) if one adds an explicit "units" attribute to a derived class,
790 # the internal units handling will be just ignored
791 if dimension
is None:
792 self
._dimension
= self
.default_dimension
794 self
._dimension
= dimension
796 super(InputValue
,self
).__init
__(help, default
, dtype
, options
)
798 def store(self
, value
, units
=""):
799 """Converts the data to the appropriate data type and units and stores it.
802 value: The raw data to be stored.
803 units: Optional string giving the units that the data should be stored
807 super(InputValue
,self
).store(value
)
810 self
.units
.store(units
) #User can define in the code the units to be
814 if self
._dimension
!= "undefined":
815 self
.value
*= unit_to_user(self
._dimension
, units
, 1.0)
818 """Returns the stored data in the user defined units."""
820 super(InputValue
,self
).fetch()
823 if self
._dimension
!= "undefined":
824 rval
*= unit_to_internal(self
._dimension
, self
.units
.fetch(), 1.0)
827 def write(self
, name
="", indent
=""):
828 """Writes data in xml file format.
830 Writes the data in the appropriate format between appropriate tags.
833 name: An optional string giving the tag name. Defaults to "".
834 indent: An optional string giving the string to be added to the start
835 of the line, so usually a number of tabs. Defaults to "".
838 A string giving the stored value in the appropriate xml format.
841 return Input
.write(self
, name
=name
, indent
=indent
, text
=write_type(self
.type, self
.value
))
843 def parse(self
, xml
=None, text
=""):
844 """Reads the data for a single value from an xml file.
847 xml: An xml_node object containing the all the data for the parent
849 text: The data held between the start and end tags.
852 Input
.parse(self
, xml
=xml
, text
=text
)
853 self
.value
= read_type(self
.type, self
._text
)
857 class InputArray(InputValue
):
858 """Array class for input handling.
860 Has the methods for dealing with simple data tags of the form:
861 <tag_name shape="(shape)"> data </tag_name>, where data is an array
862 of the form [data[0], data[1], ... , data[length]].
864 Takes the data and converts it to the required data type,
865 so that it can be used in the simulation. Also holds the shape of the array,
866 so that we can use a simple 1D list of data to specify a multi-dimensional
870 shape: The shape of the array.
873 attribs
= copy(InputValue
.attribs
)
874 attribs
["shape"] = (InputAttribute
, {"dtype": tuple, "help": "The shape of the array.", "default": (0,)})
876 def __init__(self
, help=None, default
=None, dtype
=None, dimension
=None):
877 """Initialises InputArray.
881 dimension: The dimensionality of the value.
882 default: A default value.
883 dtype: An optional data type. Defaults to None.
886 super(InputArray
,self
).__init
__(help, default
, dtype
, dimension
=dimension
)
888 def store(self
, value
, units
=""):
889 """Converts the data to the appropriate data type, shape and units and
893 value: The raw data to be stored.
894 units: Optional string giving the units that the data should be stored
898 super(InputArray
,self
).store(value
=np
.array(value
, dtype
=self
.type).flatten().copy(), units
=units
)
899 self
.shape
.store(value
.shape
)
901 #if the shape is not specified, assume the array is linear.
902 if self
.shape
.fetch() == (0,):
903 self
.shape
.store((len(self
.value
),))
906 """Returns the stored data in the user defined units."""
908 value
= super(InputArray
,self
).fetch()
910 #if the shape is not specified, assume the array is linear.
911 if self
.shape
.fetch() == (0,):
912 value
= np
.resize(self
.value
,0).copy()
914 value
= self
.value
.reshape(self
.shape
.fetch()).copy()
918 def write(self
, name
="", indent
=""):
919 """Writes data in xml file format.
921 Writes the data in the appropriate format between appropriate tags. Note
922 that only ELPERLINE values are printed on each line if there are more
923 than this in the array. If the values are floats, or another data type
924 with a fixed width of data output, then they are aligned in columns.
927 name: An optional string giving the tag name. Defaults to "".
928 indent: An optional string giving the string to be added to the start
929 of the line, so usually a number of tabs. Defaults to "".
932 A string giving the stored value in the appropriate xml format.
936 if (len(self
.value
) > ELPERLINE
):
937 rstr
+= "\n" + indent
+ " [ "
939 rstr
+= " [ " #inlines the array if it is small enough
941 for i
, v
in enumerate(self
.value
):
942 if (len(self
.value
) > ELPERLINE
and i
> 0 and i
%ELPERLINE
== 0):
943 rstr
+= "\n" + indent
+ " "
944 rstr
+= write_type(self
.type, v
) + ", "
946 rstr
= rstr
.rstrip(", ") #get rid of trailing commas
947 if (len(self
.value
) > ELPERLINE
):
952 return Input
.write(self
, name
=name
, indent
=indent
, text
=rstr
)
954 def parse(self
, xml
=None, text
=""):
955 """Reads the data for an array from an xml file.
958 xml: An xml_node object containing the all the data for the parent
960 text: The data held between the start and end tags.
963 Input
.parse(self
, xml
=xml
, text
=text
)
964 self
.value
= read_array(self
.type, self
._text
)
966 #if the shape is not specified, assume the array is linear.
967 if self
.shape
.fetch() == (0,):
968 self
.shape
.store((len(self
.value
),))