Creating a class

Creating a class - Procedure to create a new class in a GridLAB-D™ module

Synopsis

_module-name_ /_class-name_.h
_module-name_ /_class-name_.cpp
_module-name_ /Makefile.am
_module-name_ /_module-name_.vcproj

Header file

module-name /class-name.h

// $ Id$
// Copyright (c) <<<YEAR>>> <<<COMPANY>>>
// Template valid as of Hassayampa (Version 3.0)
#ifndef _<<<CLASS>>>_H
#define _<<<CLASS>>>_H
#include "gridlabd.h"
class <<<CLASS>>> : public gld_object {
public: // published variables
  // **TODO** add public typedefs
  // **TODO** declare published variables using GL_* macros
private: // unpublished variables
  // **TODO** add private typedefs
  // **TODO** add unpublished variables
public: // required functions
  <<<CLASS>>>(module *module);
  int create(void);
  int init(OBJECT *parent);
  // **TODO** add optional class functions
public: // optional/user-defined functions
  // **TODO** add published class functions
private: // internal functions
  // **TODO** add desired internal functions
public: // required members
  static class *oclass;
  static <<<CLASS>>> *defaults;
};
#endif // _<<<CLASS>>>_H

Source file

module-name /class-name.cpp

// $ Id$
// Copyright (c) <<<YEAR>>> <<<COMPANY>>>
// Template valid as of Hassayampa (Version 3.0)
#include "<<<CLASS>>>.h"
EXPORT_CREATE(<<<CLASS>>>);
EXPORT_INIT(<<<CLASS>>>);
// **TODO** add optional functions declarations
class <<<CLASS>>>::oclass = NULL;
<<<CLASS>>> *<<<CLASS>>>::defaults = NULL;
// **TODO** add declaration of class globals
<<<CLASS>>>::<<<CLASS>>>(module *module)
{
  if ( oclass!=NULL )
    exception("cannot register class more than once");
  oclass = gld_class::create(module,"<<<CLASS>>>",sizeof(<<<CLASS>>>),<<<OPTIONS>>>);
  if ( oclass==NULL )
    exception("class registration failed");
  oclass->trl = <<<TRL>>>;
  if ( gl_publish_variable(oclass, <<<VARIABLESPECS>>>, NULL)<1 )
    exception("unable to publish properties");
  memset(defaults=this,0,sizeof(*this));
  // **TODO** set defaults
}
<<<CLASS>>>::create(void)
{
  memcpy(this,defaults,sizeof(*this));
  // **TODO** set defaults
  return SUCCESS; // return FAILED on create error
}
<<<CLASS>>>::init(OBJECT *parent)
{
  // **TODO** initialize object
  return SUCCESS; // return FAILED on create error
}
// **TODO** add implementations of optional class functions

Autoconf file

module-name /Makefile.am

pkglib_LTLIBRARIES = <<<MODULE>>>.la
<<<MODULE>>>_la_SOURCES = main.cpp \
    <<<CLASS>>>.cpp <<<CLASS>>>.h \
       # **TODO** add new classes before this line
<<<MODULE>>>_la_LDFLAGS = -module -no-undefined -avoid-version -version-info 1:0:0

uninstall-hook:
    -rmdir $(DESTDIR)$(pkglibdir)

Project file

Additional include directories ..\core Debug information format Program Database (/Zi)

TODO: add other VS project options

Pass control

TODO:

Forced naming

The canonical name is the name automatically assigned to an object when name defined name is given by the modeler. The canonical name takes the form given by the object_format global variable.

object class {
name class: id;
}

Object may be assigned user-defined names using the naming variable. These names may be referred to be other objects using the object property.

object class {
name name ;
}

For example:

object house {
   name house1;
   ...
};

In this way, other objects can refer to this object by name. For example, an appliance can be added to the house by referencing the house's name in the parent-child relationship:

object waterheater {
   parent house1;
   name waterheater1;
   ...
};

