IODA
01-GroupsAndObsSpaces.py
Go to the documentation of this file.
1 #
2 # (C) Copyright 2020 UCAR
3 #
4 # This software is licensed under the terms of the Apache Licence Version 2.0
5 # which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
6 #
7 
8 # This first example shows you how to make and manipulate Groups.
9 #
10 # IODA is the Interface for Observation Data Access.
11 #
12 # The objective of the IODA is to provide uniform access to
13 # observation data across the whole forecasting chain from
14 # observation pre-processing to data assimilation to diagnostics.
15 #
16 # IODA isolates the scientific code from the underlying data
17 # structures holding the data. Of course, any user needs to have
18 # a basic understanding of how the data are laid out. How are the
19 # data grouped, how can you access the data, how can you
20 # interpret variable names, and how can you read dimensions
21 # and meta data?
22 #
23 # Data in IODA are stored in a structure Groups, Variables, and
24 # Attributes. A Group is like a folder. It is a logical
25 # collection of Variables and Attributes that describes some
26 # portion of the overall data. A Variable stores bulk data.
27 # An Attribute stores smaller quantities of metadata, and can
28 # be attached to either a Group or a Variable.
29 #
30 # In ioda-engines, we separate out how the data are stored
31 # (the backend engine) from how an end user can access it (in
32 # the frontend). Different backends all provide the same general
33 # interface, but may support slightly different features and will
34 # have different performance characteristics.
35 #
36 # This example shows you how to create Groups. It creates an
37 # HDF5 file, "Example-01-python.hdf5" using the HDF5 backend. Later examples
38 # will use groups to store and read data.
39 #
40 
41 # How to view the output of these examples:
42 #
43 # These examples also double as CTest tests. So, we have a tiny
44 # bit of a setup preamble at the beginning of each example that helps
45 # us to load in the ioda Python library.
46 #
47 # If you want to run the example, try using ctest (i.e.
48 # ctest -V -R Example_ioda_engines_01_python).
49 
50 # Note: After you build and run this example, you can view the contents of this
51 # HDF5 file with either the "h5dump" or "ncdump" commands.
52 # Since we are only using a subset of HDF5's full feature set, netCDF conveniently
53 # recognizes this as a valid netCDF-4 file!
54 #
55 # If you run this example in a Jupyter kernel, you might need
56 # to shutdown the kernel to convince Python to release its resouce
57 # locks and finish writing the output file. Every Group, Attribute,
58 # and Variable returned by ioda is actually a "resource handle". Every
59 # open handle must be closed for the file to finish writing. Or, track
60 # down every ioda Python object and "delete" it
61 # (e.g. "del grpFromFile", "del g1", "del g2", ad nauseam).
62 
63 import os
64 import sys
65 
66 if os.environ.get('LIBDIR') is not None:
67  sys.path.append(os.environ['LIBDIR'])
68 
69 # Importing ioda is easy.
70 
71 import ioda
72 
73 # We want to open a new file, backed by the default engine (HDF5).
74 # We open this file as a root-level Group.
76  name = "Example-01-python.hdf5",
77  mode = ioda.Engines.BackendCreateModes.Truncate_If_Exists)
78 
79 # The only time that you need to be concerned about the
80 # backend (HDF5) is when you create or open a root-level Group.
81 # All Variables and Attributes within a Group transparently
82 # use the same backend.
83 #
84 # Groups can contain other Groups!
85 # To create a new group, use the .create() method.
86 # The new group is a child group of the object that is used to
87 # create it. It shares the same underlying backend as its parent.
88 
89 g1 = grpFromFile.create('g1')
90 g2 = grpFromFile.create("g2")
91 
92 # Groups can form a tree structure.
93 g3 = g1.create("g3")
94 g4 = g3.create("g4")
95 g5 = g4.create("g5")
96 g6 = g4.create("g6")
97 g8 = g6.create("g7/g8")
98 
99 # Your tree looks like this:
100 #
101 # / - g1 - g3 - g4 - g5
102 # | |
103 # g2 g6 - g7 - g8
104 #
105 
106 # Besides creating Groups, we can also check if a particular
107 # group exists, list them and open them.
108 
109 # Checking existance
110 if g1.exists('g3') != True:
111  raise Exception("g3 does not exist in /g1")
112 
113 # Nesting
114 # We can use '/' as a path separator.
115 if g1.exists('g3/g4') != True:
116  raise Exception("g1/g3/g4 does not exist")
117 
118 # Listing the groups contained within a group.
119 # The .list() function returns a list of strings
120 # listing all immediate (one-level) child groups.
121 # This function DOES NOT list variables and attributes. For those,
122 # you would need g3.vars.list() and g3.atts.list(), which are
123 # discussed in subsequent tutorials.
124 g3.list()
125 
126 # These lists are regular Python lists. Nothing special about them.
127 if len(g3.list()) != 1:
128  raise Exception("Wrong size for g3!")
129 
130 if len(g4.list()) != 2:
131  raise Exception("Wrong number of children in g4!")
132 
133 # C++ and Python exceptions can coexist!
134 # C++ exceptions are converted into Python exceptions.
135 
136 # Opening groups
137 # This is also really easy. Use the .open function.
138 # It also obeys nesting criteria, and throws on an error.
139 opened_g3 = g1.open("g3")
140 opened_g6 = opened_g3.open("g4/g6")
141 
142 # Groups g3 and opened_g3 are handles that point to the same object.
143 # Groups g6 and opened_g6 also point to the same object.
144 # Any changes that you make in one of these groups will
145 # be instantly visible to the other.
146 
147 # Note: we make no guarantees about concurrent access using
148 # threads. That is a detail left up to the backend, and is
149 # an area of future work.
150 
151 # What about closing groups?
152 # These Group objects can go out of scope, and they release
153 # their resource locks when they destruct. So, there is no
154 # specific close method.
155 # If you _really_ want to close an object, do this:
156 del opened_g3
157 
158 # If all references to a specific backend instance are closed,
159 # then it is released and does its cleanup tasks.
160 
161 # What about Attributes and Variables?
162 # See tutorial 2 for Attributes.
163 # Variables are covered in tutorials 3-4.
164 
165 # What are ObsGroups?
166 # These extend Groups, and they are covered in tutorial 5.
167 
168 # Thanks for reading!
169 
170 
IODA_DL Group createFile(const std::string &filename, BackendCreateModes mode, HDF5_Version_Range compat=defaultVersionRange())
Create a ioda::Group backed by an HDF5 file.
Definition: HH.cpp:113