3.2 I/O layer

The I/O layer presents an abstraction scheme used to read persistent Wafers into the core data structures. These data are then available to all tools integrated with the WAFER-STATE-SERVER. The concept of this layer allows for an arbitrary number of file formats to be supported. Thereby the problem of reading and writing data from or to different files is solved.

The I/O module is split into two parts, the Reader and the Writer. Each part consists of several C++ interface classes that are used to traverse the data. The implementation of these classes takes care to handle data transfer to or from the underlying file or database3.1. For each file format to be supported all these interface classes must be implemented. The classes for Reader and Writer are completely independent from each other. Thus, only the set corresponding to the required operation (reading or writing) for a certain file format must be implemented.

The I/O layer is also used in a tool supplied with the WAFER-STATE-SERVER to convert between all supported file formats (ioconv). This program simply connects a Reader and a Writer object. The type of the input and output file format is thereby selectable at runtime. We succeeded to keep the Reader and Writer APIs rather compact which is best illustrated by the fact that this conversion tool was realized with less than $ 250$ lines of C++ code. (c. f. Appendix A).

Apart from a pure file conversion the I/O layer serves an additional purpose. As pointed out earlier some file formats semantically differ from the data standard as it is defined in the WAFER-STATE-SERVER data model. The implementation of the I/O module for such file formats must also take care of these differences. If, for example, a certain file format is capable of storing several element types (as with the DF-ISE file format), then the Reader implementation must take care of delivering only tetrahedrons to the WAFER-STATE-SERVER. If a file format supports only boundary conforming meshes (DF-ISE) then the Writer implementation must take care to make boundary conforming grids before data are actually stored on the file.

Data are organized in several sections. Care was taken to avoid the storage of redundant information. Therefore, a global point list was used to store the point coordinates of all grids of the Wafer. A grid is realized as a set of grid elements, each with either 2 (one-dimensional grid), 3 (two-dimensional triangular grid), or 4 (three-dimensional tetrahedral grid) references into the point list. A grid has an associated name which is used to reference the grid from a quantity. A quantity is realized as a list of abstract values3.2 and a grid reference. Fig. 3.2 depicts how the values of a quantity are associated with the coordinates of the according point.

Figure 3.2: Relation between quantity values, grid elements and point coordinates. The sequence of the data in the value list corresponds to the ordering of the point references in the grid element list.
\begin{figure}\centering\psfig{file=pics/quantity, width=0.7\linewidth}\end{figure}

Properties are realized as attributes with only one (abstract) value that do not reference a grid. Properties are defined on the whole segment, and are used to store attributes that are constant over the whole segment (e.g. the material type of a segment).

There exist also grids that are not referenced from any quantity. These so-called stand-alone grids are optional, and are only necessary to define the geometry of a segment in case no attributes are present. Thus, a stand-alone grid is used to define the geometry of a Wafer without any impurity descriptions or other quantities.

Boundaries contain attributes, used to store quantities on an interface between two segments. Boundaries are defined in the Boundaries section of the segment. From the data structure point of view they are similar to segments except for the dimension of the grid elements which is one less than the elements in the segments section.

Fig. 3.3 depicts the algorithm to read data from a persistent

Figure 3.3: I/O reading algorithm.
\begin{figure}\centering\psfig{file=pics/io-rd, width=0.8\linewidth}\end{figure}

Wafer. The data are read hierarchically.

All methods named next... are iterators (c. f. Appendix A.4) over the contents of a section. They return an instance of an object or indicate the end of a section. The sequence of the method calls is mandatory and must occur as described below.

  1. An object of type Reader must be instantiated. This can either be done by directly invoking the constructor of a certain Reader implementation or via the dynamic instantiation method (c. f. Appendix A.1). The dynamic instantiation method is preferred since it hides all details of the Reader implementation from the application code3.3.

  2. As a first step all points must be retrieved. This is achieved by a call to the nextPoint method of the Reader class. The method returns either a point or indicates "end-of-section" after the last point was read.

  3. Now the segments must be retrieved. This is done via an interface of type RdSegment. The nextSegment method returns an object of this type or indicates "end-of-section" after the last segment was retrieved. For each segment the following sequence is used to get the data.

    1. The method nextGrid of the RdSegment class returns an object of type RdGrid for each stand-alone grid that is stored on a file. The grid elements are fetched from the RdGrid interface with calls to the nextWafGridEl method.

    2. After the last stand-alone grid was fetched the attributes must be fetched. This is done by calling the nextAttribute method of the RdSegment interface once for each attribute. The method returns an object of type RdAttribute. The end of the attributes is again indicated as described above. The RdAttribute interface contains the following three methods.

      • isConstAttr is used to determine whether the attribute is a quantity (false) or a property (true).

      • nextWafGridEl does exactly the same as in the RdGrid interface. Note that this method must only be invoked for quantities, but not for properties. Grids can be shared by several attributes. For performance reasons it was chosen that the grid is read only the very first time an attribute references it. If a grid is tried to be read the second time an error condition is indicated. The predicate isNewGrid of the RdAttribute class returns true for the first occurrence of a grid and false otherwise.

      • nextVal returns an instance of an abstract value.

    3. After the attributes the boundaries must be fetched in a way similar to attributes. From a data structure point of view a boundary is identical to an attribute3.4.