There are some restrictions on the characters that can be used in name. Here are the rules for creating a name:

  1. All printable ASCII characters are allowed with some exceptions that are reserved for special functions (reserved: ., (), {}, [], ^, $, *, +, =, |, :, and ;).
  2. Only alpha characters (A-Z,a-z) can be used at the beginning of the name. (This rule can be relaxed if relax_naming_rules is set to non-zero).
  3. " " can be used to enclose the name. This is advisable when using spaces or other non-alphanumeric characters. NOTE: While "name" has a 1024 character limit, in practice, the limit is 64 characters. See ticket 980.

Automatic locking

TODO:

Observers

TODO:

Parent classes

TODO:

Abstract classes

TODO:

Parent overrides

TODO:

Built-in Types

GridLAB-D™ supports a range of built-in data types for use in defining classes.

To declare a char8 value in a class use the syntax

    class my_class {
      char8 my_string;
    }

To define a string value in an object use the syntax

    object my_class {
      my_string "value";
    }


where "value" is a string of 8 or fewer characters... Similarly for the remaining char data types. Note that an attempt to store a string longer than the maximum number of characters permitted results in truncation of the string to a length that fits.

Prior to Hassayampa (Version 3.0) there was no difference between the C and C++ implementations. Where noted, C++ specific information pertains only to versions as of Hassayampa (Version 3.0).

Type Description
bool C This is a typedef to long C type.
C++ This is the basic bool C++ type.
char8 This is a typedef to char[9].
C++ This is a template based on charbuf<9>.
char32 This is a typedef to char[33].
C++ This is a template based on charbuf<33>.
char256 This is a typedef to char[33].
C++ This is a template based on charbuf<257>.
char1024 This is a typedef to char[1025].
C++ This is a template based on charbuf<1025>.
complex C This is a typedef to the struct s_complex.
C++ This is the class Dev:complex.
complex_array C This is a typedef to the struct s_doublearray.
C++ This is the class double_array.
delegated
double This is the C/C++ basic double C type.
double_array C This is a typedef to the struct s_doublearray.
C++ This is the class double_array.
enduse This is the s_enduse structure.
enumeration This is a typedef to the long C type.
float This is the basic float C type.
int8 This is a typedef to the signed char C type. Integers requiring 8 bits are stored in an int8 built-in data type. An int8 value can represent values between -128 to 127.
int16 This is a typedef to the signed short C type. Integers requiring 16 bits are stored in an int16 built-in data type. An int16 value can represent values between -32,768 to 32,767.
int32 This is a typedef to the signed long C type.
int64 This is a typedef to the signed longlong C type. Integers requiring 64 bits are stored in an int64 built-in data type. An int64 value can represent values between −9,223,372,036,854,775,808 to 9,223,372,036,854,775,807.
loadshape This is the s_loadshape structure.
object This is the s_objectlist structure.
object_array
real
set This is a typedef to the int64 C type.
structure
timestamp This is a typedef to the int64 C type.
transform This is the s_transform structure.
randomvar This is the s_randomvar structure.
void built-in data type is used to describe an data item that contains no information.

Charbuf

template<size_t size> class charbuf {
private:
  char buffer[size];
public:
  charbuf<size>(void);
  charbuf<size>(const char *s);
  ~charbuf<size>(void);
  size_t get_size(void);
  size_t get_length(void);
  char *get_string(void);
  char* erase(void);
  char* copy_to(char *s);
  char* copy_from(const char *s);
  operator char*(void);
  bool operator ==(const char *s);
  bool operator <(const char *s);
  bool operator <(const char *s);
  bool operator <=(const char *s);
  bool operator >=(const char *s);
  char *find(const char c);
  char *find(const char *s);
  char *findrev(const char c);
  char *token(char *from, const char *delim, char **context);
  size_t format(char *fmt, ...);
  size_t vformat(char *fmt, va_list ptr);
};
typedef charbuf<1025> char1024;
typedef charbuf<257> char256;
typedef charbuf<33> char32;
typedef charbuf<9> char8;
Property Description
copy_from Copies data from a string into the buffer.
copy_to Copies data to a string from the buffer.
erase Erases the buffer.
find Finds a character or string in the buffer.
findrev Find a character in the buffer starting from the end.
format Formats the buffer using printf syntax.
get_size Gets the size of the buffer.
get_length Gets the length of the string in the buffer.
get_string Gets a pointer to the string in the buffer.
operator char* Casts to a char* type, which effectively gets a pointer to the string in the buffer.
operator == True is the string and the buffer are identical.
operator < True if the buffer is alphabetically before the string.
operator > True if the buffer is alphabetically after the string.
operator <= True if the buffer is alphabetically before or the same as the string.
operator >= True if the buffer is alphabetically after or the same as the string.
token Find the first (or next) instance of a delimited string in the buffer.
vformat Formats the string using vprintf syntax.

