Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CEP27: toolkit Snippet #297

Merged
merged 21 commits into from
Mar 27, 2021
Merged
Changes from 14 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
202 changes: 202 additions & 0 deletions source/cep/cep27.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
CEP 27 - Toolkit Capabilities Injection into an Archetype
*********************************************************

:CEP: 27
:Title: Agent Toolkit Capabilities
:Last-Modified: 2019-10-28
:Author: Baptiste Mouginot <mouginot.baptiste@gmail.com>
:Status: Active
:Type: Standards Track
:Created: Baptiste Mouginot


Abstract
========

The |Cyclus| toolkit is designed to easily implement specific capabilities in
newly developed archetypes, such as trading policy, commodity producers. To
bam241 marked this conversation as resolved.
Show resolved Hide resolved
add characteristics to archetypes such as `Position` or `Metadata`, the actual
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is still a long, awkward sentence.

implementation method is very verbose, where in each archetypes one needs to add
the new specification in the arcehtype header, then assign it and use it in the
cpp file, and the developer must ensure the consistency in the variable naming and
implementation across multiple archetypes.
This CEP explains how to use snippets to simplify and maintain consistency
bam241 marked this conversation as resolved.
Show resolved Hide resolved
in the implementation and the usage, across multiple archetypes.


Toolkit Implementation
======================

Each |Cyclus| toolkit component will contain 3 different files:
- 2 for the definition of the feature C++ class (``cpp`` and header) that allows
the use of the capabilities, and optionally to register its values in the
output database,
- a snippet definition file used to simplify the implementation and ensure
consistency accross its integration in the different archetypes.

The snippet definition file will be included in the ``private`` section of the
archetype header as: ``#include toolkit/my_snippet.cycpp.h``. (The use of the
``cycpp.h`` has been chosen to allow syntax highlighting and inform developers
that this is not a standard C++ header.)

The snippet file, will contain the declaration of all the variables required
to use the capabilities class:

- the definition of the capability class as a member variable.

- (optional) if the capability requires/allows variable input from users,
standard |Cyclus| member variable declaration with variable ``#pragma`` is
required. In addition, to the standard variable declaration and the
``#pragma`` the method also require a ``std::vector<int>
cycpp_shape_myvariable`` to be declared for each of the decorated variable
that are in the `toolkit/my_snippet.cycpp.h` file. (``cycpp preprocessor`` is
not able at the time to add them automatically for included files.)


The main purpose of this include method would be to ensure consistency across
archetypes using the same toolkit capability requiring user input, avoiding 1
set of input syntax per archetypes for the same capability.

If the toolkit features needs the capabilities to write in the output database a
``RecordSnippet(Agent* agent)`` method will be implemented in the toolkit class to avoid
multiplication of implementation in the each archetype using the feature.


Archetypes Integration
======================

When the capability is integrated in an Archetype the following implementations
have to be done:

1. Include the snippet in the class header core:
``#include toolkit/my_snippet.cycpp,h``.

2. Add the proper default initialization of the variable required for the
snippet.

3. (optional) In the ``Archetype::EnterNotify()``, initialise the toolkit class member
variables with variables.

4. (optional) If required, call the ``RecordSnippet()`` method when necessary during the
Archetype operation.


Class member vs Inheritance
===========================

With inheritance of the capability class, one will need to also modify the
archetype class declaration in addition to simply including the snippet at the
right place.
This may also lead to confusion, as one can believe that the user input value
for variable are passed in the constructor of the class and might lead the
develop to skip the assignation of the value in the inherited class in the
``EnterNotify``...

Otherwise behavior would be very similar.

Example:
========


Without Inheritance:
--------------------
``toolkit/my_snippet.cycpp.h``:
.. highlight:: c
cyclus::toolkit::Position coordinates;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this only in the version without inheritance? Is this the only difference between the with and without?

Copy link
Member Author

@bam241 bam241 Nov 27, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it also changes in the implementation of the archetype

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean the only difference in the snippet. It would be great if the same snippet could be used in both modes.


#pragma cyclus var { \
"default": 0.0, \
"uilabel": "Geographical latitude in degrees as a double", \
"doc": "Latitude of the agent's geographical position. The value should " \
"be expressed in degrees as a double." }
double latitude;
// required for compilation but not added by the cycpp preprocessor...
std::vector<int> cycpp_shape_latitude;

#pragma cyclus var { \
"default": 0.0, \
"uilabel": "Geographical longitude in degrees as a double", \
"doc": "Longitude of the agent's geographical position. The value should" \
"be expressed in degrees as a double." }
double longitude;
// required for compilation but not added by the cycpp preprocessor...
std::vector<int> cycpp_shape_longitude;

``my_archetype_example.h``:
.. highlight:: c
gonuke marked this conversation as resolved.
Show resolved Hide resolved
class fun_archetype : public cyclus::facility{
public:
[...]
private:
[...]
#include "toolkit/my_snippet.cycpp.h"
}

``my_archetype_example.cpp``:
.. highlight:: c
fun_archetype::fun_archetype(cyclus::Context* ctx):
cyclus::facility(ctx),
var1(0.0),
var2(0.0),
...,
coordinates(0,0), //coordinates constructor (toolkit feature class)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if we use C++11 can we initialize these in the snippet?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes that's true, this will be way better !

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll try this in my Position PR and see how it does work out!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it seems to be working, I updated both the PR and the CEP accordingly

longitude(0), //snippet variables added with "my_snippet.cycpp.h"
latitude(0) //snippet variables added with "my_snippet.cycpp.h"
{}
[..]
void Storage::EnterNotify() {
coordinates.set_position(latitude, longitude);
coordinates.RecordPosition(this);
[...]
}

With Inheritance:
-----------------
``toolkit/my_snippet.cycpp.h``:
.. highlight:: c
#pragma cyclus var { \
"default": 0.0, \
"uilabel": "Geographical latitude in degrees as a double", \
"doc": "Latitude of the agent's geographical position. The value should " \
"be expressed in degrees as a double." }
double latitude;
// required for compilation but not added by the cycpp preprocessor...
std::vector<int> cycpp_shape_latitude;

#pragma cyclus var { \
"default": 0.0, \
"uilabel": "Geographical longitude in degrees as a double", \
"doc": "Longitude of the agent's geographical position. The value should" \
"be expressed in degrees as a double." }
double longitude;
// required for compilation but not added by the cycpp preprocessor...
std::vector<int> cycpp_shape_longitude;

``my_archetype_example.h``:
.. highlight:: c
class fun_archetype : public cyclus::facility, public Position {
public:
[...]
private:
[...]
#include "toolkit/my_snippet.cycpp.h"
}

``my_archetype_example.cpp``:
.. highlight:: c
fun_archetype::fun_archetype(cyclus::Context* ctx):
cyclus::facility(ctx),
var1(0.0),
var2(0.0),
...,
coordinates(0,0), //coordinates constructor (toolkit feature class)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This initializer is not necessary/valid because the snippet in this example doesn't include the coordinates variable.

longitude(0), //snippet variables added with "my_snippet.cycpp.h"
latitude(0), //snippet variables added with "my_snippet.cycpp.h"
Position(0, 0)
{}
[..]
void Storage::EnterNotify() {
this.set_position(latitude, longitude);
this.RecordPosition(this);
[...]
}