Ocelet

Entity

An entity represents an element of a model. An entity can possess a number of properties that reflect its state at a given time. Entities can be defined for any element that can interact with other elements of a model. Interactions that are defined (through relations) in a model are interactions between entities.

During an interaction, the entities involved are subject to changes, that is, the property values of the entities can be changed.

An entity can also have services. A service is a function that allows access to one or several properties. Services are defined facilitate operations such as converting from one unit to another (see examples below).

Once an entity type is defined, individual entities can be created following that definition. Each individual entity will have its own state which can change during the course of a simulation.

Content


Defining an entity type

Syntax

Defining an entity type

entity name of the entity { definitions of properties and services }

An entity name must really begin with a letter (upper case preferably) but can eventually be followed by numbers, and not contain blanks or special characters.

An entity can have as many properties and services as required.


Defining a property

property Type name

The property Type is either a simple Ocelet type (Integer, Double, Point, etc.), or a composite type defined by the user using a structure.

A property name must really begin with a letter but can eventually be followed by numbers, and not contain blanks or special characters.

An entity cannot be used as a Type in the definition of a property.

N.B. when the correspondence is being established between the attributes of a data source and the properties of entities in a datafacer, attributes being of simple types always, they are to be in correspondence with simple property types. See documentation on datafacer for more details.


Defining a service

service (return type)? name ( (list of arguments)? ) { list of instructions }

A service is a function to which (optionally) can be passed as arguments, and which can (optionally) return a result. A service have access to all the properties of the entity in which it is defined, and can read and change their values.

The service name must really begin with a letter but can eventually be followed by numbers, and not contain blanks or special characters.

The return type is either a simple Ocelet type, a composite type, or an entity type.

An argument is defined by: type name

The argument type either a simple Ocelet type, a composite type, or an entity type.

The argument name must really begin with a letter but can eventually be followed by numbers, and not contain blanks or special characters.

If there are several arguments in a list, they are seperated with a comma.

The list of instructions represent the program that carries out what is expected from the function.


Examples

Cultivated field

entity Field {
  property Polygon contour
  property Integer id_parcel
  property String crop
}

The entity type Field defined here only has properties (no service). We can note the presence of a property of type Polygon describes the shape of the field and its position, and can for instance be used to show the field on a map.

Services can be added to give the barycentre of the field or its area in hectares:

entity Field {
  property Polygon contour
  property Integer id_parcel
  property String crop

  service Point getBarycentre() {
    return contour.centroid
  }

  service Double getSurfaceHa() {
    return contour.area / 10000
  }
}

Weather station

entity Station {
  property String name
  property Point location
  property Double tempC
  property Double windspeed
  property Double winddirection

  service Double getTempF() {
    return (tempC * 9 / 5) + 32
  }

  service setTempF( Double tempF ) {
    tempC = (tempF - 32) * 5 / 9
  }

}

We have here an entity that holds values measured by a weather station. The temperature property stores values in degrees Celsius. A service has been added to read and write these values as expressed in degrees Fahrenheit.

Back to top of page  

Using it in a scenario

Entity types are defined outside scenarios. Inside a scenario we refer to these definitions to create one or more individual entities. The simplest method is to declare a variable that will contain the new entity:

let field1 = new Field
let field2 = new Field
field1.crop = "cereal"
field2.crop = "fruit"
...
println("Surface area of field 1 is "+field1.getSurfaceHa()+" ha")

We can see that property of individual entities can be accessed directly using the entity and property names separated by a .. A service can be accessed in the same way.

Hence, in the example above field1.crop refer to the property crop of the entity stored in the variable field1. The instruction field1.crop = "cereal" will assign the value "cereal" to the crop property.

The last instruction of this example calls the service getSurfaceHa() to display a sentence in the console. If for example the polygon of the contour property has a surface area of 85000 m², this instruction will display:

Surface area of field 1 is 8.5 ha


Creating entities from a data source

It is possible to build a series of individual entities from a data source using a datafacer. See documentation on datafacers for more details.

Back to top of page  

Using it in a relation

Relations are used to describe what happens when entities interact with each other. In a relation, each interaction is defined as an interaction function. An interaction function can change the state of the entities involved in the interaction, that is, to modify the values of their properties.

For more details see documentation on relations.

Back to top of page  

Good to know

Adding a service toString() to your entities

This facilitates the use of println when displaying properties of an entity. When the service toString() exists, it can be used to produce a text derived from the state of the entity. In other words, if we add a service toString() to an entity, we can use the entity directly in a print() or println() to display its content.

Example

entity Sensor {
  property Integer id
  property Point pos
  property Double depth

  service String toString() {
    return "sensor n°"+id+" ("+pos.x+","+pos.y+"): "+depth+" m"
  }
}

scenario MyModel {
  let s1 = new Sensor
...
  println(" Mesurement "+s1)
}    

This last instruction will display something like:

Mesurement sensor n°15 (34.546,234.543): 236.67 m


Services getXxx() and setXxx()

Services whose names start with get or set are used as if additional properties were available: the name after the set or get can be accessed as a property with a . without calling the service itself.

Note that the name after get or set must begin with an uppercase.

Example

In the weather station example above, services were defined to access temperature in degrees Fahrenheit:

entity Station {
  property Double tempC
  ...
  service Double getTempF() {
    return (tempC * 9 / 5) + 32
  }

  service setTempF( Double tempF ) {
    tempC = (tempF - 32) * 5 / 9
  }
}

With this naming rule, it is possible to write in the scenario:

let station1 = Station{}
...
station1.tempF = 32.6
let tF = station1.tempF

instead of :

station1.SetTempF(32.6)
let tF = station1.getTempF()

and of course it is property tempC that is read or modified in all cases.


Cloning

As it is possible for a service to return an entity, it may be necessary to have a service that returns a clone of the entity to which it belongs, a clone that need not be in the same state as the original.

Example

entity Tree {
  property Point position
  property Integer age

  service Tree clone() {
    let newTree = new Tree
    newTree.position = position
    newTree.age =0
    return newTree
  }
}
Back to top of page