Caveat

You cannot rely on C++ compiler to automatically convert from the charbuf class to a string when using variable argument functions. This is a very insidious problem for certain compilers. In the absence of a cast or function that returns a char*, the compiler will either copy the entire buffer onto the stack (which is not what is usually expected) or reject the statement as an error due to the lack of a copy constructor. Therefore instead of

printf("%s",~~member~~);

you should use either

printf("%s",(const char*)member);

or

printf("%s",member.get_string());

Double Array

The double_array is a built-in type type and implemented as a class in the C++ Module API. This class allows basic math operations on arrays.

#include "myclass.h"
myclass::myclass(MODULE *module)
{
  // ...
  if ( gl_publish(oclass,
      PT_double_array,"name",get_name_offset(), // other options...
      NULL)<1 )
      exception("unable to publish module myclass properties");
  // ...
}
int myclass::create(void)
{
  // ...
  name.set_name("name");
  // ...
}
int myclass::init(OBJECT *parent)
{
  // ...
  set_name("'a'11 'a'12 ... 'a'1M ; 'a'21 'a'22 ... 'a'2M ; 'a'N1 'a'N2 ... 'a'NM");
}

Example

A good example of using double_array is the canonical control model:

int example::sync(timestamp t1)
{
    TIMESTAMP ts = 10; // discrete-time model time step
    Y = C*X + D*U;
    X += A*X + B*U;
    return (t1/ts+1)*ts;
}

The declarations for the arrays are

GL_STRUCT(double_array,A); ///< A matrix (state transition)
GL_STRUCT(double_array,B); ///< B matrix (control)
GL_STRUCT(double_array,C); ///< C matrix (output)
GL_STRUCT(double_array,D); ///< D matrix (feedfwd)
GL_STRUCT(double_array,X); ///< state vector X (state)
GL_STRUCT(double_array,U); ///< control vector U (input)
GL_STRUCT(double_array,Y); ///< output vector Y (output)

The user would then provide the input and output properties and the model definition in the GLM file. The following example is a SISO model (the extension to MIMO is intuitive).

module 
class example {
  double input;
  double output;
}
object example {
  input 0;
  output 0;
  A "0 1 ; -0.16 -1"; // dimensions must match state vector 
  B "1 ; 1"; // dimensions must match state vector and input
  C "1 0"; // dimensions must match state vector and output
  D "0"; // dimensions must match input input and output
  U "input";
  X "0 ; 0";
  Y "output";
  object player {
      property input;
      file input.csv;
  };
  object recorder {
      property output;
      file output.csv;
      interval -1;
  };
};

Enumeration

The enumeration built-in data type is used to describe a value that can have one of several discrete states. An enumeration is distinguished from a set by the fact that sets can have any combination of the states, whereas enumerations can have only one at a time.

class my_class {
  enumeration {A=1, B=2, C=3, D=4} my_enum;
}
object my_class {
  my_enum A;
}

Integral

The integral property automatically calculates the average integral of variable1 with respect to another variable2. If dt is used, the integral is with respect to the global clock. The value of the integral is updated whenever variable1 or variable2 changes. If dt is used, the value of the integral is updated after the object's clock is updated.

Both variables must have either double or complex underlying type. The multiplication is performed according to the usual mathematical rules for a product of double and complex values, as appropriate.

