#include "field.hpp" #include "attribute_template.hpp" #include "object_template.hpp" #include "group_template.hpp" #include "node_type.hpp" #include "calendar_util.hpp" #include "message.hpp" #include "xmlioserver_spl.hpp" #include "type.hpp" #include "context_client.hpp" #include namespace xios{ /// ////////////////////// Définitions ////////////////////// /// CField::CField(void) : CObjectTemplate(), CFieldAttributes() , refObject(), baseRefObject() , grid(), file() , freq_operation(), freq_write() , nstep(0) , last_Write(), last_operation() , foperation(), hasInstantData(false), hasExpression(false) , active(false) , hasOutputFile(false),hasFieldOut(false), slotUpdateDate(NULL) , processed(false), domAxisIds_("",""), areAllReferenceSolved(false), areAllExpressionBuilt(false) { setVirtualVariableGroup() ; } CField::CField(const StdString & id) : CObjectTemplate(id), CFieldAttributes() , refObject(), baseRefObject() , grid(), file() , freq_operation(), freq_write() , nstep(0) , last_Write(), last_operation() , foperation(), hasInstantData(false), hasExpression(false) , active(false), hasOutputFile(false), hasFieldOut(false), slotUpdateDate(NULL) , processed(false), domAxisIds_("",""), areAllReferenceSolved(false), areAllExpressionBuilt(false) { setVirtualVariableGroup() ; } CField::~CField(void) { // this->grid.reset() ; // this->file.reset() ; this->foperation.reset() ; if (hasExpression) delete expression ; if (slotUpdateDate!=NULL) delete slotUpdateDate ; } //---------------------------------------------------------------- void CField::setVirtualVariableGroup(CVariableGroup* newVVariableGroup) { this->vVariableGroup = newVVariableGroup; } void CField::setVirtualVariableGroup(void) { this->setVirtualVariableGroup(CVariableGroup::create()); } CVariableGroup* CField::getVirtualVariableGroup(void) const { return (this->vVariableGroup); } std::vector CField::getAllVariables(void) const { return (this->vVariableGroup->getAllChildren()); } void CField::solveDescInheritance(bool apply, const CAttributeMap * const parent) { SuperClassAttribute::setAttributes(parent,apply); this->getVirtualVariableGroup()->solveDescInheritance(apply, NULL); } //---------------------------------------------------------------- //---------------------------------------------------------------- bool CField::updateDataServer (const CDate & currDate, const std::deque< CArray* > storedClient) { const CDate opeDate = *last_operation + freq_operation; const CDate writeDate = *last_Write + freq_write; if (opeDate <= currDate) { if (this->data.numElements() != this->grid->storeIndex[0]->numElements()) { this->data.resize(this->grid->storeIndex[0] ->numElements()); } CArray input(data.numElements()) ; this->grid->inputFieldServer(storedClient, input); (*this->foperation)(input); *last_operation = currDate; } if (writeDate < (currDate + freq_operation)) { this->foperation->final(); this->incrementNStep(); *last_Write = writeDate; return (true); } return (false); } bool CField::dispatchEvent(CEventServer& event) { if (SuperClass::dispatchEvent(event)) return true ; else { switch(event.type) { case EVENT_ID_UPDATE_DATA : recvUpdateData(event) ; return true ; break ; case EVENT_ID_ADD_VARIABLE : recvAddVariable(event) ; return true ; break ; case EVENT_ID_ADD_VARIABLE_GROUP : recvAddVariableGroup(event) ; return true ; break ; default : ERROR("bool CField::dispatchEvent(CEventServer& event)",<<"Unknown Event") ; return false ; } } } void CField::sendUpdateData(void) { CContext* context = CContext::getCurrent() ; CContextClient* client=context->client ; CEventClient event(getType(),EVENT_ID_UPDATE_DATA) ; map* >::iterator it ; list > list_msg ; list< CArray* > list_data ; for(it=grid->storeIndex_toSrv.begin();it!=grid->storeIndex_toSrv.end();it++) { int rank=(*it).first ; CArray& index = *(it->second) ; CArray data_tmp(index.numElements()) ; for(int n=0;n(new CMessage)) ; list_data.push_back(new CArray(data_tmp)) ; *list_msg.back()<nbSenders[rank],*list_msg.back()) ; } client->sendEvent(event) ; for(list< CArray* >::iterator it=list_data.begin();it!=list_data.end();it++) delete *it ; } void CField::recvUpdateData(CEventServer& event) { vector ranks ; vector buffers ; list::iterator it ; string fieldId ; for (it=event.subEvents.begin();it!=event.subEvents.end();++it) { int rank=it->rank; CBufferIn* buffer=it->buffer; *buffer>>fieldId ; ranks.push_back(rank) ; buffers.push_back(buffer) ; } get(fieldId)->recvUpdateData(ranks,buffers) ; } void CField::recvUpdateData(vector& ranks, vector& buffers) { if (data_srv.empty()) { for(map* >::iterator it=grid->out_i_fromClient.begin();it!=grid->out_i_fromClient.end();it++) { int rank=it->first ; CArray data_tmp(it->second->numElements()) ; data_srv.insert( pair* >(rank, new CArray(data_tmp) ) ) ; foperation_srv.insert(pair >(rank,boost::shared_ptr(new func::CInstant(*data_srv[rank])))) ; } } CContext* context = CContext::getCurrent() ; const CDate & currDate = context->getCalendar()->getCurrentDate(); const CDate opeDate = *last_operation_srv + freq_operation_srv; const CDate writeDate = *last_Write_srv + freq_write_srv; if (opeDate <= currDate) { for(int n=0;n data_tmp ; *buffers[n]>>data_tmp ; (*foperation_srv[ranks[n]])(data_tmp) ; } *last_operation_srv = currDate; } if (writeDate < (currDate + freq_operation_srv)) { for(int n=0;nfoperation_srv[ranks[n]]->final(); } *last_Write_srv = writeDate; writeField() ; *lastlast_Write_srv=*last_Write_srv; } } void CField::writeField(void) { if (! getRelFile()->allDomainEmpty ) if (! grid->domain->isEmpty() || getRelFile()->type == CFile::type_attr::one_file) { getRelFile()->checkFile(); this->incrementNStep(); getRelFile()->getDataOutput()->writeFieldData(CField::get(this)); } } //---------------------------------------------------------------- void CField::setRelFile(CFile* _file) { this->file = _file; hasOutputFile=true ; } //---------------------------------------------------------------- StdString CField::GetName(void) { return (StdString("field")); } StdString CField::GetDefName(void){ return (CField::GetName()); } ENodeType CField::GetType(void) { return (eField); } //---------------------------------------------------------------- CGrid* CField::getRelGrid(void) const { return (this->grid); } //---------------------------------------------------------------- CFile* CField::getRelFile(void) const { return (this->file); } StdSize CField::getNStep(void) const { return (this->nstep); } void CField::incrementNStep(void) { this->nstep++; } void CField::resetNStep(void) { this->nstep=0; } //---------------------------------------------------------------- /*! \brief Get pointer to direct field to which the current field refers. */ CField* CField::getDirectFieldReference(void) const { if (this->field_ref.isEmpty()) return (this->getBaseFieldReference()); if (! CField::has(this->field_ref.getValue())) ERROR("CField::getDirectFieldReference(void)", << "[ ref_name = " << this->field_ref.getValue() << "]" << " invalid field name !"); return (CField::get(this->field_ref.getValue())); } //---------------------------------------------------------------- CField* CField::getBaseFieldReference(void) const { return (baseRefObject); } //---------------------------------------------------------------- const std::vector& CField::getAllReference(void) const { return (refObject); } //---------------------------------------------------------------- const StdString & CField::getBaseFieldId(void) const { return (this->getBaseFieldReference()->getId()); } //---------------------------------------------------------------- const CDuration & CField::getFreqOperation(void) const { return (this->freq_operation); } //---------------------------------------------------------------- const CDuration & CField::getFreqWrite(void) const { return (this->freq_write); } //---------------------------------------------------------------- boost::shared_ptr CField::getFieldOperation(void) const { return (this->foperation); } //---------------------------------------------------------------- bool CField::hasDirectFieldReference(void) const { return (!this->field_ref.isEmpty()); } bool CField::isActive(void) const { return (!this->refObject.empty()); } //---------------------------------------------------------------- CArray CField::getData(void) const { return(this->data); } //---------------------------------------------------------------- boost::shared_ptr CField::getLastWriteDate(void) const { return(this->last_Write); } //---------------------------------------------------------------- boost::shared_ptr CField::getLastOperationDate(void) const { return(this->last_operation); } //---------------------------------------------------------------- // void CField::processEnabledField(void) // { // if (!processed) // { // processed=true ; // solveRefInheritance(true) ; // solveBaseReference() ; // solveOperation() ; // solveGridReference() ; // // if (hasDirectFieldReference()) baseRefObject->processEnabledField() ; // buildExpression(); // active=true; // } // } void CField::solveAllReferenceEnabledField(bool doSending2Sever) { CContext* context = CContext::getCurrent(); if (!areAllReferenceSolved) { areAllReferenceSolved = true; if (context->hasClient) { solveRefInheritance(true); solveBaseReference(); } solveOperation(); solveGridReference(); } solveGridDomainAxisRef(doSending2Sever); solveCheckMaskIndex(doSending2Sever); } std::map CField::getGridDataSize() { return grid->getConnectedServerDataSize(); } void CField::buildAllExpressionEnabledField() { if (!areAllReferenceSolved) solveAllReferenceEnabledField(true); if (!areAllExpressionBuilt) { areAllExpressionBuilt = true; // solveCheckMaskIndex(true); // solveCheckMaskIndex(); if (hasDirectFieldReference()) baseRefObject->buildAllExpressionEnabledField(); buildExpression(); active=true; } } /*! \brief Searching for all reference of a field If a field refers to (an)other field(s), we will search for all its referenced parents. Moreover, if any father, direct or indirect (e.g: two levels up), has non-empty attributes, all its attributes will be added to the current field \param [in] apply Flag to specify whether current field uses attributes of its father in case the attribute is empty (true) or its attributes are replaced by ones of its father (false) */ void CField::solveRefInheritance(bool apply) { std::set sset; CField* refer_sptr; CField * refer_ptr = this; while (refer_ptr->hasDirectFieldReference()) { refer_sptr = refer_ptr->getDirectFieldReference(); refer_ptr = refer_sptr; if(sset.end() != sset.find(refer_ptr)) { DEBUG (<< "Circular dependency stopped for field object on " << "\"" + refer_ptr->getId() + "\" !"); break; } SuperClassAttribute::setAttributes(refer_ptr, apply); sset.insert(refer_ptr); } } /*! \brief Only on SERVER side. Remove all field_ref from current field On creating a new field on server side, redundant "field_ref" is still kept in the attribute list of the current field. This function removes this from current field */ void CField::removeRefInheritance() { if (this->field_ref.isEmpty()) return; this->clearAttribute("field_ref"); } void CField::solveBaseReference(void) { std::set sset; CField* refer_sptr; CField * refer_ptr = this; if (this->hasDirectFieldReference()) baseRefObject = getDirectFieldReference(); else baseRefObject = CField::get(this); while (refer_ptr->hasDirectFieldReference()) { refer_sptr = refer_ptr->getDirectFieldReference(); refer_ptr = refer_sptr; if(sset.end() != sset.find(refer_ptr)) { DEBUG (<< "Circular dependency stopped for field object on " << "\"" + refer_ptr->getId() + "\" !"); break; } sset.insert(refer_ptr); } if (hasDirectFieldReference()) baseRefObject->addReference(this) ; } //---------------------------------------------------------------- void CField::solveOperation(void) { using namespace func; if (!hasOutputFile && !hasFieldOut) return ; StdString id ; if (hasId()) id=getId(); else if (!name.isEmpty()) id=name ; else if (hasDirectFieldReference()) id=baseRefObject->getId() ; CContext* context = CContext::getCurrent(); if (freq_op.isEmpty()) freq_op=string("1ts") ; if (operation.isEmpty() ) { ERROR("CField::solveOperation(void)", << "[ id = " << id << "]" << "Impossible to define an operation for this field !"); } CDuration freq_offset_ = NoneDu; if (!freq_offset.isEmpty()) { freq_offset_ = CDuration::FromString(freq_offset.getValue()); } else { freq_offset.setValue(NoneDu.toString()); } // if (CXIOSManager::GetStatus() == CXIOSManager::LOC_SERVER) if (context->hasServer) { if (hasOutputFile) { this->freq_operation_srv =CDuration::FromString(this->file->output_freq.getValue()); this->freq_write_srv = CDuration::FromString(this->file->output_freq.getValue()); } this->lastlast_Write_srv = boost::shared_ptr (new CDate(context->getCalendar()->getInitDate())); this->last_Write_srv = boost::shared_ptr (new CDate(context->getCalendar()->getInitDate())); this->last_operation_srv = boost::shared_ptr (new CDate(context->getCalendar()->getInitDate())); // this->foperation_srv = // boost::shared_ptr(new CInstant(this->data_srv)); if (hasOutputFile) { const CDuration toffset = this->freq_operation_srv - freq_offset_ - context->getCalendar()->getTimeStep(); *this->last_operation_srv = *this->last_operation_srv - toffset; } } // if (context->hasClient) // { this->freq_operation = CDuration::FromString(freq_op.getValue()); if (hasOutputFile) this->freq_write = CDuration::FromString(this->file->output_freq.getValue()); if (hasFieldOut) { this->freq_write = CDuration::FromString(this->fieldOut->freq_op.getValue()); } this->last_Write = boost::shared_ptr (new CDate(context->getCalendar()->getInitDate())); this->last_operation = boost::shared_ptr (new CDate(context->getCalendar()->getInitDate())); const CDuration toffset = this->freq_operation - freq_offset_ - context->getCalendar()->getTimeStep(); *this->last_operation = *this->last_operation - toffset; if (operation.get()=="once") isOnceOperation=true ; else isOnceOperation=false; isFirstOperation=true; #define DECLARE_FUNCTOR(MType, mtype) \ if (operation.getValue().compare(#mtype) == 0) \ { \ if (!detect_missing_value.isEmpty() && !default_value.isEmpty() && detect_missing_value==true) \ { \ boost::shared_ptr foperation_(new C##MType(this->data,default_value)); \ this->foperation = foperation_; \ } \ else \ { \ boost::shared_ptr foperation_(new C##MType(this->data)); \ this->foperation = foperation_; \ } \ return; \ } #include "functor_type.conf" ERROR("CField::solveOperation(void)", << "[ operation = " << operation.getValue() << "]" << "The operation is not defined !"); // } } //---------------------------------------------------------------- /* void CField::fromBinary(StdIStream & is) { SuperClass::fromBinary(is); #define CLEAR_ATT(name_)\ SuperClassAttribute::operator[](#name_)->reset() CLEAR_ATT(domain_ref); CLEAR_ATT(axis_ref); #undef CLEAR_ATT } */ //---------------------------------------------------------------- void CField::solveGridReference(void) { CDomain* domain; CAxis* axis; if (!domain_ref.isEmpty()) { if (CDomain::has(domain_ref.getValue())) domain = CDomain::get(domain_ref.getValue()) ; else ERROR("CField::solveGridReference(void)", << "Reference to the domain \'" << domain_ref.getValue() << "\' is wrong") ; } if (!axis_ref.isEmpty()) { if (CAxis::has(axis_ref.getValue())) axis = CAxis::get(axis_ref.getValue()) ; else ERROR("CField::solveGridReference(void)", << "Reference to the axis \'" << axis_ref.getValue() <<"\' is wrong") ; } if (!grid_ref.isEmpty()) { if (CGrid::has(grid_ref.getValue())) this->grid = CGrid::get(grid_ref.getValue()) ; else ERROR("CField::solveGridReference(void)", << "Reference to the grid \'" << grid_ref.getValue() << "\' is wrong"); } if (grid_ref.isEmpty() && domain_ref.isEmpty()) { ERROR("CField::solveGridReference(void)", << "The horizontal domain for this field is not defined"); } CType goodDomain ; CType goodAxis ; if (!grid_ref.isEmpty()) { if (!grid->domain_ref.isEmpty()) goodDomain=grid->domain_ref ; if (!grid->axis_ref.isEmpty()) goodAxis=grid->axis_ref ; } if (!domain_ref.isEmpty()) goodDomain=domain_ref ; if (!axis_ref.isEmpty()) goodAxis=axis_ref ; if (goodDomain.isEmpty()) { ERROR("CField::solveGridReference(void)", << "The horizontal domain for this field is not defined"); } else { if (CDomain::has(goodDomain)) domain = CDomain::get(goodDomain) ; else ERROR("CField::solveGridReference(void)",<< "Reference to the domain \'"<domain_ref.isEmpty() && goodDomain.get() == grid->domain_ref.get()) if (goodAxis.isEmpty()) nothingToDo=true ; else if (!grid->axis_ref.isEmpty()) if (grid->axis_ref.get()==goodAxis.get()) nothingToDo=true ; } if (!nothingToDo) { if (!goodAxis.isEmpty()) { this->grid = CGrid::createGrid(domain, axis) ; this->grid_ref.setValue(this->grid->getId()); } else { this->grid = CGrid::createGrid(domain) ; this->grid_ref.setValue(this->grid->getId()); } } // grid->solveReference() ; // grid->solveDomainAxisRef(); // grid->checkMaskIndex(); } void CField::solveGridDomainAxisRef(bool checkAtt) { grid->solveDomainAxisRef(checkAtt); } void CField::solveCheckMaskIndex(bool doSendingIndex) { grid->checkMaskIndex(doSendingIndex); } ///------------------------------------------------------------------- template <> void CGroupTemplate::solveRefInheritance(void) { if (this->group_ref.isEmpty()) return; StdString gref = this->group_ref.getValue(); if (!CFieldGroup::has(gref)) ERROR("CGroupTemplate::solveRefInheritance(void)", << "[ gref = " << gref << "]" << " invalid group name !"); CFieldGroup* group = CFieldGroup::get(gref); CFieldGroup* owner = CFieldGroup::get(boost::polymorphic_downcast(this)); std::vector allChildren = group->getAllChildren(); std::vector::iterator it = allChildren.begin(), end = allChildren.end(); for (; it != end; it++) { CField* child = *it; if (child->hasId()) owner->createChild()->field_ref.setValue(child->getId()) ; } } void CField::scaleFactorAddOffset(double scaleFactor, double addOffset) { map* >::iterator it; for(it=data_srv.begin();it!=data_srv.end();it++) *it->second = (*it->second -addOffset) * 1./scaleFactor ; } void CField::outputField(CArray& fieldOut) { map* >::iterator it; for(it=data_srv.begin();it!=data_srv.end();it++) grid->outputField(it->first,*it->second, fieldOut) ; } void CField::outputField(CArray& fieldOut) { map* >::iterator it; for(it=data_srv.begin();it!=data_srv.end();it++) { grid->outputField(it->first,*it->second, fieldOut) ; } } ///------------------------------------------------------------------- void CField::parse(xml::CXMLNode & node) { SuperClass::parse(node); if (! node.getContent(this->content)) { if (node.goToChildElement()) { do { if (node.getElementName()=="variable" || node.getElementName()=="variable_group") this->getVirtualVariableGroup()->parseChild(node); } while (node.goToNextElement()) ; node.goToParentElement(); } } } CArray* CField::getInstantData(void) { if (!hasInstantData) { instantData.resize(grid->storeIndex_client.numElements()) ; hasInstantData=true ; } return &instantData ; } void CField::addReference(CField* field) { refObject.push_back(field) ; } void CField::addDependency(CField* field, int slotId) { fieldDependency.push_back(pair(field,slotId)) ; } void CField::buildExpression(void) { if (content.size() > 0) { CSimpleNodeExpr* simpleExpr=parseExpr(content+'\0') ; expression=CFieldNode::newNode(simpleExpr) ; delete simpleExpr ; set instantFieldIds ; map associatedInstantFieldIds ; expression->getInstantFieldIds(instantFieldIds) ; for (set::iterator it=instantFieldIds.begin() ; it!=instantFieldIds.end();++it) { if (*it!="this") { if (CField::has(*it)) { CField* field=CField::get(*it) ; // field->processEnabledField() ; field->buildAllExpressionEnabledField(); associatedInstantFieldIds[*it]=field ; } else ERROR("void CField::buildExpression(void)",<<" Field "<<*it<<" does not exist") ; } } set averageFieldIds ; map associatedAverageFieldIds ; expression->getAverageFieldIds(averageFieldIds) ; for (set::iterator it=averageFieldIds.begin() ; it!=averageFieldIds.end();++it) { if (CField::has(*it)) { CFieldGroup* root=CFieldGroup::get("field_definition") ; CField* averageField=root->createChild() ; CField* instantField=root->createChild() ; averageField->field_ref=*it ; averageField->hasFieldOut=true ; averageField->fieldOut=instantField ; instantField->freq_op=freq_op ; // averageField-> processEnabledField() ; averageField->buildAllExpressionEnabledField(); instantField->SuperClassAttribute::setAttributes(averageField, true); instantField->field_ref.reset() ; instantField->operation.reset() ; // instantField-> processEnabledField() ; instantField->buildAllExpressionEnabledField(); associatedAverageFieldIds[*it]=instantField ; } else ERROR("void CField::buildExpression(void)",<<" Field "<<*it<<" does not exist") ; } expression->reduce(this,associatedInstantFieldIds,associatedAverageFieldIds) ; slots.resize(instantFieldIds.size()+averageFieldIds.size()) ; resetSlots() ; int slotId=0 ; set fields ; expression->getFields(fields) ; for (set::iterator it=fields.begin() ; it!=fields.end();++it,++slotId) (*it)->addDependency(this,slotId) ; hasExpression=true; } } void CField::resetSlots(void) { for(vector::iterator it=slots.begin();it!=slots.end();++it) *it=false ; } bool CField::slotsFull(void) { bool ret=true ; for(vector::iterator it=slots.begin();it!=slots.end();++it) ret &= *it; return ret ; } void CField::setSlot(int slotId) { CContext* context = CContext::getCurrent() ; const CDate & currDate = context->getCalendar()->getCurrentDate(); if (slotUpdateDate==NULL || currDate!=*slotUpdateDate) { resetSlots() ; if (slotUpdateDate==NULL) slotUpdateDate=new CDate(currDate) ; else *slotUpdateDate=currDate ; } slots[slotId]=true ; if (slotsFull()) { CArray expr(expression->compute()) ; if (hasInstantData) { instantData=expr ; for(list< pair >::iterator it=fieldDependency.begin(); it!=fieldDependency.end(); ++it) if (it->first!=this) it->first->setSlot(it->second) ; } if (hasOutputFile) updateDataFromExpression(expr) ; } } /*! This function retrieves Id of corresponding domain_ref and axis_ref (if any) of a field. In some cases, only domain exists but axis doesn't \return pair of Domain and Axis id */ const std::pair& CField::getDomainAxisIds() { CGrid* cgPtr = getRelGrid(); if (NULL != cgPtr) { if (NULL != cgPtr->getRelDomain()) domAxisIds_.first = cgPtr->getRelDomain()->getId(); if (NULL != cgPtr->getRelAxis()) domAxisIds_.second = cgPtr->getRelAxis()->getId(); } return (domAxisIds_); } CVariable* CField::addVariable(const string& id) { return vVariableGroup->createChild(id) ; } CVariableGroup* CField::addVariableGroup(const string& id) { return vVariableGroup->createChildGroup(id) ; } void CField::sendAddAllVariables() { if (!getAllVariables().empty()) { // Firstly, it's necessary to add virtual variable group sendAddVariableGroup(getVirtualVariableGroup()->getId()); // Okie, now we can add to this variable group std::vector allVar = getAllVariables(); std::vector::const_iterator it = allVar.begin(); std::vector::const_iterator itE = allVar.end(); for (; it != itE; ++it) { std::cout << "Variable Fields " << (*it)->getId() << std::endl; this->sendAddVariable((*it)->getId()); (*it)->sendAllAttributesToServer(); (*it)->sendValue(); } } } void CField::sendAddVariable(const string& id) { CContext* context=CContext::getCurrent() ; if (! context->hasServer ) { CContextClient* client=context->client ; CEventClient event(this->getType(),EVENT_ID_ADD_VARIABLE) ; if (client->isServerLeader()) { CMessage msg ; msg<getId() ; msg<getServerLeader(),1,msg) ; client->sendEvent(event) ; } else client->sendEvent(event) ; } } void CField::sendAddVariableGroup(const string& id) { CContext* context=CContext::getCurrent() ; if (! context->hasServer ) { CContextClient* client=context->client ; CEventClient event(this->getType(),EVENT_ID_ADD_VARIABLE_GROUP) ; if (client->isServerLeader()) { CMessage msg ; msg<getId() ; msg<getServerLeader(),1,msg) ; client->sendEvent(event) ; } else client->sendEvent(event) ; } } void CField::recvAddVariable(CEventServer& event) { CBufferIn* buffer=event.subEvents.begin()->buffer; string id; *buffer>>id ; get(id)->recvAddVariable(*buffer) ; } void CField::recvAddVariable(CBufferIn& buffer) { string id ; buffer>>id ; addVariable(id) ; } void CField::recvAddVariableGroup(CEventServer& event) { CBufferIn* buffer=event.subEvents.begin()->buffer; string id; *buffer>>id ; get(id)->recvAddVariableGroup(*buffer) ; } void CField::recvAddVariableGroup(CBufferIn& buffer) { string id ; buffer>>id ; addVariableGroup(id) ; } } // namespace xios