Paired Data
Paired data is general curve data consisting of two or more arrays to define a curve or family of curves. The first array is the independent variable, or ordinate array. The second and additional arrays are the dependent variable(s) with a one-to-one correspondence to the ordinate array. For example, if you were to have a stage-damage function, the first array would contain the stage values and the second array may contain total damages; the third array residential damages, the fourth commercial and so-forth. Optional labels provide a way identifying each of the dependent variables, for example "Total", "Residential", "Commercial" in this example.
The "C" part of the pathname identifies the independent and dependent variable names. The names are separate by a dash; for example, "Stage-Flow", or "Flow-Frequency".
The "type" for each array in a paired data set determines how it should be plotted. A type of "Linear" indicates that the axis should be linear. "LOG" indicates a logarithmic axis, "FREQ" a frequency axis, and "PROB" a probability axis. For some types, the units may also help determine the axis type.
In version 7, there is no limit to the number of ordinates or number of curves. However, memory has to be allocated for all data in a paired data set, so there is the potential for exceeding available memory. Also, there is no limit to the length of each label. Labels are passed in as a single character array with each label null terminated.
In general, separating a large family of curves into separate paired data records is preferred over storing them in a single record. Best practices limit the number of data values stored in a single record to around 5,000 to 10,000 values. It is more efficient to repeat the ordinate set, rather than have many curves in a single record.
By default, the independent variable (ordinates) is plotted on the Y (vertical) axis and the dependent variable on the X (horizontal) axis. You can switch the plotting axis by setting the flag switchXyAxis to "true" or by changing the setting in the plot options dialog.
For paired data conventions, the first row is row 1 and the first column is column 1 (not row 0 or column 0.) Generally the terms "ordinates and curves" are used instead of "rows and columns".
Paired Data Structs
Paired data is stored and retrieved from HEC-DSS using "zStructPairedData". The primary components of zStructPairedData are:
- The pathname
- The number of ordinates (rows) and the number of curves (columns)
- The ordinates array, either as floats or doubles
- The coordinates array, either as floats or doubles
- The labels array (optional), one label per curve.
The ordinates array is a singly dimensioned array (either floats or doubles). The coordinates array in practice is a doubly dimensioned array, but is actually a singly dimensioned array in the struct because of how C handles arrays. The following formula is typically used to compute the position in the coordinates array:
position = (curve number * number of Ordinates) + ordinate number;
Paired Data Pathnames
A paired data pathname has the following 6 parts, separated by slashes ("/"):
A. Group or Basin
B. Location
C. Parameters, "Independent", then "dependent" variable names separated by a dash ("Stage-Flow")
D. Optional descriptor (often unused)
E. Optional date descriptor (e.g., date of measurement)
F. General descriptor or version (e.g., "Plan A")
Storage and Retrieval of Paired Data
Similar to the time series functions, paired data is stored using a zStructPairedData and the function zpdStore. Paired data is retrieved using function zpdRetrieve.
zpdStore
Paired data is stored in DSS using the function "zpdStore":
int zpdStore(long long *ifltab, zStructPairedData *pds, int storageFlag)
Returns:
STATUS_OKAY (zero) for a successful operation
< 0 (a large negative number) if an error occurred. See the section on error processing for more information.
storageFlag:
0 Normal write, store data as either floats or doubles, depending on which arrays are used in struct
1 Store as floats, regardless of the arrays in the struct.
2 Store as doubles, regardless of the arrays in the struct.
10 Pre-allocate space for storing a large family of curves. Array type determines float or double
11 Pre-allocate space for storing a large family of float curves.
12 Pre-allocate space for storing a large family of double curves.
zpdRetrieve
Paired data is retrieved from DSS using the function "zpdRetrieve":
int zpdRetrieve(long long *ifltab, zStructPairedData *pds, int retrieveSizeFlag)
Returns:
STATUS_OKAY (zero) for a successful operation
< 0 (a large negative number) if an error occurred. See the section on error processing for more information.
retrieveSizeFlag:
0 Normal, retrieved data as stored.
1 Retrieved data as floats, regardless of how stored.
2 Retrieved data as doubles, regardless of how stored.
Example: Paired Data Rating table
This example stores and retrieves a simple rating table.
#include <stdio.h>
#include "heclib.h"
// A simple sample of code to demonstrate storing and retrieving
// paired data for a rating table
int ExamplePairedData1()
{
long long ifltab[250];
zStructPairedData *pds1, *pds2;
// double xOrdinates[int numberOrdinates]
double xOrdinates[200];
// double yOrdinates[int numberCurves][int numberOrdinates]
double yOrdinates[1][200];
int status, i, j, pos;
// Open the DSS file; Create if it doesn't exist
status = zopen(ifltab, "C:/temp/Example7.dss");
// If an error occured, messages will be printed to standard out
if (status != STATUS_OKAY) return status;
// Gen up the data
for (i = 0; i<200; i++) {
xOrdinates[i] = (double)(i + 1);
yOrdinates[0][i] = (double)(i + 1) * 100.0;
}
pds1 = zstructPdNewDoubles("/Basin/Location/Stage-Flow/Rating Table//C Sample/”,
xOrdinates, (double *)yOrdinates, 200, 1, "Feet", "Linear", "CFS", "Linear");
status = zpdStore(ifltab, pds1, 0);
zstructFree(pds1);
if (status != STATUS_OKAY) return status;
// Read the data back in
pds2 = zstructPdNew("/Basin/Location/Stage-Flow/Rating Table//C Sample/”);
status = zpdRetrieve(ifltab, pds2, 0);
if (status != STATUS_OKAY) return status;
// Print out (values returned as doubles)
for (i=0; i<pds2->numberOrdinatesInStruct; i++) {
printf("Ordinate %d, %f, Curve value(s) ", i, pds2→doubleOrdinates[i]);
for (j = 0; j < pds2->numberCurvesInStruct; j++) {
// Array in struct is single dimensioned, so we compute position for double dim.
// pos = (curve number * numberOrdinates) + ordinate;
pos = (j * pds2->numberOrdinatesInStruct) + i;
printf(" %f", pds2→doubleValues[pos]);
}
printf("\n");
}
zstructFree(pds2);
zclose(ifltab);
return 0;
}
Ordinate 0, 1.000000, Curve value(s) 100.000000
Ordinate 1, 2.000000, Curve value(s) 200.000000
Ordinate 2, 3.000000, Curve value(s) 300.000000
Ordinate 3, 4.000000, Curve value(s) 400.000000
Example: Paired Data Frequency Curve
This example stores and retrieves a flow-frequency curve. Since the flow-frequency data set contains several curves, each curve is given a label to identify it.
#include <stdio.h>
#include <string.h>
#include "heclib.h"
// A simple sample of code to demonstrate storing and retrieving
// storing and retrieving a flow-frequency curve set
int ExamplePairedData2()
{
long long ifltab[250];
zStructPairedData *pds1, *pds2;
// double xOrdinates[int numberOrdinates]
double xOrdinates[20];
// double yOrdinates[int numberCurves][int numberOrdinates]
double yOrdinates[4][20];
char labels[100];
int labelLength;
int status, i, j, pos;
// Open the DSS file; Create if it doesn't exist
status = zopen(ifltab, "C:/temp/Example7.dss");
// If an error occured, messages will be printed to standard out
if (status != STATUS_OKAY) return status;
// Gen up the data
for (i = 0; i < 20; i++) {
xOrdinates[i] = (double)(i + 1) / 21.0;
for (j = 0; j < 4; j++) {
yOrdinates[j][i] = (double)(j + 1) * 10.0 + (double)(i * 5);
}
}
// Create lables (one char array.) Each lable has to be null terminated.
labelLength = 0;
stringCopy(&labels[labelLength], sizeof(labels) - labelLength, "Plan A\0", 7);
labelLength += 7;
stringCopy(&labels[labelLength], sizeof(labels) - labelLength, "Plan B\0", 7);
labelLength += 7;
stringCopy(&labels[labelLength], sizeof(labels) - labelLength, "Plan C\0", 7);
labelLength += 7;
stringCopy(&labels[labelLength], sizeof(labels) - labelLength, "No Changes\0", 11);
labelLength += 11;
pds1 = zstructPdNewDoubles("/Basin/Location/Freqency-Flow//C Sample//",
xOrdinates, (double *)yOrdinates, 20, 4, "Percent", "Freqency", "CFS", "Linear");
pds1->labels = labels;
pds1->labelsLength = labelLength;
status = zpdStore(ifltab, pds1, 0);
zstructFree(pds1);
if (status != STATUS_OKAY) return status;
// Read the data back in
pds2 = zstructPdNew("/Basin/Location/Freqency-Flow///C Sample/”);
status = zpdRetrieve(ifltab, pds2, 0);
if (status != STATUS_OKAY) return status;
// Print out labels
if (pds2->labelsLength > 0) {
printf("\n\n ");
labelLength = 0;
for (j = 0; j < pds2->numberCurvesInStruct; j++) {
printf(" %s ", &pds2→labels[labelLength]);
labelLength += (int)strlen(&pds2->labels[labelLength]) + 1;
if (labelLength > pds2->labelsLength) break;
}
printf("\n\n");
}
// Array in struct is single dimension
for (i=0; i<pds2->numberOrdinatesInStruct; i++) {
printf("Ordinate %d, %f, Curve value(s) ", i, pds2→doubleOrdinates[i]);
for (j = 0; j < pds2->numberCurvesInStruct; j++) {
// Array in struct is single dimensioned, so we compute position for double dim.
// pos = (column * numberOrdinates) + row; or,
// pos = (curve number * numberOrdinates) + ordinate;
pos = (j * pds2->numberOrdinatesInStruct) + i;
printf(" %f", pds2→doubleValues[pos]);
}
printf("\n");
}
zstructFree(pds2);
zclose(ifltab);
return 0;
}
Plan A Plan B Plan C No Changes
Ordinate 0, 0.047619, Curve value(s) 10.000000 20.000000 30.000000 40.000000
Ordinate 1, 0.095238, Curve value(s) 15.000000 25.000000 35.000000 45.000000
Ordinate 2, 0.142857, Curve value(s) 20.000000 30.000000 40.000000 50.000000
Ordinate 3, 0.190476, Curve value(s) 25.000000 35.000000 45.000000 55.000000
Ordinate 4, 0.238095, Curve value(s) 30.000000 40.000000 50.000000 60.000000
zStructPairedData
zStructPairedData struct objects are created by the following functions. The first is generally for retrieving data, while the next two are for storing float or double arrays.
When you are done with a struct, you must always free its memory with function zstructFree.
Note: These functions do not copy arrays. You cannot change those arrays between struct creation and storing or retrieving.
zStructPairedData* zstructPdNew(const char* pathname)
zStructPairedData* zstructPdNewFloats(const char* pathname, float *floatOrdinates, float *floatValues, int numberOrdinates, int numberCurves, const char *unitsIndependent, const char *typeIndependent, const char *unitsDependent, const char *typeDependent)
zStructPairedData* zstructPdNewDoubles(const char* pathname, double *doubleOrdinates, double *doubleValues, int numberOrdinates, int numberCurves, const char *unitsIndependent, const char *typeIndependent, const char *unitsDependent, const char *typeDependent)
void zstructFree(void *zstruct);
zStructPairedData Definition
typedef struct {
// Private
int structType;
/* Required */
char *pathname;
int numberCurves; // (Total number of columns)
int numberOrdinates; // (Total number of rows)
// For storing or retrieving a portion of a data set
// (Data set must exist!)
// The corresponding ordinate set is always read (but never written)
// Set to zero to ignore (store / read all)
int startingCurve;
int endingCurve;
int startingOrdinate;
int endingOrdinate;
int numberCurvesInStruct; // Only on return
int numberOrdinatesInStruct; // Only on return
// values is a double character pointer array, e.g., char *table[50][10]; (50 rows by 10 columns).
// C doesn't do multi-dimensioned arrays very well, so we get a char *table[500] style array,
// and figure out the row-column positions from that.
// Since, these are just pointers, we'll keep the actual strings in textArray.
// When storing data, you can have the actual strings wherever and we'll copy into an array
// When retrieving, carray will contain the data.
// Don't forget to call zstructFree when done to release the data
// (Otherwise, you'll have a huge memory leak)
// Data
float *floatOrdinates;
float *floatValues; // Either float or double, not both
double *doubleOrdinates; // The array not used must be null
double *doubleValues;
int sizeEachValueRead; // 1 = float, 2 = double
int xprecision; // -1 = not set, otherwise decimal places for each value
int yprecision; // 1.234 has a precision of 3 (digits past decimal)
char *unitsIndependent;
char *typeIndependent;
char *unitsDependent;
char *typeDependent;
int boolIndependentIsXaxis;
/* ____________ Optional __________________________ */
// labels is a string of characters that contain a label for each curve.
// Each label must be null terminated. The total length of labels is labelsLength
// e.g., labels = "Residential Commercial Ag", where ' ' is really '\0'
char *labels;
int labelsLength;
char *timeZoneName; // Time zone of the data (may or may not match location time zone)
/* User header, used for further description of data/gage */
/* Not often used */
int *userHeader;
int userHeaderNumber;
int *otherInfo;
int otherInfoNumber;
zStructLocation *locationStruct;
// Informational only (on return only)
int dataType;
long long lastWrittenTime; // Seconds since 1970
long long fileLastWrittenTime;
char programName[17];
// Private - knowing which variables were allocated by the ztsNew functions,
// instead of the calling program
char allocated[zSTRUCT_length];
} zStructPairedData;
zStructPairedData Use for Storing
char *pathname: Required - Usually input by a zstructPdNew function. The “C” part must contain the independent and dependent variable names separated by a dash (e.g., “Stage-Flow” or “Frquency-Flow”.)
int numberCurves: Required - Usually input by a zstructPdNew function. The number of curves or columns in the data set.
int numberOrdinates: Required - Usually input by a zstructPdNew function. The number of ordinates or rows in the data set.
float *floatOrdinates or double *doubleOrdinates: Required - Usually input by a zstructPdNew function. An array containing the ordinates (data for the independent or first variable in the C part). The array should be dimensioned to [numberOrdinates]. You can either have a float array or double array, not both. The unused array must be null.
float *floatValues or double *doubleValues: Required - Usually input by a zstructPdNew function. An array containing the values (data for the dependent or second variable in the C part). The array should be dimensioned to [numberCurves][numberOrdinates]. You can either have a float array or double array, not both. The unused array must be null.
char *unitsIndependent: A null terminated string containing the units of the independent variable. For example, if the C part was “Stage-Flow”, this might be “feet”.
char *typeIndependent: A null terminated string containing the type for the independent variable. For example, if the C part was “Stage-Flow”, this might be “LIN” (linear) and if the C part was “Flow-Frequency”, this could be “LIN” or “LOG”.
char *unitsDependent: A null terminated string containing the units of the dependent variable. For example, if the C part was “Stage-Flow”, this might be “cfs”.
char *typeDependent: A null terminated string containing the type for the independent variable. For example, if the C part was “Stage-Flow”, this might be “LIN” (linear) and if the C part was “Flow-Frequency”, this could be “PROB” a probability axis.
char *labels: (Optional) A char string conaining numberCurves labels, one for each curve and label null terminated. For example, a “Stage-Damage” data set this might be "Residential\0Commercial\0Ag\0", where “\0” is a null char. Care should be taken when handling strings that contain multiple null characters. See the code examples.
int labelsLength: The number of characters (including nulls) in labels.
int xprecision: Optional. The display precision of the independent data. This is how many decimals to the right of the decimal point to show in tables, e.g. “1.234” would have a precision of 3. A value of -1 indicates not set. Note, this is only the display, the full value of the number is stored in DSS.
int yprecision: Optional. The display precision of the dependent data.
int boolIndependentIsXaxis: Optional. Set to 1 if the independent variable is to plot on the X axis; otherwise 0 indincates it is to plot on the Y axis. This parameter is used for plotting only.
Parameters for storing partial datasets
int startingCurve: If a partial dataset is to be stored, this is the starting curve number for the data in the struct, where the first curve is number one, not zero. If all curves are to be set, then this should be zero.
int endingCurve: If a partial dataset is to be stored, this is the ending curve number for the data in the struct, where the first curve starts at one, not zero. If all curves are to be set, then this should be zero.
int startingOrdinate: If a partial dataset is to be stored, this is the starting ordinate (row) number for the data in the struct, where the first ordinate is number one, not zero. If all ordinates are to be set, then this should be zero.
int endingOrdinate: If a partial dataset is to be stored, this is the ending ordinate number for the data in the struct, where the first ordinate starts at one, not zero. If all ordinates are to be set, then this should be zero.
User Header
int *userHeader: Optional. An array to store any additional information needed about the data set. The user header does not generally have a one-to-one correspondence with data, but is an area to store pertinent information, often in a keyword:item format, such as "Shift:12.4".
int userHeaderNumber: Optional. The number of ints in the userHeader array to store (regardless of the data type in that array.)
zStructPairedData Use for Retrieving
Input Parameters:
char *pathname: Required - Usually input by a zstructPdNew function. The "C" part must contain the independent and dependent variable names separated by a dash (e.g., "Stage-Flow" or "Frquency-Flow".)
Return Parameters:
int numberCurves: The number of curves or columns in the complete data set. Note, if you read a partial data set, this will be the total number of curves, not what was read.
int numberOrdinates: The number of ordinates or rows in the complete data set.
int numberCurvesInStruct: The number of curves or columns returned in this struct.
int numberOrdinatesInStruct: The number of ordinates or rows returned in this struct.
int startingCurve: The starting curve number for the data in the returned struct, where the first curve is number one (not zero.)
int endingCurve: The ending curve number for the data in the returned struct, where the first curve starts at one (not zero.)
int startingOrdinate: The starting ordinate (row) number for the data in the returned struct, where the first ordinate starts at one (not zero.)
int endingOrdinate: The ending ordinate number for the data in the returned struct, where the first ordinate starts starts at one (not zero.)
float *floatOrdinates or double *doubleOrdinates: An array containing the ordinates (data for the independent or first variable in the C part). The array is dimensioned to [numberOrdinates]. The unused array will be null.
float *floatValues or double *doubleValues: An array containing the values (data for the dependent or second variable in the C part). The array will be dimensioned to [numberCurves][numberOrdinates]. The unused array will be null. Note: the struct contains a single pointer to the array, which implies a singly dimensioned array. Because of the handeling of arrays in C, it is difficult to correctly return other than a single pointer. The following formula is typically used to compute the position in the array:
position = (curve number * number of Ordinates) + ordinate number;
char *unitsIndependent: A null terminated string containing the units of the independent variable. For example, if the C part was “Stage-Flow”, this might be “feet”.
char *typeIndependent: A null terminated string containing the type for the independent variable. For example, if the C part was “Stage-Flow”, this might be “LIN” (linear) and if the C part was “Flow-Frequency”, this could be “LIN” or “LOG”.
char *unitsDependent: A null terminated string containing the units of the dependent variable. For example, if the C part was “Stage-Flow”, this might be “cfs”.
char *typeDependent: A null terminated string containing the type for the independent variable. For example, if the C part was “Stage-Flow”, this might be “LIN” (linear) and if the C part was “Flow-Frequency”, this could be “PROB” a probability axis.
char *labels: A char string conaining numberCurves labels, one for each curve and label null terminated. For example, a “Stage-Damage” data set this might be "Residential\0Commercial\0Ag\0", where “\0” is a null char. Care should be taken when handling strings that contain multiple null characters. See the code examples.
int labelsLength: The number of characters (including nulls) in labels.
int xprecision: The display precision of the independent data. This is how many decimals to the right of the decimal point to show in tables, e.g. “1.234” would have a precision of 3. A value of -1 indicates not set. Note, this is only the display, the full value of the number is stored in DSS.
int yprecision: The display precision of the dependent data.
int boolIndependentIsXaxis: This is set to 1 if the independent variable is to plot on the X axis; otherwise 0 indincates it is to plot on the Y axis.
Paired Data Functions for Large Datasets
There is no limit for the number of data that can be stored in a single record for HEC-DSS version 7, however, memory management and the ability to use the record without issues, such as in a Java table, suggests reasonable limits be used. For example, if you were computing a dataset that could be represented in a table with 1,000 columns and 10,000 rows, it would be far better to store as 1,000 separate paired data records (with 10,000 rows each), rather than a single paired data record of 1,000 by 10,000. Paired Data records of 1,000 by 10,000 have been tested with DSS-7, but that size will probably exceed the available memory in most applications.) Regardless, sometimes large paired datasets are needed and HEC-DSS version 7 has functions to accomidate this.
In HEC-DSS version 7, you can read or write a block of a paired dataset, without having to read or write the entire record. For example, you may want to read or write a block that is for columns 35 to 42 and rows 541 to 550. DSS will read or write only those values and return (or store) that subset, which will be 8 rows by 10 columns for this example. The location on disk of those values will be computed and only those values will be read (or written). This saves resources considerably without having to do a large allocation of memory or read a large segment from disk.
Pre-allocating paired data space
If you have a program that computes where paired data values are computed in separate iterations (i.e., the whole dataset is not computed at one time), then space for that record is "allocated" prior writing data to it. To allocate space, a zStructPairedData is filled out with everything except for the coordinate arrays (the columns in the table). The number of rows and columns, labels, units, etc., for each column, and the complete ordinate array (first column of the table) need to be given for the allocation.
To allocate space for a paired dataset, set the zpdStore "storageFlag" and then write the struct to disk. The storageFlag settings for allocating space are:
storageFlag:
10 Pre-allocate space for storing a large family of curves. Array type determines float or double
11 Pre-allocate space for storing a large family of float curves.
12 Pre-allocate space for storing a large family of double curves.
All of the parameters used for normal storage, except for the "values" array are used in pre-allocating space on disk. This includes a fully defined "ordinates" array and labels, if they are used. You may change ordinates later on, if desired, but the ordinates array is written during pre-allocation.
The numberCurves and numberOrdinates parameters define how much space to allocate. Those parameters cannot be changed in later writes (You would have to create a new record to change those, although you may also choose not to write out all the curves.)
Storing and Retrieving Portions of a Paired Dataset
To write or read only a segment of the record, specify the startingCurve, endingCurve, startingOrdinate, and endingOrdinate in the zStructPairedData. You do not need to include any other data, except the pathname. Note: the first curve and first ordinate are 1, not 0. A zero in these variables indicates to ignore them. If you want to write an entire single curve, set the startingOrdinate and endingOrdinate to zero. Setting all 4 variables to zero, indicates that you are writing the entire dataset.
Example: Writing individual paired data curves
This example pre-allocates space for a paired data record so that individual curves can be written at a later time. Curves 4-5, rows 10-20 are read and tabulated.
#include <stdio.h>
#include <string.h>
#include "heclib.h"
// Write a family of curves by allocating space, then writing one curve at a time
int ExamplePairedData3()
{
long long ifltab[250];
zStructPairedData *pds1, *pds2;
// double xOrdinates[int numberOrdinates]
double xOrdinates[100];
// double yOrdinates[int numberCurves][int numberOrdinates]
double yOrdinates[1][100];
char labels[200];
int labelLength;
int status, i, j, pos;
// Open the DSS file; Create if it doesn't exist
status = zopen(ifltab, "C:/temp/Example7.dss");
// If an error occured, messages will be printed to standard out
if (status != STATUS_OKAY) return status;
// Allocate space for 100 rows for a family of 10 curves
// Gen up the ordinates
for (i = 0; i<100; i++) {
xOrdinates[i] = (double)(i + 1) * 2;
}
pds1 = zstructPdNewDoubles("/Basin/Location/Stage-Damage///C Sample/”,
xOrdinates, (double *)yOrdinates, 100, 10, "Feet", "Linear", "Dollars", "Linear");
// Set display precision (for tables, etc.)
pds1->xprecision = 2; // 1.23
pds1->yprecision = 3; // 1.234
// Add labels
labelLength = 0;
for (j = 0; j < 10; j++) {
sprintf_s(&labels[labelLength], sizeof(labels) - labelLength, "Plan %2d", (j + 1));
labelLength += 8;
}
pds1->labels = labels;
pds1->labelsLength = labelLength;
status = zpdStore(ifltab, pds1, 10);
zstructFree(pds1);
if (status != STATUS_OKAY) return status;
// Now write each of the 10 curves separately
for (j=0; j<10; j++) {
pds1 = zstructPdNew("/Basin/Location/Stage-Damage///C Sample/”);
// Gen data
for (i=0; i<100; i++) {
yOrdinates[0][i] = ((double)(i + 1) * 100.0) + (double)((j + 1) * 3000);
}
// First curve is #1, not #0 (by convention)
pds1->startingCurve = j + 1;
pds1->endingCurve = j + 1;
pds1->doubleValues = (double *)yOrdinates;
status = zpdStore(ifltab, pds1, 0);
zstructFree(pds1);
if (status != STATUS_OKAY) return status;
}
// Read curve 2 (only). We won't do anything with this struct...
pds2 = zstructPdNew("/Basin/Location/Stage-Damage///C Sample/”);
pds2->startingCurve = 2;
pds2->endingCurve = 2;
status = zpdRetrieve(ifltab, pds2, 0);
if (status != STATUS_OKAY) return status;
zstructFree(pds2);
// Read curves 4 and 5 for rows 10-20 and tabulate
pds2 = zstructPdNew("/Basin/Location/Stage-Damage///C Sample/”);
pds2->startingOrdinate = 10;
pds2->endingOrdinate = 20;
pds2->startingCurve = 4;
pds2->endingCurve = 5;
status = zpdRetrieve(ifltab, pds2, 0);
if (status != STATUS_OKAY) return status;
// Print out labels
if (pds2->labelsLength > 0) {
printf("\n\n ");
labelLength = 0;
for (j = 0; j < pds2->numberCurvesInStruct; j++) {
printf(" %s ", &pds2→labels[labelLength]);
labelLength += (int)strlen(&pds2->labels[labelLength]) + 1;
if (labelLength > pds2->labelsLength) break;
}
printf("\n\n");
}
// Print out. Number ordinates and curves are for full data set
// (e.g., doubleValues[0] is for [pds2->startingCurve][pds2→startingOrdinate]
for (i = 0; i < pds2->numberOrdinatesInStruct; i++) {
pos = i + pds2→startingOrdinate;
printf("Ordinate %d, %9.1f, Curve value(s) ", pos, pds2→doubleOrdinates[i]);
for (j = 0; j < pds2->numberCurvesInStruct; j++) {
// Array in struct is single dimensioned, so we compute position for double dim.
// pos = (curve number in struct * numberOrdinates in struct) + ordinate;
pos = (j * pds2->numberOrdinatesInStruct) + i;
printf(" %9.1f", pds2→doubleValues[pos]);
}
printf("\n");
}
zstructFree(pds2);
zclose(ifltab);
return 0;
}
Plan 4 Plan 5
Ordinate 10, 20.0, Curve value(s) 13000.0 16000.0
Ordinate 11, 22.0, Curve value(s) 13100.0 16100.0
Ordinate 12, 24.0, Curve value(s) 13200.0 16200.0
Ordinate 13, 26.0, Curve value(s) 13300.0 16300.0
Ordinate 14, 28.0, Curve value(s) 13400.0 16400.0
Ordinate 15, 30.0, Curve value(s) 13500.0 16500.0
Ordinate 16, 32.0, Curve value(s) 13600.0 16600.0
Ordinate 17, 34.0, Curve value(s) 13700.0 16700.0
Ordinate 18, 36.0, Curve value(s) 13800.0 16800.0
Ordinate 19, 38.0, Curve value(s) 13900.0 16900.0
Ordinate 20, 40.0, Curve value(s) 14000.0 17000.0
Ordinate 10, 20.0, Curve value(s) 13000.0 16000.0
Example: Combining curves from multiple datasets into one
This example demonstrates reading a individual curve from 5 paired datasets and then combining into one using pre-allocation.
#include <stdio.h>
#include <string.h>
#include "heclib.h"
// Write a matrix of paired data sets
// There are 5 conditions (records), each with 10 plans
// Then take the curves of one plan and combine into a single record
int ExamplePairedData4()
{
long long ifltab[250];
zStructPairedData *pds1, *pds2;
// double xOrdinates[int numberOrdinates]
double xOrdinates[100];
// double yOrdinates[int numberCurves][int numberOrdinates]
double yOrdinates[1][100];
char labels[200];
char pathname[100];
int labelLength;
int status, i, j, k, pos;
// Open the DSS file; Create if it doesn't exist
status = zopen(ifltab, "C:/temp/Example7.dss");
// If an error occured, messages will be printed to standard out
if (status != STATUS_OKAY) return status;
// Allocate space for 100 rows for a family of 10 curves
// Gen up the ordinates
for (i = 0; i<100; i++) {
xOrdinates[i] = (double)(i + 1) * 2;
}
for (k = 0; k < 5; k++) {
sprintf_s(pathname, sizeof(pathname), "/Basin/Location/Stage-Damage///Condition %d/", (k + 1));
pds1 = zstructPdNewDoubles(pathname, xOrdinates, (double *)yOrdinates, 100, 10,
"Feet", "Linear", "Dollars", "Linear");
// Add labels
labelLength = 0;
for (j = 0; j < 10; j++) {
sprintf_s(&labels[labelLength], sizeof(labels) - labelLength, "Plan %2d", (j + 1));
labelLength += 8;
}
pds1->labels = labels;
pds1->labelsLength = labelLength;
status = zpdStore(ifltab, pds1, 10);
zstructFree(pds1);
if (status != STATUS_OKAY) return status;
// Write each of the 10 curves separately
for (j = 0; j < 10; j++) {
pds1 = zstructPdNew(pathname);
// Gen data
for (i = 0; i < 100; i++) {
yOrdinates[0][i] = ((double)(i + 1) * 100.0) + (double)((j + 1) * 3000) + (double)(k * 5);
}
pds1->startingCurve = j + 1;
pds1->endingCurve = j + 1;
pds1->doubleValues = (double *)yOrdinates;
status = zpdStore(ifltab, pds1, 0);
zstructFree(pds1);
if (status != STATUS_OKAY) return status;
}
}
// Combine all the Plan 6's into one record, with the conditions being the curves
for (k = 0; k < 5; k++) {
// Get the pathname of the data to read
sprintf_s(pathname, sizeof(pathname), "/Basin/Location/Stage-Damage///Condition %d/", (k + 1));
pds1 = zstructPdNew(pathname);
pds1->startingCurve = 6;
pds1->endingCurve = 6;
status = zpdRetrieve(ifltab, pds1, 0);
if (status != STATUS_OKAY) return status;
if (k == 0) {
// If this is the first iteration, allocate the struct to hold the conditions
pds2 = zstructPdNewDoubles("/Basin/Location/Stage-Damage///Conditions for Plan 6/",
pds1->doubleOrdinates, (double *)yOrdinates, pds1->numberOrdinates, 5,
pds1->unitsIndependent, pds1->typeIndependent, pds1->unitsDependent, pds1→typeDependent);
// Add labels
labelLength = 0;
for (j = 0; j < 5; j++) {
sprintf_s(&labels[labelLength], sizeof(labels) - labelLength, "Condition %d", (j + 1));
labelLength += 12;
}
pds2->labels = labels;
pds2->labelsLength = labelLength;
status = zpdStore(ifltab, pds2, 10);
zstructFree(pds2);
if (status != STATUS_OKAY) return status;
}
pds2 = zstructPdNew("/Basin/Location/Stage-Damage///Conditions for Plan 6/");
pds2->doubleValues = pds1→doubleValues;
// curves start at number 1, not 0.
pds2->startingCurve = k + 1;
pds2->endingCurve = k + 1;
status = zpdStore(ifltab, pds2, 0);
zstructFree(pds2);
if (status != STATUS_OKAY) return status;
}
zstructFree(pds1);
// Now read and print the first 5 rows of the new record
pds2 = zstructPdNew("/Basin/Location/Stage-Damage///Conditions for Plan 6/");
pds2->startingOrdinate = 0;
pds2->endingOrdinate = 5;
status = zpdRetrieve(ifltab, pds2, 0);
if (status != STATUS_OKAY) return status;
// Print out labels
if (pds2->labelsLength > 0) {
printf("\n\n ");
labelLength = 0;
for (j = 0; j < pds2->numberCurvesInStruct; j++) {
printf(" %s ", &pds2→labels[labelLength]);
labelLength += (int)strlen(&pds2->labels[labelLength]) + 1;
if (labelLength > pds2->labelsLength) break;
}
printf("\n\n");
}
// Print out.
for (i = 0; i < pds2->numberOrdinatesInStruct; i++) {
pos = i + pds2→startingOrdinate;
printf("Ordinate %d, %9.1f, Curve value(s) ", pos, pds2→doubleOrdinates[i]);
for (j = 0; j < pds2->numberCurvesInStruct; j++) {
// pos = (curve number in struct * numberOrdinates in struct) + ordinate;
pos = (j * pds2->numberOrdinatesInStruct) + i;
printf(" %9.1f", pds2→doubleValues[pos]);
}
printf("\n");
}
zstructFree(pds2);
zclose(ifltab);
return 0;
}
Condition 1 Condition 2 Condition 3 Condition 4 Condition 5
Ordinate 0, 2.0, Curve value(s) 18100.0 18105.0 18110.0 18115.0 18120.0
Ordinate 1, 4.0, Curve value(s) 18200.0 18205.0 18210.0 18215.0 18220.0
Ordinate 2, 6.0, Curve value(s) 18300.0 18305.0 18310.0 18315.0 18320.0
Ordinate 3, 8.0, Curve value(s) 18400.0 18405.0 18410.0 18415.0 18420.0
Ordinate 4, 10.0, Curve value(s) 18500.0 18505.0 18510.0 18515.0 18520.0