The units of the integral must be consistent the units obtained when multiplying variable1 by variable2. The conversion is performed automatically each time the integral value is updated. If either of the variables has no unit, then the integral cannot have a unit, and the values are simply multiplied.

Variables can be local to the object, in which case they are simply named. If a variable in another object is used, the name of the object must be prepended, as in object_name.variable.

Global variables may used provided the are of double or complex type. The syntax for a global variable is ::variable for core globals and module::variable for module globals.

Example

The following example maintains the integral of the random variable \(x\) with respect to time and names it \(Sx\).

class example {
  random x[m];
  integral Sx[m/s];
}

object example {
  x "type:normal(0,1); refresh:1h";
  Sx S(x)dt;
  object recorder {
    property "x,Sx";
    interval -1;
    file example.csv;
  };

}

Loadshape

The basic principle underpinning loadshape is that the total energy \(E\) consumed by a series of \(N\) pulses

\[E = N P \Delta t \tag1\]

where

  • \(P\) is the power of each pulse
  • \(\Delta t\) is the duration of each pulse.

At least one of the variables E, N, P, \(\Delta t\) must remain unspecified by the user in order for Eq. 1 to not be overspecified. Thus

\[N = \frac{E}{P \Delta t}\tag{1a}!\]

is used to determine the number of pulses,

\[\Delta t = \frac{E}{P N}\tag{1b}!\]

is used to determine the pulse duration, and

\[P = \frac{E}{P \Delta t}\tag{1c}!\]

is used to determine the power of each pulse.

In cases where the standard deviation \(\sigma\) is provided, the power of the pulse is adjusted so that

\[P_{adjusted} = Normal[P,\sigma]\tag2\]

Analog loadshapes

When the analog loadshape power \(P\) is given, the loadshape amplitude \(y_t\) at the time \(t\) shall be computed from schedule value \(x_t\) as

\[y_t = P x_t \tag3!\]

When the analog loadshape energy \(E\) is given, the loadshape amplitude \(y_t\) at the time \(t\) shall be computed from the schedule values \(x_t\) in the interval \(t=(0,T)\) as

\[y_t = \frac{E x_t}{\sum_{t=0}^T x_t \Delta t}\tag4\]

where

  • \(\Delta t\) is the time interval over which the schedule value \(x_t\) is given.

When neither the energy nor the power are given, the loadshape amplitude \(y_t\) at the time \(t\) shall be the schedule value \(x_t\).

Pulsed shapes

When a pulse loadshape is specified, the power amplitude \(y_t\) at the time \(t\) based on the schedule value \(x_t\) is given by

\[y_t = \frac{E}{N \Delta t} x_t\tag5\]

When the energy is not given, the power amplitude may be computed from the power and time interval

\[y_t = \frac{P T}{N \Delta t} x_t\tag6\]

When both the energy and power are given, the power amplitude may be computed as

\[y_t = \frac{P^2 T}{E}x_t\tag7\]

Modulated shapes

TODO: describe how modulated shapes are generated from schedules

Queued shapes

TODO: describe how queued shapes are generated from schedules

Scheduled shaped

TODO: describe how pulse shapes are generated from schedules

  • Guide to Programming GridLAB-D™
    • Introduction
    • Developer prerequisites
    • Programming conventions
    • Build/release process
    • Documentation Guide
    • Theory of operation
    • Creating a module
    • Module globals
    • Module functions
    • Enabling Transient Mode
    • Import/export
    • Check
    • KML output
    • Example 1
    • Creating a class
    • Class functions
    • Class globals
    • Publishing properties
    • Publishing methods
    • Notifications
    • Load methods
    • Example 2
    • Special Topics
    • Data types
    • Multithreading
    • Application links
    • Realtime server
    • Graphical user interfaces
    • Troubleshooting messages
    • Example 3
    • Source documentation
    • C/C++ Module API documentation (trunk)
    • C/C++ Module API Guide
    • Example 4
    • Validation
    • Example 5
    • Debugging
    • Debug option
    • VS2005 (MS Windows)
      • use_msvc
    • gdb option (linux/mac)
      • gdb_window
    • Runtime Class Debugging
      • compile_once
    • Code templates