Objects
TODO - Review - I'm assuming there are things to say here that are not about the object synchronization process (which has its own page) and are not about device modeling (which also has its own page); this is the kind of content that will go on this page.
GridLAB-D™ objects are malloc’ed (memory allocation) structures that include enough space for a GridLAB-D™ object header and an instance of the class. In practice, the C++ classes are created using malloc() in the core, rather than using new() in the modules. Using the properties defined for the GridLAB-D™ class, it is possible for modules with no definition for an object’s C++ class to access any published variable in that foreign class.
Synopsis
class my_class : public gld_object {
protected: // data (internal use only)
object *my();
public: // constructors
public: // header read accessors (no locking)
OBJECTNUM get_id(void);
char* get_groupid(void);
gld_class* get_oclass(void);
gld_object *get_parent(void);
OBJECTRANK get_rank(void);
TIMESTAMP get_clock(void);
TIMESTAMP get_valid_to(void);
TIMESTAMP get_schedule_skew(void);
FORECAST *get_forecast(void);
double get_latitude(void);
double get_longitude(void);
TIMESTAMP get_in_svc(void);
TIMESTAMP get_out_svc(void);
const char *get_name(void);
int get_tp_affinity(void);
NAMESPACE *get_space(void);
unsigned int get_lock(void);
unsigned int get_rng_state(void);
unsigned long get_flags(unsigned long mask=0xffffffff);
protected: // header write accessors (no locking)
void set_forecast(FORECAST *fs);
void set_latitude(double x);
void set_longitude(double x);
void #set_flags(unsigned long flags);
protected: // locking (self)
void rlock(void);
void runlock(void);
void wlock(void);
void wunlock(void);
protected: // locking (others)
void rlock(OBJECT*);
void runlock(OBJECT*);
void wlock(OBJECT*);
void wunlock(OBJECT*);
protected: // member lookup functions
property* get_property(char *name);
FUNCTIONADDR* get_function(char *name);
public: // external accessors
template <class T> void getp(property *prop, T &value);
template <class T> void getp(property *prop, T &value, gld_rlock&);
template <class T> void getp(property *prop, T &value, gld_wlock&);
template <class T> void setp(property *prop, T &value);
template <class T> void setp(property *prop, T &value, gld_wlock&);
public: // core interface
int set_dependent(object *obj);
int set_parent(object *obj);
int set_rank(unsigned int r);
bool isa(char *type);
public: // iterators
bool is_last(void);
object *get_next(void);
}
Description
The gld_object base class provides the basic linkage to GridLAB-D™'s core. It supersedes the implementation of the core linkage provided by using the macros and callbacks included in gridlabd.h. As of Hassayampa (Version 3.0) new modules should be implemented using this method to support multithreading properly.
Runtime Classes
If a class block is defined, and that class is not already implemented by an existing module, then you may define class behavior for each of the supported behaviors in GridLAB-D™. Such classes are called runtime classes and are only be supported if you have installed MinGW on your system. Use of the compiler is automatic and does not need to be explicitly configured. However, if you have installed GridLAB-D™ in an unusually location, you may have to set the global variable INCLUDE to indicate where the rt/gridlabd.h file is located. You may also want to add the location of any files that the #include macros are expected to find.
The supported behaviors for runtime classes include:
create (object <parent>) { ... return [SUCCESS|FAILED];};is used to define the object creation behavior other than the default behavior (which is to set the entire object's memory buffer to 0). Usually parent is not defined at this point. Object creation functions are called when the object's memory is allocated, while initialization isn't performed until after all objects have been created and the parent/child hierarchy established.init (object <parent>) { ... return [SUCCESS|FAILED];};is used to define object initialization behavior, which is delayed until all objects have been created and their properties set as defined in the model file. Usually initialization is a good time to adjust dependent properties and/or check for inconsistencies in the values provided.[presync|sync|postsync] (TIMESTAMP t0, TIMESTAMP t1) { TIMESTAMP t2 = TS_NEVER; ... return t2;};is used to implement presync, sync, and postsync behavior. Presyncs are called on the first top-down pass, syncs are called on the bottom-up pass, and postsyncs are called on the last top-down pass. The top-down/bottom-up order in which objects are evaluated is based on their ranks. Rank is determined primarily by the parent-child relationship, however calls to gl_set_rank() can be used to promote the rank of an object arbitrarily with respect to another object. (Objects cannot be demoted.)plc (TIMESTAMP t0, TIMESTAMP t1) {TIMESTAMP t2 = TS_NEVER; ... return t2;};is used to define the default programmable logic controller (PLC) behavior. This behavior is overridden if a plc refers to this object as its parent.
Over time other behaviors, such as check, import, export, kmldump, etc. will be added, as needed.
Expanded values
An expression written in back quotes will be parsed in such a way that expressions in curly-braces are expanded in the context of the object being loaded. The following values are expanded
{file}embeds the current file (full path,name,extension){filename}embeds the name of the file (no path, no extension){fileext}embeds the extension of the file (no path, no name){filepath}embeds the path of the file (no name, no extension){line}embeds the current line number{namespace}embeds the name of the current namespace{class}embeds the classname of the current object{id}embeds the id of the current object{var}embeds the current value of the current object's variable var
For example,
namespace space1 {
object mytest {
name `{namespace}::{class}:{id}`;
};
}
will result in the object having a name like space1::mytest:0.
TODO - Empty - gld_object: Describe class members
Class parameters
Class methods
getp
void gld_object::getp(property &prop ,TYPE &value)
This template provides a general-purpose locked read accessor for all published properties of the class.
// allocate local space for value
double myvalue = 0;
// get property information
gld_property prop(my(),"value");
// get value (using read lock)
getp(prop,myvalue);
void gld_object::getp(property &prop ,TYPE &value , gld_rlock &lock)
void gld_object::getp(property &prop ,TYPE &value , gld_wlock &lock)
This functions allow reading of data with an existing lock to avoid deadlocks.
double myvalue;
gld_property prop(my(),"value");
if ( prop.is_valid() )
{
gld_wlock lock(my());
getp((PROPERTY*)prop,myvalue,lock);
myvalue*=3.14;
setp((PROPERTY*)prop,myvalue,lock);
}
Although the above code works fine, it is often easier to use the gld_property's get/set members:
double myvalue;
gld_property prop(my(),"value");
if ( prop.is_valid() )
{
gld_wlock lock(my());
prop.getp(myvalue,lock);
myvalue*=3.14;
prop.setp(myvalue,lock);
}
get_clock
TIMESTAMP gld_object::get_clock(void)
This returns the object's clock.
// get the object's clock and convert it to a string
gld_clock t3(get_clock());
char buffer64;
t3.to_string(buffer,sizeof(buffer));
get_flags
get_forecast
get_id
get_in_svc
get_groupid
get_latitude
get_lock
get_longitude
get_name
This function is used to get the name of the keyword.
public: // read accessors
char* get_name(void);
unsigned int64 get_value(void);
get_next
This function is used to get the next keyword.
public: // iterators
bool is_last(void);
gld_keyword* get_next(void);
Where the cast KEYWORD* is used to obtain a pointer to the underlying core data structure for the property keyword.
get_oclass
get_out_svc
get_parent
get_property
get_rank
get_rng_state
get_schedule_skew
get_space
get_tp_affinity
get_valid_to
gld_objlist
The advanced object list handling routine provide a mechanism to create a list of objects that match a particular criteria, to scan through the list, and to apply a function to the list.
class gld_objlist {
private:
struct s_objlist *list;
public:
inline operator OBJLIST*();
public:
inline gld_objlist(void);
inline gld_objlist_objlist(CLASS *c, PROPERTY *m, char *p, char *o, void *a, void *b=NULL);
inline gld_objlist_objlist(char *cn, char *mn, char *p, char *o, void *a, void *b=NULL);
inline ~gld_objlist_objlist(void);
public:
inline size_t add(PROPERTY *m, char *p, char *o, void *a, void *b=NULL);
inline size_t del(PROPERTY *m, char *p, char *o, void *a, void *b=NULL);
inline size_t add(char *cn, char *mn, char *p, char *o, void *a, void *b=NULL);
inline size_t del(char *cn, char *mn, char *p, char *o, void *a, void *b=NULL);
public:
inline bool is_valid(void);
inline size_t get_size(void);
inline OBJECT *get(size_t n);
inline int apply(void *arg, int (*function)(OBJECT *,void*,int));
inline void exception(char *msg, ...);
};
-
gld_objlist - The constructors accept either a class/property entities or class/property names. The part, operator, a and b values are provided in a manner similar to
gld_property::compare(). Note that the a and b values must be pointers to the data and not the data itself.inline gld_objlist(void) inline gld_objlist(CLASS *oclass, PROPERTY *match, char *part, char *op, void *aval, void *bval=NULL) inline gld_objlist(char *classname, char *match_name, char *part, char *op, void *aval, void *bval=NULL) inline ~gld_objlist(void) -
add - Adds objects to the list that match the criteria given. The part, operator, a and b values are provided in a manner similar to
gld_property::compare(). Note that the a and b values must be pointers to the data and not the data itself.inline size_t add(PROPERTY *m, char *p, char *o, void *a, void *b=NULL) inline size_t add(char *cn, char *mn, char *p, char *o, void *a, void *b=NULL) -
del - Deletes objects from the list that match the criteria. The part, operator, a and b values are provided in a manner similar to
gld_property::compare(). Note that the a and b values must be pointers to the data and not the data itself.inline size_t del(PROPERTY *m, char *p, char *o, void *a, void *b=NULL) inline size_t del(char *cn, char *mn, char *p, char *o, void *a, void *b=NULL) -
** is_valid** - Returns true if the object list is valid and false if it is not valid.
bool is_valid(void) -
get_size - Returns the number of objects in the list.
size_t get_size(void) -
get - Returns a pointer to the nth object in the list.
OBJECT *get(size_t n) -
apply - Applies the function to each item in the list. The definition of arg is function specific and determined by the programmer. The function expects the first argument to be a pointer to the object, the second a pointer to the arg structure, and the third to be the object position in the list.
The function is called the first time with a pointer to the first object and the index zero, which can be used to perform any needed pre-processing on arg. The function will be called once with a NULL object pointer and -1 are the index to indicate that no further calls will be performed and the function can perform any post-processing needed on arg.
The function must return the number of items processed. If a failure occurs, the return value must be negative and the magnitude of the negative number indicates how many objects were successfully processed before the failure. Zero indicates no objects were processed, which indicates a failure on the first object only if the list contains more than zero objects.
inline int apply(void *arg, int (*function)(OBJECT *,void*,int));Applies the function to each item in the list. The definition of arg is function specific and determined by the programmer. The function expects the first argument to be a pointer to the object, the second a pointer to the arg structure, and the third to be the object position in the list.
The function is called the first time with a pointer to the first object and the index zero, which can be used to perform any needed pre-processing on arg. The function will be called once with a NULL object pointer and -1 are the index to indicate that no further calls will be performed and the function can perform any post-processing needed on arg.
The function must return the number of items processed. If a failure occurs, the return value must be negative and the magnitude of the negative number indicates how many objects were successfully processed before the failure. Zero indicates no objects were processed, which indicates a failure on the first object only if the list contains more than zero objects.
Example
The following example creates a list of object and applies a mean calculate to that list.
struct s_arg {
size_t addr; // object property addr of value used by logmean
double sum; // accumulator for sum
unsigned int n; // accumulator for count
double ans; // storage for answer
};
int mean(OBJECT *obj,void *arg,int n)
{
struct s_arg *res = (struct s_arg*)arg;
if ( obj ) // normal call
{
double x = *(double*)((char*)(obj+1)+(int64)res->addr);
res->sum += x;
res->n++;
} // last call
else
{
res->ans = res->sum / res->n;
}
return 1;
}
int example(void)
{
gl_error("mysql::collector is not supported yet");
double zero=0.0, pos=+3.0, neg=-pos;
clock_t start = clock();
gld_objlist list("example","x",NULL,"inside",&neg,&pos);
gl_verbose("%d objects found", list.get_size());
clock_t mid = clock();
struct s_arg arg = {0,0.0,00.0};
gl_verbose("result=%d, mean=%f", list.apply(&arg,mean),arg.ans);
clock_t done = clock();
gl_verbose("create time=%.3fms, apply time=%.3fms", (mid-start)*1.0e3/CLOCKS_PER_SEC,(done-mid)*1.0e3/CLOCKS_PER_SEC);
return 1;
}
gld_property
The gld_property class provides access to the properties of both objects and global variables.
class gld_property {
private: // data
PROPERTY *prop;
OBJECT *obj;
public: // constructors/casts
gld_property(OBJECT *o, PROPERTY *p);
gld_property(OBJECT *o, char *n);
gld_property(GLOBALVAR *v);
gld_property(char *n);
operator PROPERTY*(void);
public: // read accessors
int from_string(char *string);
PROPERTYACCESS get_access(void);
void* get_addr(void);
gld_class* get_class(void);
char* get_description(void);
gld_keyword* get_first_keyword(void);
PROPERTYFLAGS get_flags(void);
char *get_name(void);
size_t get_size(void);
gld_type get_type(void);
size_t get_width(void);
gld_unit* get_unit(void);
int to_string(char *buffer, int size);
public: // special operations
template <class T> void getp(T &value);
template <class T> void getp(T &value, gld_rlock &lock);
template <class T> void getp(T &value, gld_wlock &lock);
template <class T> void setp(T &value);
template <class T> void setp(T &value, gld_wlock &lock);
public: // keyword operations
gld_keyword* find_keyword(unsigned long value);
gld_keyword* find_keyword(char *name);
public: // compare operations
bool compare(char *op, char *a, char *b=NULL, char *p=NULL);
public: // iterators
PROPERTY* get_next(void);
bool is_last(void);
};
-
compare
-
bool [[#compare|compare[[(char *op, char *a, char *b=NULL, char *part=NULL)This function compares the property using the operator op to the values a (and b if the operator in inside or outside). If the value part is given and the property supports parts (e.g., complex, enduse), then the part indicated is compared.
The values a and b will be parsed using the property type.
Supported operators are ==, <=, >=, !=, <, >, inside, and outside.
Supported parts depend on the type of the property: * complex: real (double), imag (double), mag (double), arg (double), ang (double). * enduse: total (complex), energy (complex), demand (complex), breaker_amps (double), admittance (complex), current (complex), power (complex), impedance_fraction (double), current_fraction (double), power_fraction (double), power_factor (double), voltage_factor (double), heatgain (double), heatgain_fraction (double). * object: id (double), rng_state (double), tp_affinity (double), latitude (double), longitude (double), clock (timestamp), valid_to (timestamp), schedule_skew (double), in_svc (timestamp), out_svc (timestamp) * timestamp: seconds (double), minutes (double), hours (double), days (double), second (double), minute (double), hour (double), day (double), month (double), year (double), weekday (double), yearday (double), isdst (double).
-
-
find_keyword
gld_keyword* find_keyword(unsigned long value);-
gld_keyword* find_keyword(char *name);This function will find a keyword given a value or given a name.
-
from_string
-
int from_string(char *buffer)This function is used to read the string to the value associated with this property and object.
-
-
get_access
-
PROPERTYACCESS get_access(void)This function is used to determine the PROPERTYACCESS flags associated with this property.
-
-
get_addr
-
void* get_addr(void)This function is used to obtain the memory address of the data associated with this property. * get_class *
gld_class* get_class(void)This function is used to obtain a pointer to the container of the CLASS associated with this property. * get_description *
char* get_description(void)This function is used to obtain the description of the property, if any. A NULL pointer is returned if no description is associated with the property. * get_first_keyword *
gld_keyword* get_keyword(void)This function is used to obtain a pointer to container of the first KEYWORD associated with this property, if any. Keywords are only associated with enumeration and set properties. * get_flags *
PROPERTYFLAGS get_flags(void)This function is used to obtain the PROPERTYFLAGS associated with this property. * get_name *
char* get_name(void)This function is used to get the name of the property. * get_next *
PROPERTY* get_next(void)This is used to find the next property associated with this object. * get_size *
size_t get_size(void)This function is used to determine the size of the property (in units of size of the primitive type). * get_type *
gld_type* get_type(void)This function is used to obtain a pointer to the container of the PROPERTYTYPE associated with this property. *get_unit *
gld_unit* get_unit(void)This function is used to obtain a pointer to container of the UNIT associated with this property. * getp *
void getp(PROPERTYTYPE &value)This template function is used to get the value associated with this property and object. * gld_property * There are four available constructors.
-
gld_property(OBJECT *obj, PROPERTY *prop)This constructor is used to access a property of an object when the core PROPERTY structure is already available. *
gld_property(OBJECT *obj, char *name)This constructor is used to access a property of an object when only the name of the property is available. *
gld_property(GLOBALVAR *var)This constructor is used to access a global variable's property information when the GLOBALVAR structure is already available. *
gld_property(char *name)This constructor is used to access a global variable's property information when only the name of the variable is available. * is_last *
bool is_last(void)
This is used to determine whether this property is the last in list of properties associated with this object. * PROPERTY * (PROPERTY)
This cast is used to gain access to the core PROPERTY structure used by the property. * to_string *
int to_string(char *buffer, int size)This function is used to write the value associated with this property and object to a string. * setp *
void setp(PROPERTYTYPE &value)This template is used to set the value associated with this property and object.
-
-
gld_property Examples
To obtain access a property in another object:
gld_property myvar(my_obj,"varname");
To get the value of the property (assuming it's a double):
double value;
myvar.getp(value);
To set the value of the property (assuming it's a double):
myvar.setp(12.4);
To write the property to a string:
char buffer[256];
myvar.to_string(buffer,sizeof(buffer));
To read the value from a string:
myvar.from_string("18.2");
To compare the value to another value:
if ( myvar.compare("<","0") )
output_warning("myvar is negative");
is_last
bool is_last(object *obj)
This function is used to determine whether an object is the last object in the core's list of objects. This is used for iterators that wish to determine which objects come after the current object in the creation order. See the init_sequence global variable for details on the use of the creation order list.
object *obj;
for ( obj=my ; !is_last(obj) ; obj=get_next(obj) )
// iterates through all object created after _my_
bool is_last(void)
This function is used to determine whether the object my is the last object created in the core's list of objects.
isa
my
property object *my
This is always defined when the base class gld_object is used. It is used to access the object header and object data. The property my is not defined until the end of the create() call. Consequently, many member functions are not supported until after create() returns.
rlock
Scope read locks on objects may be taken using the gld_rlock class. As long as the lock is in scope, the object remain read-locked. When the lock goes out of scope the object is unlocked. The following example implements a scope read-lock for an if-else statement, thereby avoiding multiple unlock calls for each return.
int example (int test)
{
gld_rlock _lock(my);
// object is now read-locked
if ( test==1 ) return 1;
else if ( test==2 ) return 2;
else if ( test==3 ) return 3;
else return 0;
// object unlocks automatically on return
}
Caveat
Be careful not to use general purpose accessors inside scope locks. This will cause a deadlock.
gld_unit
The gld_unit class is simply a cast of the UNIT structure.
class gld_unit {
private: // data
UNIT core;
public: // constructors/casts
operator UNIT*(void);
public: // read accessors
char* get_name(void);
double get_c(void);
double get_e(void);
double get_h(void);
double get_k(void);
double get_m(void);
double get_s(void);
double get_a(void);
double get_b(void);
int get_prec(void);
public: // iterators
bool is_last(void);
gld_unit* get_next(void);
};
-
convert: Convert a value given to a new unit.bool convert(char* name, double &value) bool convert(UNIT* unit, double &value) bool convert(gld_unit &unit, double &value) -
get_a: Retrieve the scalar of the unit.double get_a(void) -
get_b: Retrieve the bias of the unit.double get_b(void)
-
get_c: Retrieve the exponent to the unit constant c.double get_c(void) -
get_e: Retrieve the exponent to the unit constant e.double get_e(void) -
get_h: Retrieve the exponent to the unit constant h.double get_h(void) -
get_k: Retrieve the exponent to the unit constant k.double get_k(void) -
get_m: Retrieve the exponent to the unit constant m.double get_m(void) -
get_name: Retrieve the name assigned to the unit.char* get_name(void) -
get_next: Retrieve the next unit in the unit list.gld_unit* get_next(void) -
get_prec: Retrieve the precision of the unit.int get_prec(void) -
get_s: Retrieve the exponent to the unit constant s.double get_s(void) -
gld_type: Construct a unit handler.gld_type(char *name) -
is_last: Determine whether the unit is the last in the unit list.bool is_last(void) -
UNIT: Cast the gld_unit to aUNITpointer.(UNIT*)
runlock
setp
gld_object::setp(property &prop ,TYPE &value)
This template provides a general-purpose locked write accessor for all published properties of the class.
// allocate local space for value
double myvalue = 0;
// get property information
gld_property prop(my,"value");
// set value (using write lock)
setp(prop,myvalue);
void gld_object::setp(property &prop ,TYPE &value , gld_wlock &lock)
This function allows writing of data with an existing lock to avoid deadlocks.
double myvalue;
gld_property prop(my(),"value");
if ( prop.is_valid() )
{
gld_wlock lock(my());
getp((PROPERTY*)prop,myvalue,lock);
myvalue*=3.14;
setp((PROPERTY*)prop,myvalue,lock);
}
Although the above code works fine, it is often easier to use the gld_property's get/set members:
double myvalue;
gld_property prop(my(),"value");
if ( prop.is_valid() )
{
gld_wlock lock(my());
prop.getp(myvalue,lock);
myvalue*=3.14;
prop.setp(myvalue,lock);
}
set_dependent
set_forecast
set_longitude
set_latitude
set_parent
set_rank
structure
Built-in multipart data structures are used to collect multiple object properties under a single name that can be referenced.
To define a new member of a class in a GLM file, use the class directive. For example
class my_class {
structure {
double a[kW];
complex b[kVA];
} c;
}
creates a structure named c with two members a and b having units compatible with Watts.
Structure member can be set three ways in GLM files:
-
Formal definition - The formal definition of a structure uses a pair of curly braces to enclose the data in a structure in a form that is generally compatible with the object (directive). For example:
object my_class { c { a 1200 W; b 1.2+0.1j kVA; }; }Structure data will be output using the GLM-compatible format.
-
String definition - The string definition of a structure uses a quoted string to represent the data in a form that is compatible with the string output of data for XML and other general data exchange formats. For example:
object my_class { name d; c "a:1200 W; b:1.2+0.1j kVA"; }Note that the string form does not support nested structure definitions. Structure data will be output using an XML-compatible format.
-
Serial definition - The serial definition of a structure uses a comma-separated series of values that is compatible with the serial output of data for legacy system data exchange. For example:
object my_class { name d; c "1.2, 1.2+0.1j"; }Note that the serial form does support nested structure definitions, but assumes that value are presented in the order in which they are declared. Structure data will be output using a CSV-compatible format.
From the command line,
host% **gridlabd -D
structure_format=FORMAL|STRING|SERIAL**
In a glm,
#set structure_format=FORMAL|STRING|SERIAL
wlock
Scope write locks on objects may be taken using the gld_wlock class. As long as the lock is in scope, the object remain write-locked. When the lock goes out of scope the object is unlocked. The following example implements a scope write-lock for an if-else statement, thereby avoiding multiple unlock calls for each return.
{ gld_wlock lock(my());
// object is now write-locked
value1 = 12.3;
value2 = 45.6;
} // object unlocks when lock goes out of scope
Caveat
Be careful not to use general purpose accessors inside scope locks. This will cause a deadlock. If you need to set or get a property while a scope lock is held then use the unlocked accessors, e.g.,
gld_property prop(obj,"varname"); // access the object's property
if ( prop.is_valid() ) // verify that the property is valid
{
double value; // create local space for the value
gld_wlock lock(obj); // lock the object
prop.getp(value,lock); // get the old value
value+=12.3; // modify the value
prop.setp(value,lock); // set the new value
} // unlock is automatic when lock goes out of scope
wunlock
Version
The C++ Module API was introduced in Hassayampa (Version 3.0) to ensure support for multithreading.
Javascript Calls
GLDGetGlobal
Get a global variable in javascript
<SCRIPT src="gridlabd.js">
value = GLDGetGlobal("name");
</SCRIPT>
GLDGetProperty
Get an object property in javascript
<SCRIPT src="gridlabd.js">
value = GLDGetProperty("object-name","property-name");
value = GLDGetProperty("object-name","property-name[unit]");
value = GLDGetProperty("object-name","property-name[unit,format]");
</SCRIPT>
GLDSetGlobal
Set a global variable in javascript
<SCRIPT src="gridlabd.js">
GLDSetGlobal("name","value");
</SCRIPT>
GLDSetProperty
Set an object property in javascript
<SCRIPT src="gridlabd.js">
GLDSetProperty("object-name","property-name","value");
GLDSetProperty("object-name","property-name","value[unit]");
</SCRIPT>