@@ -36,6 +36,9 @@ or into the user space issueing ::
3636Quick tutorial
3737==============
3838
39+ The basics
40+ ----------
41+
3942A typical, self-explaining input written in HSD looks like ::
4043
4144 driver {
@@ -117,3 +120,81 @@ Python ::
117120and then stored again in HSD format ::
118121
119122 hsd.dump(hsdinput, "test2.hsd")
123+
124+
125+
126+ Accesing nested data structures via wrappers
127+ --------------------------------------------
128+
129+ The hsd module contains lightweight wrappers (``HsdDict ``, ``HsdList `` and
130+ ``HsdValue ``), which offer convenient access to entries in nested data
131+ structures. With the help of these wrappers, nested nodes and values can be
132+ directly accessed using paths. When accessing nested content via wrappers, the
133+ resulting objects will be wrappers themself, wrapping the appropriate parts of
134+ the data structure (and inheriting certain properties of the original wrapper).
135+
136+ For example, reading and wrapping the example above::
137+
138+ import hsd
139+ hsdinp = hsd.wrap(hsd.load("test.hsd"))
140+
141+ creates an ``HsdDict `` wrapper instance (``hsdinp ``), which can be used to query
142+ encapsulated information in the structure::
143+
144+ # Reading out the value directly (100)
145+ maxsteps = hsdinp["driver", "conjugate_gradients", "max_steps"].value
146+
147+ # Storing wrapper (HsdValue) instance and reading out value and the attribute
148+ temp = hsdinp["hamiltonian / dftb / filling / fermi / temperature"]
149+ temp_value = temp.value
150+ temp_unit = temp.attrib
151+
152+ # Getting a default value, if a given path does not exists:
153+ pot = hsdinp.get_item("hamiltonian / dftb / bias", default=hsd.HsdValue(100, attrib="V"))
154+
155+ # Setting a value for given path by creating missing parents
156+ hsdinp.set_item("analysis / calculate_forces", True, parents=True)
157+
158+ As demonstrated above, paths can be specified as tuples or as slash (``/ ``) joined strings.
159+
160+ The wrappers also support case-insensitive access. Let's have a look at a
161+ mixed-case example file ``test2.hsd ``::
162+
163+ Driver {
164+ ConjugateGradients {
165+ MovedAtoms = 1 2 "7:19"
166+ MaxSteps = 100
167+ }
168+
169+ We now make copy of the data structure before wrapping it, and make sure that
170+ all keys are converted to lower case, but the original names are saved as
171+ HSD-attributes::
172+
173+ hsdinp = hsd.copy(hsd.load("test2.hsd"), lower_names=True, save_names=True)
174+
175+ This way, paths passed to the Hsd-wrapper are treated in a case-insensitive
176+ way::
177+
178+ maxsteps = hsdinp["driver", "CONJUGATEGRADIENTS", "MAXSTEPS"].value
179+
180+ When adding new items, the access is and remains case in-sensitive, but the
181+ actual form of the name of the new node will be saved. The code snippet::
182+
183+ hsdinp["driver", "conjugategradients", "MaxForce"] = hsd.HsdValue(1e-4, attrib="au")
184+ maxforceval = hsdinp["driver", "conjugategradients", "maxforce"]
185+ print(f"{maxforceval.value} {maxforceval.attrib}")
186+ print(hsd.dump_string(hsdinp.value, use_hsd_attribs=True))
187+
188+ will result in ::
189+
190+ 0.0001 au
191+ Driver {
192+ ConjugateGradients {
193+ MovedAtoms = 1 2 "7:19"
194+ MaxSteps = 100
195+ MaxForce [au] = 0.0001
196+ }
197+ }
198+
199+ where the case-convention for ``MaxForce `` is identical to the one used when the
200+ item was created.
0 commit comments