#ifndef GENERICMODEL_H
#define GENERICMODEL_H
/*
* genericmodel.h
*
* This file is part of NEST.
*
* Copyright (C) 2004 The NEST Initiative
*
* NEST is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* NEST is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with NEST. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "model.h"
#include "dynmodule.h"
#include <new>
namespace nest
{
/**
* Generic Model template.
* The template GenericModel should be used
* as base class for custom model classes. It already includes the
* element factory functionality, as well as a pool based memory
* manager, so that the user can concentrate on the "real" model
* aspects.
* @ingroup user_interface
*/
template <typename ElementT>
class GenericModel: public Model
{
public:
GenericModel(const std::string &);
GenericModel(const char[]);
/**
* Create copy of model with new name.
*/
GenericModel(const GenericModel&, const std::string&);
/**
* Return pointer to cloned model with same name.
*/
Model* clone(const std::string&) const;
bool has_proxies();
bool one_node_per_process();
bool is_off_grid();
/**
@note The decision of whether one node can receive a certain
event was originally in the node. But in the distributed case,
it may be that you only have a proxy node and not he real
thing. Thus, you need to be able to make this decision without
having the node. Since the model now takes responsibility for a
lot of general node properties, it was a natural place to put
this function.
Model::check_connection() is a forwarding function that call
check_connection() from the prototype. Since proxies know the
model they represent, they can now answer a call to check
connection by refering back to the model.
*/
port check_connection(Connection&, port);
Node const & get_prototype() const;
void set_model_id(int);
private:
void set_status_(DictionaryDatum);
DictionaryDatum get_status_();
size_t get_element_size() const;
/**
* Call placement new on the supplied memory position.
*/
Node* allocate_(void *);
/**
* Initialize the pool allocator with the node specific properties.
*/
void init_memory_(sli::pool &);
/**
* Prototype node from which all instances are constructed.
*/
ElementT proto_;
};
template< typename ElementT>
GenericModel<ElementT>::GenericModel(const std::string &name)
: Model(name),
proto_()
{
set_threads();
}
template< typename ElementT>
GenericModel<ElementT>::GenericModel(const char name[])
: Model(std::string(name)),
proto_()
{
set_threads();
}
template <typename ElementT>
GenericModel<ElementT>::GenericModel(const GenericModel& oldmod,
const std::string& newname)
: Model(newname),
proto_(oldmod.proto_)
{
set_type_id(oldmod.get_type_id());
set_threads();
}
template <typename ElementT>
Model* GenericModel<ElementT>::clone(const std::string& newname) const
{
return new GenericModel(*this, newname);
}
template< typename ElementT>
Node* GenericModel<ElementT>::allocate_(void *adr)
{
Node *n = new(adr) ElementT(proto_);
return n;
}
template< typename ElementT>
void GenericModel<ElementT>::init_memory_(sli::pool &mem)
{
mem.init(sizeof(ElementT), 1000, 1);
}
template <typename ElementT>
inline
bool GenericModel<ElementT>::has_proxies()
{
return proto_.has_proxies();
}
template <typename ElementT>
inline
bool GenericModel<ElementT>::one_node_per_process()
{
return proto_.one_node_per_process();
}
template <typename ElementT>
inline
bool GenericModel<ElementT>::is_off_grid()
{
return proto_.is_off_grid();
}
template <typename ElementT>
inline
port GenericModel<ElementT>::check_connection(Connection& c, port receptor)
{
return proto_.check_connection(c, receptor);
}
template <typename ElementT>
void GenericModel<ElementT>::set_status_(DictionaryDatum d)
{
proto_.set_status(d);
}
template <typename ElementT>
DictionaryDatum GenericModel<ElementT>::get_status_()
{
DictionaryDatum d = proto_.get_status_base();
(*d)["elementsize"]= sizeof(ElementT);
return d;
}
template <typename ElementT>
size_t GenericModel<ElementT>::get_element_size() const
{
return sizeof(ElementT);
}
template <typename ElementT>
Node const & GenericModel<ElementT>::get_prototype() const
{
return proto_;
}
template <typename ElementT>
void GenericModel<ElementT>::set_model_id(int i)
{
proto_.set_model_id(i);
}
/**
* Register a model prototype with the network.
* This function must be called exactly once for each model class to make
* it known to the network. The natural place for a call to this function
* is in a *module.cpp file.
* @param reference to network
* @param name under which model is to be known in simulator
* @return Model ID assigned by network
*
* @see register_private_prototype_model, register_prototype_connection
*/
template <class ModelT>
index register_model(Network& net, const std::string &name,
bool private_model = false)
{
Model* prototype = new GenericModel<ModelT>(name);
assert(prototype != 0);
return net.register_model(*prototype, private_model);
}
/**
* Register a pre-configured model prototype with the network.
* This function must be called exactly once for each model class to make
* it known to the network. The natural place for a call to this function
* is in a *module.cpp file.
*
* Pre-configured models are models based on the same class, as
* another model, but have different parameter settings; e.g.,
* voltmeter is a pre-configured multimeter.
*
* @param reference to network
* @param name under which model is to be known in simulator
* @param dictionary to use to pre-configure model
* @param register as private model if true
* @return Model ID assigned by network
*
* @see register_private_prototype_model, register_prototype_connection
*/
template <class ModelT>
index register_preconf_model(Network& net, const std::string &name,
Dictionary& conf, bool private_model = false)
{
Model* prototype = new GenericModel<ModelT>(name);
assert(prototype != 0);
conf.clear_access_flags();
prototype->set_status(conf);
std::string missed;
assert(conf.all_accessed(missed)); // we only get here from C++ code, no need for exception
return net.register_model(*prototype, private_model);
}
/**
* Register a private model prototype with the network.
* Private model prototypes differ from normal ones in that they are not
* visible in the modeldict. This is important for node types that serve
* only as in-/output elements of layers, but cannot "live" independently.
* @param reference to network
* @param name under which model is to be known in simulator
* @return Model ID assigned by network
*
* @see register_prototype_model, register_prototype_connection,
* layerdc_node, layerdc_generator
*/
template <class ModelT>
index register_private_model(Network& net, const std::string &name)
{
return register_model<ModelT>(net, name, true);
}
}
#endif