Fig. 3.4 depicts the algorithm to write data to a file.

Figure 3.4: I/O writing algorithm.
\begin{figure}\centering\psfig{file=pics/io-wr, width=0.8\linewidth}\end{figure}

The Writer interface works similar to the Reader. Again the order of the method calls is mandatory and must not be altered. Additionally to the classes that directly correspond to the respective classes in the Reader interface there are extra classes used to help in syntactically closing a section of the file. The destructor of these classes is reserved to perform that task.

  1. An object of type Writer must be instantiated. This can either be done by directly invoking the constructor of a certain Writer implementation or via the dynamic instantiation method (c. f. Appendix A.2). The dynamic instantiation method is preferred for the same reasons as with the instantiation of the Reader.

  2. The method openPoints of the Writer interface must be called to initiate the transfer of points. The method returns an object of type WrPoints. The nextPoint method of WrPoints must be called once for each point. The points are orderer in the way they are written to the file, starting with index 0 for the first point. After the last point the points section must be closed by explicitly assigning a 0 handle3.5 to the WrPoints section.

  3. After the points are written and the points section is properly closed the segments need to be transferred. This is initiated by a call to the openSegments method of the Writer class. This method returns an object of type WrSegSection which in turn contains a method to open a segment section (nextSegment. The WrSegment interface contains three methods to write stand-alone grids (nextGrid) to open the attributes section (openAttributes) and to open the boundaries section (openBoundaries). A segment must be created in the following manner.

    1. All stand-alone grids must be written first. To start writing a stand-alone grid the method
      nextGrid must be invoked. It returns an object of type WrGrid. The method nextEl of the WrGrid interface must be called for each grid element that is to be stored on a file. Note that the the elements are again ordered the way they are written, starting with index 0. After the last element was transferred the WrGrid section must be closed by an explicit assignment to a 0 handle.

    2. The method openAttributes must be used to open the attributes section of that segment. It returns an object of type WrAttributes which contains methods to dump an attribute. The write cycle of an attribute depends on whether a quantity or a property is to be written. For quantities a grid that holds the quantity's values is to be dumped first. This is done in the very same way as for stand-alone grids described above (nextGrid. The actual values of the attribute are then written via an object of type WrAttribute that is returned from the nextAttribute method of the WrAttributes interface. The nextVal method is invoked once for each value that is to be stored. For properties this method must only be invoked once. After completion of a WrAttribute it must be closed. After the last attribute was written the WrAttributes section must be closed.

    3. The method openBoundaries opens the boundaries section and returns an object of type WrBoundaries. Note that a call of this method is optional since boundaries are only contained optionally. The WrBoundaries object contains the method nextGrid that must be used exactly the same was as for stand-alone grids and for attributes. Since from a data structurepoint of view boundaries are identical to attributes, the method nextBoundary returns an object of type WrAttribute. The method nextVal of that object is again used to store an abstract value on the file.

  4. A finished segment must be closed by assigning a 0 to the WrSegment object. After the last segment was written also the WrSegSection must be closed.

  5. As a final step the Writer object itself must be closed.

The Reader interface contains methods that are used to query the name of segments, attributes and grids, and to query the name of the grid reference of an attribute. Fig. 3.5 and Fig. 3.6 depict a class diagram of the Reader and Writer processes respectively, in the UML (UNIFIED MODELING LANGUAGE) notation. The figures show all classes involved in the reading and writing process. An implementation of a Reader or Writer must inherit all depicted classes and implement the specified (virtual) methods.

Figure 3.5: UML reading class diagram.
\begin{figure}\centering\psfig{file=pics/reader-uml, width=0.5\linewidth}\par\end{figure}

Figure 3.6: UML writing class diagram.
\begin{figure}\centering\psfig{file=pics/writer-uml, width=0.45\linewidth}\par\end{figure}