source: XIOS/dev/dev_trunk_omp/src/node/context.cpp @ 1628

Last change on this file since 1628 was 1628, checked in by yushan, 5 years ago

bug fix (Nb of files less than Nb of servers)

  • Property copyright set to
    Software name : XIOS (Xml I/O Server)
    http://forge.ipsl.jussieu.fr/ioserver
    Creation date : January 2009
    Licence : CeCCIL version2
    see license file in root directory : Licence_CeCILL_V2-en.txt
    or http://www.cecill.info/licences/Licence_CeCILL_V2-en.html
    Holder : CEA/LSCE (Laboratoire des Sciences du CLimat et de l'Environnement)
    CNRS/IPSL (Institut Pierre Simon Laplace)
    Project Manager : Yann Meurdesoif
    yann.meurdesoif@cea.fr
File size: 71.0 KB
RevLine 
[219]1#include "context.hpp"
[352]2#include "attribute_template.hpp"
3#include "object_template.hpp"
4#include "group_template.hpp"
[219]5
6#include "calendar_type.hpp"
[278]7#include "duration.hpp"
[219]8
[300]9#include "context_client.hpp"
10#include "context_server.hpp"
11#include "nc4_data_output.hpp"
[346]12#include "node_type.hpp"
[352]13#include "message.hpp"
14#include "type.hpp"
[591]15#include "xios_spl.hpp"
[1158]16#include "timer.hpp"
17#include "memtrack.hpp"
[1215]18#include <limits>
[1349]19#include <fstream>
[992]20#include "server.hpp"
[1349]21#include "distribute_file_server2.hpp"
[697]22
[1601]23using namespace ep_lib;
24
[335]25namespace xios {
[509]26
[1601]27  std::shared_ptr<CContextGroup> * CContext::root_ptr = 0;
[509]28
[219]29   /// ////////////////////// Définitions ////////////////////// ///
30
31   CContext::CContext(void)
32      : CObjectTemplate<CContext>(), CContextAttributes()
[983]33      , calendar(), hasClient(false), hasServer(false)
[1139]34      , isPostProcessed(false), finalized(false)
[1009]35      , idServer_(), client(0), server(0)
[1130]36      , allProcessed(false), countChildCtx_(0)
[219]37   { /* Ne rien faire de plus */ }
38
39   CContext::CContext(const StdString & id)
40      : CObjectTemplate<CContext>(id), CContextAttributes()
[983]41      , calendar(), hasClient(false), hasServer(false)
[1139]42      , isPostProcessed(false), finalized(false)
[1009]43      , idServer_(), client(0), server(0)
[1130]44      , allProcessed(false), countChildCtx_(0)
[219]45   { /* Ne rien faire de plus */ }
46
47   CContext::~CContext(void)
[509]48   {
[597]49     delete client;
50     delete server;
[1071]51     for (std::vector<CContextClient*>::iterator it = clientPrimServer.begin(); it != clientPrimServer.end(); it++)  delete *it;
52     for (std::vector<CContextServer*>::iterator it = serverPrimServer.begin(); it != serverPrimServer.end(); it++)  delete *it;
[1139]53
[300]54   }
[219]55
56   //----------------------------------------------------------------
[509]57   //! Get name of context
[219]58   StdString CContext::GetName(void)   { return (StdString("context")); }
59   StdString CContext::GetDefName(void){ return (CContext::GetName()); }
60   ENodeType CContext::GetType(void)   { return (eContext); }
61
62   //----------------------------------------------------------------
[640]63
[509]64   /*!
65   \brief Get context group (context root)
66   \return Context root
67   */
[347]68   CContextGroup* CContext::getRoot(void)
[509]69   {
[1601]70      if(root_ptr == 0) root_ptr = new std::shared_ptr<CContextGroup>(new CContextGroup(xml::CXMLNode::GetRootName()));
71      return root_ptr->get();
[219]72   }
73
[640]74   //----------------------------------------------------------------
[509]75
76   /*!
77   \brief Get calendar of a context
78   \return Calendar
79   */
[1542]80   std::shared_ptr<CCalendar> CContext::getCalendar(void) const
[219]81   {
82      return (this->calendar);
83   }
[509]84
[219]85   //----------------------------------------------------------------
[640]86
[509]87   /*!
88   \brief Set a context with a calendar
89   \param[in] newCalendar new calendar
90   */
[1542]91   void CContext::setCalendar(std::shared_ptr<CCalendar> newCalendar)
[219]92   {
93      this->calendar = newCalendar;
94   }
[509]95
[219]96   //----------------------------------------------------------------
[509]97   /*!
98   \brief Parse xml file and write information into context object
99   \param [in] node xmld node corresponding in xml file
100   */
[219]101   void CContext::parse(xml::CXMLNode & node)
102   {
103      CContext::SuperClass::parse(node);
104
105      // PARSING POUR GESTION DES ENFANTS
[278]106      xml::THashAttributes attributes = node.getAttributes();
[219]107
[278]108      if (attributes.end() != attributes.find("src"))
109      {
110         StdIFStream ifs ( attributes["src"].c_str() , StdIFStream::in );
[462]111         if ( (ifs.rdstate() & std::ifstream::failbit ) != 0 )
112            ERROR("void CContext::parse(xml::CXMLNode & node)",
113                  <<endl<< "Can not open <"<<attributes["src"].c_str()<<"> file" );
[278]114         if (!ifs.good())
115            ERROR("CContext::parse(xml::CXMLNode & node)",
116                  << "[ filename = " << attributes["src"] << " ] Bad xml stream !");
[462]117         xml::CXMLParser::ParseInclude(ifs, attributes["src"], *this);
[278]118      }
119
[219]120      if (node.getElementName().compare(CContext::GetName()))
[421]121         DEBUG("Le noeud is wrong defined but will be considered as a context !");
[219]122
123      if (!(node.goToChildElement()))
124      {
125         DEBUG("Le context ne contient pas d'enfant !");
126      }
127      else
128      {
129         do { // Parcours des contextes pour traitement.
130
131            StdString name = node.getElementName();
132            attributes.clear();
133            attributes = node.getAttributes();
134
135            if (attributes.end() != attributes.find("id"))
[509]136            {
137              DEBUG(<< "Definition node has an id,"
138                    << "it will not be taking account !");
139            }
[219]140
141#define DECLARE_NODE(Name_, name_)    \
142   if (name.compare(C##Name_##Definition::GetDefName()) == 0) \
[549]143   { C##Name_##Definition::create(C##Name_##Definition::GetDefName()) -> parse(node); continue; }
[219]144#define DECLARE_NODE_PAR(Name_, name_)
145#include "node_type.conf"
[286]146
[421]147            DEBUG(<< "The element \'"     << name
148                  << "\' in the context \'" << CContext::getCurrent()->getId()
149                  << "\' is not a definition !");
[219]150
151         } while (node.goToNextElement());
152
153         node.goToParentElement(); // Retour au parent
154      }
155   }
156
157   //----------------------------------------------------------------
[509]158   //! Show tree structure of context
[219]159   void CContext::ShowTree(StdOStream & out)
160   {
[549]161      StdString currentContextId = CContext::getCurrent() -> getId();
[347]162      std::vector<CContext*> def_vector =
[346]163         CContext::getRoot()->getChildList();
[347]164      std::vector<CContext*>::iterator
[219]165         it = def_vector.begin(), end = def_vector.end();
166
167      out << "<? xml version=\"1.0\" ?>" << std::endl;
168      out << "<"  << xml::CXMLNode::GetRootName() << " >" << std::endl;
[509]169
[219]170      for (; it != end; it++)
171      {
[509]172         CContext* context = *it;
173         CContext::setCurrent(context->getId());
[219]174         out << *context << std::endl;
175      }
[509]176
[219]177      out << "</" << xml::CXMLNode::GetRootName() << " >" << std::endl;
[509]178      CContext::setCurrent(currentContextId);
[219]179   }
[346]180
[509]181
[219]182   //----------------------------------------------------------------
183
[509]184   //! Convert context object into string (to print)
[219]185   StdString CContext::toString(void) const
186   {
187      StdOStringStream oss;
188      oss << "<" << CContext::GetName()
189          << " id=\"" << this->getId() << "\" "
190          << SuperClassAttribute::toString() << ">" << std::endl;
191      if (!this->hasChild())
192      {
193         //oss << "<!-- No definition -->" << std::endl; // fait planter l'incrémentation
194      }
195      else
196      {
197
198#define DECLARE_NODE(Name_, name_)    \
[346]199   if (C##Name_##Definition::has(C##Name_##Definition::GetDefName())) \
200   oss << * C##Name_##Definition::get(C##Name_##Definition::GetDefName()) << std::endl;
[219]201#define DECLARE_NODE_PAR(Name_, name_)
202#include "node_type.conf"
203
204      }
205
206      oss << "</" << CContext::GetName() << " >";
207
208      return (oss.str());
209   }
210
211   //----------------------------------------------------------------
212
[509]213   /*!
214   \brief Find all inheritace among objects in a context.
215   \param [in] apply (true) write attributes of parent into ones of child if they are empty
216                     (false) write attributes of parent into a new container of child
217   \param [in] parent unused
218   */
[445]219   void CContext::solveDescInheritance(bool apply, const CAttributeMap * const UNUSED(parent))
[219]220   {
221#define DECLARE_NODE(Name_, name_)    \
[354]222   if (C##Name_##Definition::has(C##Name_##Definition::GetDefName())) \
[445]223     C##Name_##Definition::get(C##Name_##Definition::GetDefName())->solveDescInheritance(apply);
[219]224#define DECLARE_NODE_PAR(Name_, name_)
225#include "node_type.conf"
226   }
227
228   //----------------------------------------------------------------
229
[509]230   //! Verify if all root definition in the context have child.
[219]231   bool CContext::hasChild(void) const
232   {
233      return (
234#define DECLARE_NODE(Name_, name_)    \
[346]235   C##Name_##Definition::has(C##Name_##Definition::GetDefName())   ||
[219]236#define DECLARE_NODE_PAR(Name_, name_)
237#include "node_type.conf"
238      false);
239}
240
241   //----------------------------------------------------------------
242
243   void CContext::CleanTree(void)
244   {
[549]245#define DECLARE_NODE(Name_, name_) C##Name_##Definition::ClearAllAttributes();
[219]246#define DECLARE_NODE_PAR(Name_, name_)
247#include "node_type.conf"
248   }
249   ///---------------------------------------------------------------
[509]250
251   //! Initialize client side
[1601]252   void CContext::initClient(ep_lib::MPI_Comm intraComm, ep_lib::MPI_Comm interComm, CContext* cxtServer /*= 0*/)
[300]253   {
[983]254
255     hasClient = true;
[1601]256     ep_lib::MPI_Comm intraCommServer, interCommServer;
[1316]257     
[1054]258
[1601]259     if (CServer::serverLevel != 1) // initClient is called by client
[983]260     {
261       client = new CContextClient(this, intraComm, interComm, cxtServer);
[1054]262       if (cxtServer) // Attached mode
263       {
264         intraCommServer = intraComm;
265         interCommServer = interComm;
266       }
267       else
268       {
[1601]269         ep_lib::MPI_Comm_dup(intraComm, &intraCommServer);
[1071]270         comms.push_back(intraCommServer);
[1601]271         ep_lib::MPI_Comm_dup(interComm, &interCommServer);
[1071]272         comms.push_back(interCommServer);
[1054]273       }
[1316]274/* for registry take the id of client context */
275/* for servers, supress the _server_ from id  */
276       string contextRegistryId=getId() ;
277       size_t pos=contextRegistryId.find("_server_") ;
278       if (pos!=std::string::npos)  contextRegistryId=contextRegistryId.substr(0,pos) ;
279
[1071]280       registryIn=new CRegistry(intraComm);
[1316]281       registryIn->setPath(contextRegistryId) ;
[1071]282       if (client->clientRank==0) registryIn->fromFile("xios_registry.bin") ;
283       registryIn->bcastRegistry() ;
284       registryOut=new CRegistry(intraComm) ;
[1316]285       
286       registryOut->setPath(contextRegistryId) ;
[1071]287
288       server = new CContextServer(this, intraCommServer, interCommServer);
[983]289     }
[1601]290
291     else // initClient is called by primary server
[983]292     {
[1009]293       clientPrimServer.push_back(new CContextClient(this, intraComm, interComm));
[1601]294       ep_lib::MPI_Comm_dup(intraComm, &intraCommServer);
[1071]295       comms.push_back(intraCommServer);
[1601]296       ep_lib::MPI_Comm_dup(interComm, &interCommServer);
[1071]297       comms.push_back(interCommServer);
298       serverPrimServer.push_back(new CContextServer(this, intraCommServer, interCommServer));
[983]299     }
[509]300   }
[219]301
[1330]302   /*!
303    Sets client buffers.
304    \param [in] contextClient
305    \param [in] bufferForWriting True if buffers are used for sending data for writing
306    This flag is only true for client and server-1 for communication with server-2
307  */
308   void CContext::setClientServerBuffer(CContextClient* contextClient, bool bufferForWriting)
[509]309   {
[1201]310      // Estimated minimum event size for small events (10 is an arbitrary constant just for safety)
[1372]311     const size_t minEventSize = CEventClient::headerSize + getIdServer().size() + 10 * sizeof(int);
[1201]312
313      // Ensure there is at least some room for 20 of such events in the buffers
314      size_t minBufferSize = std::max(CXios::minBufferSize, 20 * minEventSize);
315
[583]316#define DECLARE_NODE(Name_, name_)    \
[731]317     if (minBufferSize < sizeof(C##Name_##Definition)) minBufferSize = sizeof(C##Name_##Definition);
[583]318#define DECLARE_NODE_PAR(Name_, name_)
319#include "node_type.conf"
[719]320#undef DECLARE_NODE
321#undef DECLARE_NODE_PAR
322
[1201]323     // Compute the buffer sizes needed to send the attributes and data corresponding to fields
[917]324     std::map<int, StdSize> maxEventSize;
[1330]325     std::map<int, StdSize> bufferSize = getAttributesBufferSize(maxEventSize, contextClient, bufferForWriting);
326     std::map<int, StdSize> dataBufferSize = getDataBufferSize(maxEventSize, contextClient, bufferForWriting);
[729]327
[909]328     std::map<int, StdSize>::iterator it, ite = dataBufferSize.end();
[731]329     for (it = dataBufferSize.begin(); it != ite; ++it)
330       if (it->second > bufferSize[it->first]) bufferSize[it->first] = it->second;
331
[1227]332     // Apply the buffer size factor, check that we are above the minimum buffer size and below the maximum size
[909]333     ite = bufferSize.end();
334     for (it = bufferSize.begin(); it != ite; ++it)
335     {
336       it->second *= CXios::bufferSizeFactor;
337       if (it->second < minBufferSize) it->second = minBufferSize;
[1227]338       if (it->second > CXios::maxBufferSize) it->second = CXios::maxBufferSize;
[909]339     }
340
[1201]341     // Leaders will have to send some control events so ensure there is some room for those in the buffers
[1184]342     if (contextClient->isServerLeader())
[598]343     {
[1184]344       const std::list<int>& ranks = contextClient->getRanksServerLeader();
[729]345       for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
[1201]346       {
347         if (!bufferSize.count(*itRank))
348         {
349           bufferSize[*itRank] = minBufferSize;
350           maxEventSize[*itRank] = minEventSize;
351         }
352       }
[598]353     }
[1184]354     contextClient->setBufferSize(bufferSize, maxEventSize);
[584]355
[509]356   }
357
358   //! Verify whether a context is initialized
[461]359   bool CContext::isInitialized(void)
360   {
[549]361     return hasClient;
[461]362   }
[509]363
[1601]364   void CContext::initServer(ep_lib::MPI_Comm intraComm, ep_lib::MPI_Comm interComm, CContext* cxtClient /*= 0*/)
[300]365   {
[549]366     hasServer=true;
367     server = new CContextServer(this,intraComm,interComm);
[697]368
[1316]369/* for registry take the id of client context */
370/* for servers, supress the _server_ from id  */
371     string contextRegistryId=getId() ;
372     size_t pos=contextRegistryId.find("_server_") ;
373     if (pos!=std::string::npos)  contextRegistryId=contextRegistryId.substr(0,pos) ;
374       
[1071]375     registryIn=new CRegistry(intraComm);
[1316]376     registryIn->setPath(contextRegistryId) ;
[1071]377     if (server->intraCommRank==0) registryIn->fromFile("xios_registry.bin") ;
378     registryIn->bcastRegistry() ;
379     registryOut=new CRegistry(intraComm) ;
[1316]380     registryOut->setPath(contextRegistryId) ;
[775]381
[1601]382     ep_lib::MPI_Comm intraCommClient, interCommClient;
[597]383     if (cxtClient) // Attached mode
384     {
385       intraCommClient = intraComm;
386       interCommClient = interComm;
387     }
388     else
389     {
[1601]390       ep_lib::MPI_Comm_dup(intraComm, &intraCommClient);
[1071]391       comms.push_back(intraCommClient);
[1601]392       ep_lib::MPI_Comm_dup(interComm, &interCommClient);
[1071]393       comms.push_back(interCommClient);
[597]394     }
[1158]395     client = new CContextClient(this,intraCommClient,interCommClient, cxtClient);
[509]396   }
[300]397
[597]398   //! Try to send the buffers and receive possible answers
[1378]399  bool CContext::checkBuffersAndListen(bool enableEventsProcessing /*= true*/)
[1130]400  {
401    bool clientReady, serverFinished;
[1054]402
[1130]403    // Only classical servers are non-blocking
404    if (CServer::serverLevel == 0)
405    {
406      client->checkBuffers();
407      bool hasTmpBufferedEvent = client->hasTemporarilyBufferedEvent();
408      if (hasTmpBufferedEvent)
409        hasTmpBufferedEvent = !client->sendTemporarilyBufferedEvent();
410      // Don't process events if there is a temporarily buffered event
[1378]411      return server->eventLoop(!hasTmpBufferedEvent || !enableEventsProcessing);
[1130]412    }
413    else if (CServer::serverLevel == 1)
414    {
[1139]415      if (!finalized)
416        client->checkBuffers();
417      bool serverFinished = true;
418      if (!finalized)
[1380]419        serverFinished = server->eventLoop(enableEventsProcessing);
[1130]420      bool serverPrimFinished = true;
421      for (int i = 0; i < clientPrimServer.size(); ++i)
422      {
[1139]423        if (!finalized)
424          clientPrimServer[i]->checkBuffers();
425        if (!finalized)
[1378]426          serverPrimFinished *= serverPrimServer[i]->eventLoop(enableEventsProcessing);
[1130]427      }
428      return ( serverFinished && serverPrimFinished);
429    }
[1054]430
[1130]431    else if (CServer::serverLevel == 2)
432    {
433      client->checkBuffers();
[1378]434      return server->eventLoop(enableEventsProcessing);
[1130]435    }
436  }
[1054]437
[509]438   //! Terminate a context
[300]439   void CContext::finalize(void)
440   {
[1418]441      if (hasClient && !hasServer) // For now we only use server level 1 to read data
442      {
443        doPreTimestepOperationsForEnabledReadModeFiles();
444      }
[1130]445     // Send registry upon calling the function the first time
446     if (countChildCtx_ == 0)
447       if (hasClient) sendRegistry() ;
448
449     // Client:
450     // (1) blocking send context finalize to its server
451     // (2) blocking receive context finalize from its server
[1194]452     // (3) some memory deallocations
[1130]453     if (CXios::isClient)
[1009]454     {
[1130]455       // Make sure that client (model) enters the loop only once
456       if (countChildCtx_ < 1)
457       {
458         ++countChildCtx_;
[983]459
[1130]460         client->finalize();
461         while (client->havePendingRequests())
462            client->checkBuffers();
[1054]463
[1130]464         while (!server->hasFinished())
465           server->eventLoop();
[1139]466
[1194]467         if (hasServer) // Mode attache
468         {
469           closeAllFile();
470           registryOut->hierarchicalGatherRegistry() ;
471           if (server->intraCommRank==0) CXios::globalRegistry->mergeRegistry(*registryOut) ;
472         }
[1139]473
[1194]474         //! Deallocate client buffers
475         client->releaseBuffers();
476
477         //! Free internally allocated communicators
[1601]478         for (std::list<ep_lib::MPI_Comm>::iterator it = comms.begin(); it != comms.end(); ++it)
479           ep_lib::MPI_Comm_free(&(*it));
[1194]480         comms.clear();
481
[1601]482         #pragma omp critical (_output)
[1194]483         info(20)<<"CContext: Context <"<<getId()<<"> is finalized."<<endl;
[1130]484       }
485     }
486     else if (CXios::isServer)
487     {
[1194]488       // First context finalize message received from a model
489       // Send context finalize to its child contexts (if any)
[1130]490       if (countChildCtx_ == 0)
[1009]491         for (int i = 0; i < clientPrimServer.size(); ++i)
492           clientPrimServer[i]->finalize();
[983]493
[1139]494       // (Last) context finalized message received
[1130]495       if (countChildCtx_ == clientPrimServer.size())
[1194]496       {
497         // Blocking send of context finalize message to its client (e.g. primary server or model)
[1601]498         #pragma omp critical (_output)
[1378]499         info(100)<<"DEBUG: context "<<getId()<<" Send client finalize<<"<<endl ;
[1130]500         client->finalize();
[1194]501         bool bufferReleased;
502         do
503         {
504           client->checkBuffers();
505           bufferReleased = !client->havePendingRequests();
506         } while (!bufferReleased);
507         finalized = true;
[983]508
[1232]509         closeAllFile(); // Just move to here to make sure that server-level 1 can close files
[1194]510         if (hasServer && !hasClient)
[1232]511         {           
[1194]512           registryOut->hierarchicalGatherRegistry() ;
513           if (server->intraCommRank==0) CXios::globalRegistry->mergeRegistry(*registryOut) ;
514         }
[1077]515
[1194]516         //! Deallocate client buffers
517         client->releaseBuffers();
518         for (int i = 0; i < clientPrimServer.size(); ++i)
519           clientPrimServer[i]->releaseBuffers();
[1139]520
[1194]521         //! Free internally allocated communicators
[1601]522         for (std::list<ep_lib::MPI_Comm>::iterator it = comms.begin(); it != comms.end(); ++it)
523           ep_lib::MPI_Comm_free(&(*it));
[1194]524         comms.clear();
525
[1601]526         #pragma omp critical (_output)
[1194]527         info(20)<<"CContext: Context <"<<getId()<<"> is finalized."<<endl;
[1139]528       }
529
[1194]530       ++countChildCtx_;
[1130]531     }
532   }
533
[1071]534   //! Free internally allocated communicators
535   void CContext::freeComms(void)
536   {
[1601]537     for (std::list<ep_lib::MPI_Comm>::iterator it = comms.begin(); it != comms.end(); ++it)
538       ep_lib::MPI_Comm_free(&(*it));
[1071]539     comms.clear();
540   }
[509]541
[1130]542   //! Deallocate buffers allocated by clientContexts
543   void CContext::releaseClientBuffers(void)
544   {
545     client->releaseBuffers();
546     for (int i = 0; i < clientPrimServer.size(); ++i)
547       clientPrimServer[i]->releaseBuffers();
548   }
549
[1025]550   void CContext::postProcessingGlobalAttributes()
[300]551   {
[1144]552     if (allProcessed) return; 
[1025]553     
[1144]554     // After xml is parsed, there are some more works with post processing
555     postProcessing();
[983]556
[1144]557     // Check grid and calculate its distribution
[1232]558     checkGridEnabledFields();
559 
[1208]560     // Distribute files between secondary servers according to the data size
561     distributeFiles();
562
[1330]563     setClientServerBuffer(client, (hasClient && !hasServer));
[1255]564     for (int i = 0; i < clientPrimServer.size(); ++i)
[1330]565         setClientServerBuffer(clientPrimServer[i], true);
[300]566
[983]567     if (hasClient)
[510]568     {
[509]569      // Send all attributes of current context to server
570      this->sendAllAttributesToServer();
[459]571
[549]572      // Send all attributes of current calendar
573      CCalendarWrapper::get(CCalendarWrapper::GetDefName())->sendAllAttributesToServer();
574
[509]575      // We have enough information to send to server
[1021]576      // First of all, send all enabled files
[1232]577      sendEnabledFiles(this->enabledWriteModeFiles);
578      // We only use server-level 1 (for now) to read data
579      if (!hasServer)
580        sendEnabledFiles(this->enabledReadModeFiles);
[509]581
[1232]582      // Then, send all enabled fields     
583      sendEnabledFieldsInFiles(this->enabledWriteModeFiles);
584      if (!hasServer)
585        sendEnabledFieldsInFiles(this->enabledReadModeFiles);
[1021]586
[1239]587      // Then, check whether we have domain_ref, axis_ref or scalar_ref attached to the enabled fields
588      // If any, so send them to server
[1232]589       sendRefDomainsAxisScalars(this->enabledWriteModeFiles);
590      if (!hasServer)
591        sendRefDomainsAxisScalars(this->enabledReadModeFiles);       
[1021]592
[1239]593       // Check whether enabled fields have grid_ref, if any, send this info to server
[1237]594      sendRefGrid(this->enabledFiles);
595      // This code may be useful in the future when we want to seperate completely read and write
596      // sendRefGrid(this->enabledWriteModeFiles);
597      // if (!hasServer)
598      //   sendRefGrid(this->enabledReadModeFiles);
[1239]599     
600      // A grid of enabled fields composed of several components which must be checked then their
601      // checked attributes should be sent to server
602      sendGridComponentEnabledFieldsInFiles(this->enabledFiles); // This code can be seperated in two (one for reading, another for writing)
[1021]603
[983]604       // We have a xml tree on the server side and now, it should be also processed
[1239]605      sendPostProcessing();
[1232]606       
[1239]607      // Finally, we send information of grid itself to server
608      sendGridEnabledFieldsInFiles(this->enabledWriteModeFiles);       
609      if (!hasServer)
[1232]610        sendGridEnabledFieldsInFiles(this->enabledReadModeFiles);       
[983]611     }
[1025]612     allProcessed = true;
613   }
[983]614
[1025]615   void CContext::sendPostProcessingGlobalAttributes()
616   {
[1027]617      // Use correct context client to send message
[1030]618     // int nbSrvPools = (hasServer) ? clientPrimServer.size() : 1;
619    int nbSrvPools = (this->hasServer) ? (this->hasClient ? this->clientPrimServer.size() : 0) : 1;
[1027]620     for (int i = 0; i < nbSrvPools; ++i)
621     {
622       CContextClient* contextClientTmp = (0 != clientPrimServer.size()) ? clientPrimServer[i] : client;
623       CEventClient event(getType(),EVENT_ID_POST_PROCESS_GLOBAL_ATTRIBUTES);
[987]624
[1027]625       if (contextClientTmp->isServerLeader())
626       {
627         CMessage msg;
[1099]628         if (hasServer)
629           msg<<this->getIdServer(i);
630         else
631           msg<<this->getIdServer();
[1027]632         const std::list<int>& ranks = contextClientTmp->getRanksServerLeader();
633         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
634           event.push(*itRank,1,msg);
635         contextClientTmp->sendEvent(event);
636       }
637       else contextClientTmp->sendEvent(event);
[1025]638     }
639   }
640
641   void CContext::recvPostProcessingGlobalAttributes(CEventServer& event)
642   {
643      CBufferIn* buffer=event.subEvents.begin()->buffer;
644      string id;
645      *buffer>>id;
[1099]646      get(id)->recvPostProcessingGlobalAttributes(*buffer);
[1025]647   }
648
649   void CContext::recvPostProcessingGlobalAttributes(CBufferIn& buffer)
[1144]650   {     
[1025]651      postProcessingGlobalAttributes();
652   }
653
654   /*!
655   \brief Close all the context defintion and do processing data
656      After everything is well defined on client side, they will be processed and sent to server
657   From the version 2.0, sever and client work no more on the same database. Moreover, client(s) will send
658   all necessary information to server, from which each server can build its own database.
659   Because the role of server is to write out field data on a specific netcdf file,
660   the only information that it needs is the enabled files
661   and the active fields (fields will be written onto active files)
662   */
663   void CContext::closeDefinition(void)
664   {
[1158]665    CTimer::get("Context : close definition").resume() ;
[1025]666    postProcessingGlobalAttributes();
[983]667
[1130]668    if (hasClient) sendPostProcessingGlobalAttributes();
669
670    // There are some processings that should be done after all of above. For example: check mask or index
[1025]671    this->buildFilterGraphOfEnabledFields();
672   
[1130]673     if (hasClient && !hasServer)
[509]674    {
[1130]675      buildFilterGraphOfFieldsWithReadAccess();
[1358]676      postProcessFilterGraph();
[509]677    }
[1144]678   
[1232]679    checkGridEnabledFields();   
[509]680
[1025]681    if (hasClient) this->sendProcessingGridOfEnabledFields();
[1077]682    if (hasClient) this->sendCloseDefinition();
[510]683
[584]684    // Nettoyage de l'arborescence
[983]685    if (hasClient) CleanTree(); // Only on client side??
[510]686
[598]687    if (hasClient)
688    {
689      sendCreateFileHeader();
[983]690      if (!hasServer) startPrefetchingOfEnabledReadModeFiles();
[598]691    }
[1158]692    CTimer::get("Context : close definition").suspend() ;
[300]693   }
[509]694
[1232]695   void CContext::findAllEnabledFieldsInFiles(const std::vector<CFile*>& activeFiles)
[300]696   {
[1232]697     for (unsigned int i = 0; i < activeFiles.size(); i++)
698     (void)activeFiles[i]->getEnabledFields();
[300]699   }
700
[775]701   void CContext::readAttributesOfEnabledFieldsInReadModeFiles()
702   {
703      for (unsigned int i = 0; i < this->enabledReadModeFiles.size(); ++i)
704        (void)this->enabledReadModeFiles[i]->readAttributesOfEnabledFieldsInReadMode();
705   }
706
[1239]707   void CContext::sendGridComponentEnabledFieldsInFiles(const std::vector<CFile*>& activeFiles)
708   {
709     int size = activeFiles.size();
710     for (int i = 0; i < size; ++i)
711     {       
712       activeFiles[i]->sendGridComponentOfEnabledFields();
713     }
714   }
715
[1232]716   /*!
717      Send active (enabled) fields in file from a client to others
718      \param [in] activeFiles files contains enabled fields to send
719   */
720   void CContext::sendGridEnabledFieldsInFiles(const std::vector<CFile*>& activeFiles)
[1025]721   {
[1232]722     int size = activeFiles.size();
[1025]723     for (int i = 0; i < size; ++i)
[1099]724     {       
[1232]725       activeFiles[i]->sendGridOfEnabledFields();
[1025]726     }
727   }
728
[1099]729   void CContext::checkGridEnabledFields()
730   {
[1232]731     int size = enabledFiles.size();
[1099]732     for (int i = 0; i < size; ++i)
733     {
[1232]734       enabledFiles[i]->checkGridOfEnabledFields();       
[1099]735     }
736   }
[1025]737
[1232]738   /*!
739      Check grid of active (enabled) fields in file
740      \param [in] activeFiles files contains enabled fields whose grid needs checking
741   */
742   void CContext::checkGridEnabledFieldsInFiles(const std::vector<CFile*>& activeFiles)
743   {
744     int size = activeFiles.size();
745     for (int i = 0; i < size; ++i)
746     {
747       activeFiles[i]->checkGridOfEnabledFields();       
748     }
749   }
750
751    /*!
752      Go up the hierachical tree via field_ref and do check of attributes of fields
753      This can be done in a client then all computed information will be sent from this client to others
754      \param [in] sendToServer Flag to indicate whether calculated information will be sent
755   */
[823]756   void CContext::solveOnlyRefOfEnabledFields(bool sendToServer)
757   {
758     int size = this->enabledFiles.size();
759     for (int i = 0; i < size; ++i)
760     {
761       this->enabledFiles[i]->solveOnlyRefOfEnabledFields(sendToServer);
762     }
763
764     for (int i = 0; i < size; ++i)
765     {
766       this->enabledFiles[i]->generateNewTransformationGridDest();
767     }
768   }
769
[1232]770    /*!
771      Go up the hierachical tree via field_ref and do check of attributes of fields.
772      The transformation can be done in this step.
773      All computed information will be sent from this client to others.
774      \param [in] sendToServer Flag to indicate whether calculated information will be sent
775   */
[1129]776   void CContext::solveAllRefOfEnabledFieldsAndTransform(bool sendToServer)
[300]777   {
[509]778     int size = this->enabledFiles.size();
779     for (int i = 0; i < size; ++i)
780     {
[1129]781       this->enabledFiles[i]->solveAllRefOfEnabledFieldsAndTransform(sendToServer);
[509]782     }
[300]783   }
784
[640]785   void CContext::buildFilterGraphOfEnabledFields()
786   {
787     int size = this->enabledFiles.size();
788     for (int i = 0; i < size; ++i)
789     {
790       this->enabledFiles[i]->buildFilterGraphOfEnabledFields(garbageCollector);
791     }
792   }
793
[1358]794   void CContext::postProcessFilterGraph()
795   {
796     int size = enabledFiles.size();
797     for (int i = 0; i < size; ++i)
798     {
799        enabledFiles[i]->postProcessFilterGraph();
800     }
801   }
802
[598]803   void CContext::startPrefetchingOfEnabledReadModeFiles()
804   {
805     int size = enabledReadModeFiles.size();
806     for (int i = 0; i < size; ++i)
807     {
808        enabledReadModeFiles[i]->prefetchEnabledReadModeFields();
809     }
810   }
811
[1358]812   void CContext::doPreTimestepOperationsForEnabledReadModeFiles()
813   {
814     int size = enabledReadModeFiles.size();
815     for (int i = 0; i < size; ++i)
816     {
817        enabledReadModeFiles[i]->doPreTimestepOperationsForEnabledReadModeFields();
818     }
819   }
820
[1318]821   void CContext::doPostTimestepOperationsForEnabledReadModeFiles()
[598]822   {
823     int size = enabledReadModeFiles.size();
824     for (int i = 0; i < size; ++i)
825     {
[1318]826        enabledReadModeFiles[i]->doPostTimestepOperationsForEnabledReadModeFields();
[598]827     }
828   }
829
[593]830  void CContext::findFieldsWithReadAccess(void)
831  {
832    fieldsWithReadAccess.clear();
833    const vector<CField*> allFields = CField::getAll();
834    for (size_t i = 0; i < allFields.size(); ++i)
835    {
[740]836      CField* field = allFields[i];
837
838      if (field->file && !field->file->mode.isEmpty() && field->file->mode == CFile::mode_attr::read)
839        field->read_access = true;
840      else if (!field->read_access.isEmpty() && field->read_access && (field->enabled.isEmpty() || field->enabled))
841        fieldsWithReadAccess.push_back(field);
[593]842    }
843  }
844
845  void CContext::solveAllRefOfFieldsWithReadAccess()
846  {
847    for (size_t i = 0; i < fieldsWithReadAccess.size(); ++i)
848      fieldsWithReadAccess[i]->solveAllReferenceEnabledField(false);
849  }
850
[640]851  void CContext::buildFilterGraphOfFieldsWithReadAccess()
852  {
853    for (size_t i = 0; i < fieldsWithReadAccess.size(); ++i)
854      fieldsWithReadAccess[i]->buildFilterGraph(garbageCollector, true);
855  }
856
[445]857   void CContext::solveAllInheritance(bool apply)
[300]858   {
859     // Résolution des héritages descendants (càd des héritages de groupes)
860     // pour chacun des contextes.
[445]861      solveDescInheritance(apply);
[300]862
863     // Résolution des héritages par référence au niveau des fichiers.
[549]864      const vector<CFile*> allFiles=CFile::getAll();
[540]865      const vector<CGrid*> allGrids= CGrid::getAll();
[300]866
[983]867      if (hasClient && !hasServer)
868      //if (hasClient)
[540]869      {
[510]870        for (unsigned int i = 0; i < allFiles.size(); i++)
871          allFiles[i]->solveFieldRefInheritance(apply);
[540]872      }
873
874      unsigned int vecSize = allGrids.size();
875      unsigned int i = 0;
876      for (i = 0; i < vecSize; ++i)
877        allGrids[i]->solveDomainAxisRefInheritance(apply);
878
[300]879   }
880
881   void CContext::findEnabledFiles(void)
882   {
[347]883      const std::vector<CFile*> allFiles = CFile::getAll();
[1158]884      const CDate& initDate = calendar->getInitDate();
[300]885
886      for (unsigned int i = 0; i < allFiles.size(); i++)
887         if (!allFiles[i]->enabled.isEmpty()) // Si l'attribut 'enabled' est défini.
[430]888         {
[300]889            if (allFiles[i]->enabled.getValue()) // Si l'attribut 'enabled' est fixé à vrai.
[1158]890            {
[1489]891              if (allFiles[i]->output_freq.isEmpty())
[1488]892              {
893                 ERROR("CContext::findEnabledFiles()",
894                     << "Mandatory attribute output_freq must be defined for file \""<<allFiles[i]->getFileOutputName()
895                     <<" \".")
896              }
[1158]897              if ((initDate + allFiles[i]->output_freq.getValue()) < (initDate + this->getCalendar()->getTimeStep()))
898              {
899                error(0)<<"WARNING: void CContext::findEnabledFiles()"<<endl
900                    << "Output frequency in file \""<<allFiles[i]->getFileOutputName()
901                    <<"\" is less than the time step. File will not be written."<<endl;
902              }
903              else
[300]904               enabledFiles.push_back(allFiles[i]);
[1158]905            }
[430]906         }
[1158]907         else
908         {
[1489]909           if (allFiles[i]->output_freq.isEmpty())
[1488]910           {
911              ERROR("CContext::findEnabledFiles()",
912                  << "Mandatory attribute output_freq must be defined for file \""<<allFiles[i]->getFileOutputName()
913                  <<" \".")
914           }
[1158]915           if ( (initDate + allFiles[i]->output_freq.getValue()) < (initDate + this->getCalendar()->getTimeStep()))
916           {
917             error(0)<<"WARNING: void CContext::findEnabledFiles()"<<endl
918                 << "Output frequency in file \""<<allFiles[i]->getFileOutputName()
919                 <<"\" is less than the time step. File will not be written."<<endl;
920           }
921           else
922             enabledFiles.push_back(allFiles[i]); // otherwise true by default
923         }
[300]924
925      if (enabledFiles.size() == 0)
926         DEBUG(<<"Aucun fichier ne va être sorti dans le contexte nommé \""
927               << getId() << "\" !");
[1021]928
[300]929   }
930
[1208]931   void CContext::distributeFiles(void)
932   {
[1349]933     bool distFileMemory=false ;
934     distFileMemory=CXios::getin<bool>("server2_dist_file_memory", distFileMemory);
935
936     if (distFileMemory) distributeFileOverMemoryBandwith() ;
937     else distributeFileOverBandwith() ;
938   }
939
940
941   void CContext::distributeFileOverBandwith(void)
942   {
[1215]943     double eps=std::numeric_limits<double>::epsilon()*10 ;
944     
[1208]945     // If primary server
946     if (hasServer && hasClient)
947     {
[1349]948       std::ofstream ofs(("distribute_file_"+getId()+".dat").c_str(), std::ofstream::out);
[1212]949       int nbPools = clientPrimServer.size();
950
[1208]951       // (1) Find all enabled files in write mode
[1232]952       // for (int i = 0; i < this->enabledFiles.size(); ++i)
953       // {
954       //   if (enabledFiles[i]->mode.isEmpty() || (!enabledFiles[i]->mode.isEmpty() && enabledFiles[i]->mode.getValue() == CFile::mode_attr::write ))
955       //    enabledWriteModeFiles.push_back(enabledFiles[i]);
956       // }
[1208]957
958       // (2) Estimate the data volume for each file
959       int size = this->enabledWriteModeFiles.size();
[1215]960       std::vector<std::pair<double, CFile*> > dataSizeMap;
961       double dataPerPool = 0;
962       int nfield=0 ;
[1349]963       ofs<<size<<endl ;
[1208]964       for (size_t i = 0; i < size; ++i)
965       {
966         CFile* file = this->enabledWriteModeFiles[i];
[1349]967         ofs<<file->getId()<<endl ;
[1215]968         StdSize dataSize=0;
[1208]969         std::vector<CField*> enabledFields = file->getEnabledFields();
970         size_t numEnabledFields = enabledFields.size();
[1349]971         ofs<<numEnabledFields<<endl ;
972         for (size_t j = 0; j < numEnabledFields; ++j)
973         {
974           dataSize += enabledFields[j]->getGlobalWrittenSize() ;
975           ofs<<enabledFields[j]->grid->getId()<<endl ;
976           ofs<<enabledFields[j]->getGlobalWrittenSize()<<endl ;
977         }
[1215]978         double outFreqSec = (Time)(calendar->getCurrentDate()+file->output_freq)-(Time)(calendar->getCurrentDate()) ;
979         double dataSizeSec= dataSize/ outFreqSec;
[1349]980         ofs<<dataSizeSec<<endl ;
[1215]981         nfield++ ;
982// add epsilon*nField to dataSizeSec in order to  preserve reproductive ordering when sorting
983         dataSizeMap.push_back(make_pair(dataSizeSec + dataSizeSec * eps * nfield , file));
984         dataPerPool += dataSizeSec;
[1208]985       }
[1212]986       dataPerPool /= nbPools;
[1208]987       std::sort(dataSizeMap.begin(), dataSizeMap.end());
988
[1212]989       // (3) Assign contextClient to each enabled file
[1215]990
991       std::multimap<double,int> poolDataSize ;
992// multimap is not garanty to preserve stable sorting in c++98 but it seems it does for c++11
993
994       int j;
995       double dataSize ;
996       for (j = 0 ; j < nbPools ; ++j) poolDataSize.insert(std::pair<double,int>(0.,j)) ; 
997             
[1212]998       for (int i = dataSizeMap.size()-1; i >= 0; --i)
[1208]999       {
[1215]1000         dataSize=(*poolDataSize.begin()).first ;
1001         j=(*poolDataSize.begin()).second ;
1002         dataSizeMap[i].second->setContextClient(clientPrimServer[j]);
1003         dataSize+=dataSizeMap[i].first;
1004         poolDataSize.erase(poolDataSize.begin()) ;
1005         poolDataSize.insert(std::pair<double,int>(dataSize,j)) ; 
[1208]1006       }
[1212]1007
[1601]1008       for (std::multimap<double,int>:: iterator it=poolDataSize.begin() ; it!=poolDataSize.end(); ++it)
1009       {
1010         #pragma omp critical (_output)
1011         info(30)<<"Load Balancing for servers (perfect=1) : "<<it->second<<" :  ratio "<<it->first*1./dataPerPool<<endl ;
1012       }
1013
[1212]1014       for (int i = 0; i < this->enabledReadModeFiles.size(); ++i)
[1232]1015       {
1016         enabledReadModeFiles[i]->setContextClient(client);         
1017       }
[1208]1018     }
1019     else
1020     {
1021       for (int i = 0; i < this->enabledFiles.size(); ++i)
1022         enabledFiles[i]->setContextClient(client);
1023     }
1024   }
1025
[1349]1026   void CContext::distributeFileOverMemoryBandwith(void)
1027   {
1028     // If primary server
1029     if (hasServer && hasClient)
1030     {
1031       int nbPools = clientPrimServer.size();
1032       double ratio=0.5 ;
1033       ratio=CXios::getin<double>("server2_dist_file_memory_ratio", ratio);
1034
1035       int nFiles = this->enabledWriteModeFiles.size();
1036       vector<SDistFile> files(nFiles);
1037       vector<SDistGrid> grids;
1038       map<string,int> gridMap ;
1039       string gridId; 
1040       int gridIndex=0 ;
1041
1042       for (size_t i = 0; i < nFiles; ++i)
1043       {
1044         StdSize dataSize=0;
1045         CFile* file = this->enabledWriteModeFiles[i];
1046         std::vector<CField*> enabledFields = file->getEnabledFields();
1047         size_t numEnabledFields = enabledFields.size();
1048
1049         files[i].id_=file->getId() ;
1050         files[i].nbGrids_=numEnabledFields;
1051         files[i].assignedGrid_ = new int[files[i].nbGrids_] ;
1052         
1053         for (size_t j = 0; j < numEnabledFields; ++j)
1054         {
1055           gridId=enabledFields[j]->grid->getId() ;
1056           if (gridMap.find(gridId)==gridMap.end())
1057           {
1058              gridMap[gridId]=gridIndex  ;
1059              SDistGrid newGrid; 
1060              grids.push_back(newGrid) ;
1061              gridIndex++ ;
1062           }
1063           files[i].assignedGrid_[j]=gridMap[gridId] ;
1064           grids[files[i].assignedGrid_[j]].size_=enabledFields[j]->getGlobalWrittenSize() ;
1065           dataSize += enabledFields[j]->getGlobalWrittenSize() ; // usefull
1066         }
1067         double outFreqSec = (Time)(calendar->getCurrentDate()+file->output_freq)-(Time)(calendar->getCurrentDate()) ;
1068         files[i].bandwith_= dataSize/ outFreqSec ;
1069       }
1070
1071       double bandwith=0 ;
1072       double memory=0 ;
1073   
1074       for(int i=0; i<nFiles; i++)  bandwith+=files[i].bandwith_ ;
1075       for(int i=0; i<nFiles; i++)  files[i].bandwith_ = files[i].bandwith_/bandwith * ratio ;
1076
1077       for(int i=0; i<grids.size(); i++)  memory+=grids[i].size_ ;
1078       for(int i=0; i<grids.size(); i++)  grids[i].size_ = grids[i].size_ / memory * (1.0-ratio) ;
1079       
1080       distributeFileOverServer2(nbPools, grids.size(), &grids[0], nFiles, &files[0]) ;
1081
1082       vector<double> memorySize(nbPools,0.) ;
1083       vector< set<int> > serverGrids(nbPools) ;
1084       vector<double> bandwithSize(nbPools,0.) ;
1085       
1086       for (size_t i = 0; i < nFiles; ++i)
1087       {
1088         bandwithSize[files[i].assignedServer_] += files[i].bandwith_* bandwith /ratio ;
1089         for(int j=0 ; j<files[i].nbGrids_;j++)
1090         {
1091           if (serverGrids[files[i].assignedServer_].find(files[i].assignedGrid_[j]) == serverGrids[files[i].assignedServer_].end())
1092           {
1093             memorySize[files[i].assignedServer_]+= grids[files[i].assignedGrid_[j]].size_ * memory / (1.0-ratio);
1094             serverGrids[files[i].assignedServer_].insert(files[i].assignedGrid_[j]) ;
1095           }
1096         }
1097         enabledWriteModeFiles[i]->setContextClient(clientPrimServer[files[i].assignedServer_]) ;
1098         delete [] files[i].assignedGrid_ ;
1099       }
1100
[1601]1101       for (int i = 0; i < nbPools; ++i)
1102       {
1103         #pragma omp critical (_output)
1104         info(100)<<"Pool server level2 "<<i<<"   assigned file bandwith "<<bandwithSize[i]*86400.*4./1024/1024.<<" Mb / days"<<endl ;
1105       }
1106       for (int i = 0; i < nbPools; ++i)
1107       {
1108         #pragma omp critical (_output)
1109         info(100)<<"Pool server level2 "<<i<<"   assigned grid memory "<<memorySize[i]*100/1024./1024.<<" Mb"<<endl ;
1110       }
[1349]1111
1112       for (int i = 0; i < this->enabledReadModeFiles.size(); ++i)
1113       {
1114         enabledReadModeFiles[i]->setContextClient(client);         
1115       }
1116
1117   }
1118   else
1119   {
1120     for (int i = 0; i < this->enabledFiles.size(); ++i)
1121        enabledFiles[i]->setContextClient(client);
1122   }
1123}
1124
1125
1126
[1232]1127   /*!
1128      Find all files in write mode
1129   */
1130   void CContext::findEnabledWriteModeFiles(void)
1131   {
1132     int size = this->enabledFiles.size();
1133     for (int i = 0; i < size; ++i)
1134     {
1135       if (enabledFiles[i]->mode.isEmpty() || 
1136          (!enabledFiles[i]->mode.isEmpty() && enabledFiles[i]->mode.getValue() == CFile::mode_attr::write ))
1137        enabledWriteModeFiles.push_back(enabledFiles[i]);
1138     }
1139   }
1140
1141   /*!
1142      Find all files in read mode
1143   */
[598]1144   void CContext::findEnabledReadModeFiles(void)
1145   {
1146     int size = this->enabledFiles.size();
1147     for (int i = 0; i < size; ++i)
1148     {
1149       if (!enabledFiles[i]->mode.isEmpty() && enabledFiles[i]->mode.getValue() == CFile::mode_attr::read)
1150        enabledReadModeFiles.push_back(enabledFiles[i]);
1151     }
1152   }
1153
[300]1154   void CContext::closeAllFile(void)
1155   {
[347]1156     std::vector<CFile*>::const_iterator
[300]1157            it = this->enabledFiles.begin(), end = this->enabledFiles.end();
[509]1158
[300]1159     for (; it != end; it++)
1160     {
[1601]1161       #pragma omp critical (_output)
[300]1162       info(30)<<"Closing File : "<<(*it)->getId()<<endl;
1163       (*it)->close();
1164     }
1165   }
[509]1166
1167   /*!
1168   \brief Dispatch event received from client
1169      Whenever a message is received in buffer of server, it will be processed depending on
1170   its event type. A new event type should be added in the switch list to make sure
1171   it processed on server side.
1172   \param [in] event: Received message
1173   */
[300]1174   bool CContext::dispatchEvent(CEventServer& event)
1175   {
[509]1176
[549]1177      if (SuperClass::dispatchEvent(event)) return true;
[300]1178      else
1179      {
1180        switch(event.type)
1181        {
1182           case EVENT_ID_CLOSE_DEFINITION :
[549]1183             recvCloseDefinition(event);
1184             return true;
1185             break;
[584]1186           case EVENT_ID_UPDATE_CALENDAR:
[549]1187             recvUpdateCalendar(event);
1188             return true;
1189             break;
[300]1190           case EVENT_ID_CREATE_FILE_HEADER :
[549]1191             recvCreateFileHeader(event);
1192             return true;
1193             break;
[509]1194           case EVENT_ID_POST_PROCESS:
[549]1195             recvPostProcessing(event);
1196             return true;
[697]1197            case EVENT_ID_SEND_REGISTRY:
1198             recvRegistry(event);
1199             return true;
[1025]1200             break;
1201            case EVENT_ID_POST_PROCESS_GLOBAL_ATTRIBUTES:
1202             recvPostProcessingGlobalAttributes(event);
1203             return true;
1204             break;
1205            case EVENT_ID_PROCESS_GRID_ENABLED_FIELDS:
1206             recvProcessingGridOfEnabledFields(event);
1207             return true;
1208             break;
[300]1209           default :
1210             ERROR("bool CContext::dispatchEvent(CEventServer& event)",
[549]1211                    <<"Unknown Event");
1212           return false;
[300]1213         }
1214      }
1215   }
[509]1216
1217   //! Client side: Send a message to server to make it close
[300]1218   void CContext::sendCloseDefinition(void)
1219   {
[987]1220     // Use correct context client to send message
[1030]1221     int nbSrvPools = (this->hasServer) ? (this->hasClient ? this->clientPrimServer.size() : 0) : 1;
[1009]1222     for (int i = 0; i < nbSrvPools; ++i)
[300]1223     {
[1009]1224       CContextClient* contextClientTmp = (hasServer) ? clientPrimServer[i] : client;
1225       CEventClient event(getType(),EVENT_ID_CLOSE_DEFINITION);
1226       if (contextClientTmp->isServerLeader())
1227       {
1228         CMessage msg;
1229         if (hasServer)
1230           msg<<this->getIdServer(i);
1231         else
1232           msg<<this->getIdServer();
1233         const std::list<int>& ranks = contextClientTmp->getRanksServerLeader();
1234         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
1235           event.push(*itRank,1,msg);
1236         contextClientTmp->sendEvent(event);
1237       }
1238       else contextClientTmp->sendEvent(event);
[300]1239     }
1240   }
[509]1241
1242   //! Server side: Receive a message of client announcing a context close
[300]1243   void CContext::recvCloseDefinition(CEventServer& event)
1244   {
1245      CBufferIn* buffer=event.subEvents.begin()->buffer;
1246      string id;
[549]1247      *buffer>>id;
[509]1248      get(id)->closeDefinition();
[300]1249   }
[509]1250
1251   //! Client side: Send a message to update calendar in each time step
[300]1252   void CContext::sendUpdateCalendar(int step)
1253   {
[987]1254     // Use correct context client to send message
[1030]1255    int nbSrvPools = (this->hasServer) ? (this->hasClient ? this->clientPrimServer.size() : 0) : 1;
[1009]1256     for (int i = 0; i < nbSrvPools; ++i)
1257     {
1258       CContextClient* contextClientTmp = (hasServer) ? clientPrimServer[i] : client;
1259       CEventClient event(getType(),EVENT_ID_UPDATE_CALENDAR);
[987]1260
[1009]1261         if (contextClientTmp->isServerLeader())
1262         {
1263           CMessage msg;
1264           if (hasServer)
1265             msg<<this->getIdServer(i)<<step;
1266           else
1267             msg<<this->getIdServer()<<step;
1268           const std::list<int>& ranks = contextClientTmp->getRanksServerLeader();
1269           for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
1270             event.push(*itRank,1,msg);
1271           contextClientTmp->sendEvent(event);
1272         }
1273         else contextClientTmp->sendEvent(event);
1274     }
[300]1275   }
[509]1276
1277   //! Server side: Receive a message of client annoucing calendar update
[300]1278   void CContext::recvUpdateCalendar(CEventServer& event)
1279   {
1280      CBufferIn* buffer=event.subEvents.begin()->buffer;
1281      string id;
[549]1282      *buffer>>id;
1283      get(id)->recvUpdateCalendar(*buffer);
[300]1284   }
[509]1285
1286   //! Server side: Receive a message of client annoucing calendar update
[300]1287   void CContext::recvUpdateCalendar(CBufferIn& buffer)
1288   {
[549]1289      int step;
1290      buffer>>step;
1291      updateCalendar(step);
[987]1292      if (hasClient && hasServer)
1293      {       
1294        sendUpdateCalendar(step);
1295      }
[300]1296   }
[509]1297
1298   //! Client side: Send a message to create header part of netcdf file
[300]1299   void CContext::sendCreateFileHeader(void)
1300   {
[987]1301     // Use correct context client to send message
[1030]1302     // int nbSrvPools = (hasServer) ? clientPrimServer.size() : 1;
1303     int nbSrvPools = (this->hasServer) ? (this->hasClient ? this->clientPrimServer.size() : 0) : 1;
[1009]1304     for (int i = 0; i < nbSrvPools; ++i)
1305     {
1306       CContextClient* contextClientTmp = (hasServer) ? clientPrimServer[i] : client;
1307       CEventClient event(getType(),EVENT_ID_CREATE_FILE_HEADER);
[983]1308
[1009]1309       if (contextClientTmp->isServerLeader())
1310       {
1311         CMessage msg;
1312         if (hasServer)
1313           msg<<this->getIdServer(i);
1314         else
1315           msg<<this->getIdServer();
1316         const std::list<int>& ranks = contextClientTmp->getRanksServerLeader();
1317         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
1318           event.push(*itRank,1,msg) ;
1319         contextClientTmp->sendEvent(event);
1320       }
1321       else contextClientTmp->sendEvent(event);
[300]1322     }
1323   }
[509]1324
1325   //! Server side: Receive a message of client annoucing the creation of header part of netcdf file
[300]1326   void CContext::recvCreateFileHeader(CEventServer& event)
1327   {
1328      CBufferIn* buffer=event.subEvents.begin()->buffer;
1329      string id;
[549]1330      *buffer>>id;
1331      get(id)->recvCreateFileHeader(*buffer);
[300]1332   }
[509]1333
1334   //! Server side: Receive a message of client annoucing the creation of header part of netcdf file
[300]1335   void CContext::recvCreateFileHeader(CBufferIn& buffer)
1336   {
[987]1337      if (!hasClient && hasServer) 
1338        createFileHeader();
[300]1339   }
[509]1340
1341   //! Client side: Send a message to do some post processing on server
[1025]1342   void CContext::sendProcessingGridOfEnabledFields()
1343   {
1344      // Use correct context client to send message
[1030]1345     int nbSrvPools = (this->hasServer) ? (this->hasClient ? this->clientPrimServer.size() : 0) : 1;
[1027]1346     for (int i = 0; i < nbSrvPools; ++i)
1347     {
1348       CContextClient* contextClientTmp = (0 != clientPrimServer.size()) ? clientPrimServer[i] : client;
1349       CEventClient event(getType(),EVENT_ID_PROCESS_GRID_ENABLED_FIELDS);
[1025]1350
[1027]1351       if (contextClientTmp->isServerLeader())
1352       {
1353         CMessage msg;
[1099]1354         if (hasServer)
1355           msg<<this->getIdServer(i);
1356         else
1357           msg<<this->getIdServer();
[1027]1358         const std::list<int>& ranks = contextClientTmp->getRanksServerLeader();
1359         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
1360           event.push(*itRank,1,msg);
1361         contextClientTmp->sendEvent(event);
1362       }
1363       else contextClientTmp->sendEvent(event);
[1025]1364     }
1365   }
1366
1367   //! Server side: Receive a message to do some post processing
1368   void CContext::recvProcessingGridOfEnabledFields(CEventServer& event)
1369   {
1370      CBufferIn* buffer=event.subEvents.begin()->buffer;
1371      string id;
[1144]1372      *buffer>>id;     
[1025]1373   }
1374
1375   //! Client side: Send a message to do some post processing on server
[509]1376   void CContext::sendPostProcessing()
1377   {
[987]1378      // Use correct context client to send message
[1030]1379     // int nbSrvPools = (hasServer) ? clientPrimServer.size() : 1;
1380     int nbSrvPools = (this->hasServer) ? (this->hasClient ? this->clientPrimServer.size() : 0) : 1;
[1009]1381     for (int i = 0; i < nbSrvPools; ++i)
[509]1382     {
[1009]1383       CContextClient* contextClientTmp = (hasServer) ? clientPrimServer[i] : client;
1384       CEventClient event(getType(),EVENT_ID_POST_PROCESS);
1385       if (contextClientTmp->isServerLeader())
1386       {
1387         CMessage msg;
1388         if (hasServer)
1389           msg<<this->getIdServer(i);
1390         else
1391           msg<<this->getIdServer();
1392         const std::list<int>& ranks = contextClientTmp->getRanksServerLeader();
1393         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
[987]1394         event.push(*itRank,1,msg);
[1009]1395         contextClientTmp->sendEvent(event);
1396       }
1397       else contextClientTmp->sendEvent(event);
[509]1398     }
1399   }
1400
1401   //! Server side: Receive a message to do some post processing
1402   void CContext::recvPostProcessing(CEventServer& event)
1403   {
1404      CBufferIn* buffer=event.subEvents.begin()->buffer;
1405      string id;
1406      *buffer>>id;
1407      get(id)->recvPostProcessing(*buffer);
1408   }
1409
1410   //! Server side: Receive a message to do some post processing
1411   void CContext::recvPostProcessing(CBufferIn& buffer)
1412   {
[549]1413      CCalendarWrapper::get(CCalendarWrapper::GetDefName())->createCalendar();
[509]1414      postProcessing();
1415   }
1416
[511]1417   const StdString& CContext::getIdServer()
1418   {
1419      if (hasClient)
1420      {
1421        idServer_ = this->getId();
1422        idServer_ += "_server";
1423        return idServer_;
1424      }
1425      if (hasServer) return (this->getId());
1426   }
1427
[1009]1428   const StdString& CContext::getIdServer(const int i)
1429   {
1430     idServer_ = this->getId();
1431     idServer_ += "_server_";
[1542]1432     idServer_ += std::to_string(static_cast<unsigned long long>(i));
[1009]1433     return idServer_;
1434   }
1435
1436
[509]1437   /*!
1438   \brief Do some simple post processings after parsing xml file
1439      After the xml file (iodef.xml) is parsed, it is necessary to build all relations among
1440   created object, e.g: inhertance among fields, domain, axis. After that, all fiels as well as their parents (reference fields),
1441   which will be written out into netcdf files, are processed
1442   */
1443   void CContext::postProcessing()
1444   {
1445     if (isPostProcessed) return;
1446
[549]1447      // Make sure the calendar was correctly created
1448      if (!calendar)
1449        ERROR("CContext::postProcessing()", << "A calendar must be defined for the context \"" << getId() << "!\"")
1450      else if (calendar->getTimeStep() == NoneDu)
1451        ERROR("CContext::postProcessing()", << "A timestep must be defined for the context \"" << getId() << "!\"")
[550]1452      // Calendar first update to set the current date equals to the start date
1453      calendar->update(0);
[509]1454
1455      // Find all inheritance in xml structure
1456      this->solveAllInheritance();
1457
[992]1458//      ShowTree(info(10));
[983]1459
[676]1460      // Check if some axis, domains or grids are eligible to for compressed indexed output.
1461      // Warning: This must be done after solving the inheritance and before the rest of post-processing
[1025]1462      checkAxisDomainsGridsEligibilityForCompressedOutput();     
[676]1463
[711]1464      // Check if some automatic time series should be generated
[1144]1465      // Warning: This must be done after solving the inheritance and before the rest of post-processing     
[711]1466
[1025]1467      // The timeseries should only be prepared in client
1468      if (hasClient && !hasServer) prepareTimeseries();
1469
[509]1470      //Initialisation du vecteur 'enabledFiles' contenant la liste des fichiers à sortir.
[1232]1471      findEnabledFiles();
1472      findEnabledWriteModeFiles();
1473      findEnabledReadModeFiles();
1474
[1025]1475      // For now, only read files with client and only one level server
[1232]1476      // if (hasClient && !hasServer) findEnabledReadModeFiles();     
[509]1477
[1232]1478      // Find all enabled fields of each file     
1479      findAllEnabledFieldsInFiles(this->enabledWriteModeFiles);
1480      findAllEnabledFieldsInFiles(this->enabledReadModeFiles);
1481
[1025]1482      // For now, only read files with client and only one level server
[1232]1483      // if (hasClient && !hasServer)
1484      //   findAllEnabledFieldsInFiles(this->enabledReadModeFiles);     
[509]1485
[1144]1486      if (hasClient && !hasServer)
1487      {
[1232]1488        initReadFiles();
1489        // Try to read attributes of fields in file then fill in corresponding grid (or domain, axis)
1490        this->readAttributesOfEnabledFieldsInReadModeFiles();
[1144]1491      }
1492
[823]1493      // Only search and rebuild all reference objects of enable fields, don't transform
[1099]1494      this->solveOnlyRefOfEnabledFields(false);
[823]1495
[1099]1496      // Search and rebuild all reference object of enabled fields, and transform
[1129]1497      this->solveAllRefOfEnabledFieldsAndTransform(false);
[1099]1498
[593]1499      // Find all fields with read access from the public API
[1025]1500      if (hasClient && !hasServer) findFieldsWithReadAccess();
[593]1501      // and solve the all reference for them
[1025]1502      if (hasClient && !hasServer) solveAllRefOfFieldsWithReadAccess();
[593]1503
[509]1504      isPostProcessed = true;
1505   }
1506
[917]1507   /*!
1508    * Compute the required buffer size to send the attributes (mostly those grid related).
1509    * \param maxEventSize [in/out] the size of the bigger event for each connected server
[1330]1510    * \param [in] contextClient
1511    * \param [in] bufferForWriting True if buffers are used for sending data for writing
1512      This flag is only true for client and server-1 for communication with server-2
[917]1513    */
[1330]1514   std::map<int, StdSize> CContext::getAttributesBufferSize(std::map<int, StdSize>& maxEventSize,
1515                                                           CContextClient* contextClient, bool bufferForWriting /*= "false"*/)
[509]1516   {
[1372]1517         // As calendar attributes are sent even if there are no active files or fields, maps are initialized according the size of calendar attributes
1518     std::map<int, StdSize> attributesSize = CCalendarWrapper::get(CCalendarWrapper::GetDefName())->getMinimumBufferSizeForAttributes(contextClient);
1519     maxEventSize = CCalendarWrapper::get(CCalendarWrapper::GetDefName())->getMinimumBufferSizeForAttributes(contextClient);
[731]1520
[1370]1521     std::vector<CFile*>& fileList = this->enabledFiles;
1522     size_t numEnabledFiles = fileList.size();
1523     for (size_t i = 0; i < numEnabledFiles; ++i)
[731]1524     {
[1370]1525//         CFile* file = this->enabledWriteModeFiles[i];
1526        CFile* file = fileList[i];
1527        std::vector<CField*> enabledFields = file->getEnabledFields();
1528        size_t numEnabledFields = enabledFields.size();
1529        for (size_t j = 0; j < numEnabledFields; ++j)
1530        {
1531          const std::map<int, StdSize> mapSize = enabledFields[j]->getGridAttributesBufferSize(contextClient, bufferForWriting);
1532          std::map<int, StdSize>::const_iterator it = mapSize.begin(), itE = mapSize.end();
1533          for (; it != itE; ++it)
1534          {
1535                     // If attributesSize[it->first] does not exist, it will be zero-initialized
1536                     // so we can use it safely without checking for its existence
1537             if (attributesSize[it->first] < it->second)
1538                           attributesSize[it->first] = it->second;
[917]1539
[1370]1540                     if (maxEventSize[it->first] < it->second)
1541                           maxEventSize[it->first] = it->second;
1542          }
1543        }
[731]1544     }
1545     return attributesSize;
1546   }
1547
[917]1548   /*!
1549    * Compute the required buffer size to send the fields data.
1550    * \param maxEventSize [in/out] the size of the bigger event for each connected server
[1330]1551    * \param [in] contextClient
1552    * \param [in] bufferForWriting True if buffers are used for sending data for writing
1553      This flag is only true for client and server-1 for communication with server-2
[917]1554    */
[1330]1555   std::map<int, StdSize> CContext::getDataBufferSize(std::map<int, StdSize>& maxEventSize,
1556                                                      CContextClient* contextClient, bool bufferForWriting /*= "false"*/)
[731]1557   {
[730]1558     std::map<int, StdSize> dataSize;
[509]1559
1560     // Find all reference domain and axis of all active fields
[1330]1561     std::vector<CFile*>& fileList = bufferForWriting ? this->enabledWriteModeFiles : this->enabledReadModeFiles;
1562     size_t numEnabledFiles = fileList.size();
[730]1563     for (size_t i = 0; i < numEnabledFiles; ++i)
[509]1564     {
[1330]1565//       CFile* file = this->enabledFiles[i];
1566       CFile* file = fileList[i];
[1193]1567       if (file->getContextClient() == contextClient)
[1184]1568       {
[1370]1569         std::vector<CField*> enabledFields = file->getEnabledFields();
1570         size_t numEnabledFields = enabledFields.size();
1571         for (size_t j = 0; j < numEnabledFields; ++j)
[509]1572         {
[1370]1573           // const std::vector<std::map<int, StdSize> > mapSize = enabledFields[j]->getGridDataBufferSize(contextClient);
1574           const std::map<int, StdSize> mapSize = enabledFields[j]->getGridDataBufferSize(contextClient,bufferForWriting);
1575           std::map<int, StdSize>::const_iterator it = mapSize.begin(), itE = mapSize.end();
1576           for (; it != itE; ++it)
[509]1577           {
[1370]1578             // If dataSize[it->first] does not exist, it will be zero-initialized
1579             // so we can use it safely without checking for its existance
1580                 if (CXios::isOptPerformance)
1581               dataSize[it->first] += it->second;
1582             else if (dataSize[it->first] < it->second)
1583               dataSize[it->first] = it->second;
[917]1584
[1370]1585                 if (maxEventSize[it->first] < it->second)
1586               maxEventSize[it->first] = it->second;
[598]1587           }
[509]1588         }
1589       }
1590     }
[730]1591     return dataSize;
[509]1592   }
1593
1594   //! Client side: Send infomation of active files (files are enabled to write out)
[1232]1595   void CContext::sendEnabledFiles(const std::vector<CFile*>& activeFiles)
[509]1596   {
[1232]1597     int size = activeFiles.size();
[509]1598
1599     // In a context, each type has a root definition, e.g: axis, domain, field.
1600     // Every object must be a child of one of these root definition. In this case
1601     // all new file objects created on server must be children of the root "file_definition"
1602     StdString fileDefRoot("file_definition");
1603     CFileGroup* cfgrpPtr = CFileGroup::get(fileDefRoot);
[1158]1604
[509]1605     for (int i = 0; i < size; ++i)
1606     {
[1232]1607       CFile* f = activeFiles[i];
1608       cfgrpPtr->sendCreateChild(f->getId(),f->getContextClient());
1609       f->sendAllAttributesToServer(f->getContextClient());
1610       f->sendAddAllVariables(f->getContextClient());
[509]1611     }
1612   }
1613
1614   //! Client side: Send information of active fields (ones are written onto files)
[1232]1615   void CContext::sendEnabledFieldsInFiles(const std::vector<CFile*>& activeFiles)
[509]1616   {
[1232]1617     int size = activeFiles.size();
[509]1618     for (int i = 0; i < size; ++i)
1619     {
[1232]1620       activeFiles[i]->sendEnabledFields(activeFiles[i]->getContextClient());
[509]1621     }
1622   }
1623
[676]1624   //! Client side: Check if the defined axis, domains and grids are eligible for compressed indexed output
1625   void CContext::checkAxisDomainsGridsEligibilityForCompressedOutput()
1626   {
1627     if (!hasClient) return;
1628
1629     const vector<CAxis*> allAxis = CAxis::getAll();
1630     for (vector<CAxis*>::const_iterator it = allAxis.begin(); it != allAxis.end(); it++)
1631       (*it)->checkEligibilityForCompressedOutput();
1632
1633     const vector<CDomain*> allDomains = CDomain::getAll();
1634     for (vector<CDomain*>::const_iterator it = allDomains.begin(); it != allDomains.end(); it++)
1635       (*it)->checkEligibilityForCompressedOutput();
1636
1637     const vector<CGrid*> allGrids = CGrid::getAll();
1638     for (vector<CGrid*>::const_iterator it = allGrids.begin(); it != allGrids.end(); it++)
1639       (*it)->checkEligibilityForCompressedOutput();
1640   }
1641
[711]1642   //! Client side: Prepare the timeseries by adding the necessary files
1643   void CContext::prepareTimeseries()
1644   {
1645     if (!hasClient) return;
1646
1647     const std::vector<CFile*> allFiles = CFile::getAll();
1648     for (size_t i = 0; i < allFiles.size(); i++)
1649     {
1650       CFile* file = allFiles[i];
1651
[1158]1652       std::vector<CVariable*> fileVars, fieldVars, vars = file->getAllVariables();
1653       for (size_t k = 0; k < vars.size(); k++)
1654       {
1655         CVariable* var = vars[k];
1656
1657         if (var->ts_target.isEmpty()
1658              || var->ts_target == CVariable::ts_target_attr::file || var->ts_target == CVariable::ts_target_attr::both)
1659           fileVars.push_back(var);
1660
1661         if (!var->ts_target.isEmpty()
1662              && (var->ts_target == CVariable::ts_target_attr::field || var->ts_target == CVariable::ts_target_attr::both))
1663           fieldVars.push_back(var);
1664       }
1665
[711]1666       if (!file->timeseries.isEmpty() && file->timeseries != CFile::timeseries_attr::none)
1667       {
[1158]1668         StdString fileNameStr("%file_name%") ;
1669         StdString tsPrefix = !file->ts_prefix.isEmpty() ? file->ts_prefix : fileNameStr ;
1670         
1671         StdString fileName=file->getFileOutputName();
1672         size_t pos=tsPrefix.find(fileNameStr) ;
1673         while (pos!=std::string::npos)
1674         {
1675           tsPrefix=tsPrefix.replace(pos,fileNameStr.size(),fileName) ;
1676           pos=tsPrefix.find(fileNameStr) ;
1677         }
1678       
[711]1679         const std::vector<CField*> allFields = file->getAllFields();
1680         for (size_t j = 0; j < allFields.size(); j++)
1681         {
1682           CField* field = allFields[j];
1683
1684           if (!field->ts_enabled.isEmpty() && field->ts_enabled)
1685           {
1686             CFile* tsFile = CFile::create();
1687             tsFile->duplicateAttributes(file);
1688
[1158]1689             // Add variables originating from file and targeted to timeserie file
1690             for (size_t k = 0; k < fileVars.size(); k++)
1691               tsFile->getVirtualVariableGroup()->addChild(fileVars[k]);
1692
1693           
[711]1694             tsFile->name = tsPrefix + "_";
1695             if (!field->name.isEmpty())
1696               tsFile->name.get() += field->name;
1697             else if (field->hasDirectFieldReference()) // We cannot use getBaseFieldReference() just yet
1698               tsFile->name.get() += field->field_ref;
1699             else
1700               tsFile->name.get() += field->getId();
1701
1702             if (!field->ts_split_freq.isEmpty())
1703               tsFile->split_freq = field->ts_split_freq;
1704
1705             CField* tsField = tsFile->addField();
1706             tsField->field_ref = field->getId();
1707
[1158]1708             // Add variables originating from file and targeted to timeserie field
1709             for (size_t k = 0; k < fieldVars.size(); k++)
1710               tsField->getVirtualVariableGroup()->addChild(fieldVars[k]);
1711
1712             vars = field->getAllVariables();
1713             for (size_t k = 0; k < vars.size(); k++)
1714             {
1715               CVariable* var = vars[k];
1716
1717               // Add variables originating from field and targeted to timeserie field
1718               if (var->ts_target.isEmpty()
1719                    || var->ts_target == CVariable::ts_target_attr::field || var->ts_target == CVariable::ts_target_attr::both)
1720                 tsField->getVirtualVariableGroup()->addChild(var);
1721
1722               // Add variables originating from field and targeted to timeserie file
1723               if (!var->ts_target.isEmpty()
1724                    && (var->ts_target == CVariable::ts_target_attr::file || var->ts_target == CVariable::ts_target_attr::both))
1725                 tsFile->getVirtualVariableGroup()->addChild(var);
1726             }
1727
[711]1728             tsFile->solveFieldRefInheritance(true);
1729
1730             if (file->timeseries == CFile::timeseries_attr::exclusive)
1731               field->enabled = false;
1732           }
1733         }
1734
1735         // Finally disable the original file is need be
1736         if (file->timeseries == CFile::timeseries_attr::only)
1737          file->enabled = false;
1738       }
1739     }
1740   }
1741
[509]1742   //! Client side: Send information of reference grid of active fields
[1232]1743   void CContext::sendRefGrid(const std::vector<CFile*>& activeFiles)
[509]1744   {
1745     std::set<StdString> gridIds;
[1232]1746     int sizeFile = activeFiles.size();
[509]1747     CFile* filePtr(NULL);
1748
1749     // Firstly, find all reference grids of all active fields
1750     for (int i = 0; i < sizeFile; ++i)
1751     {
[1232]1752       filePtr = activeFiles[i];
[509]1753       std::vector<CField*> enabledFields = filePtr->getEnabledFields();
1754       int sizeField = enabledFields.size();
1755       for (int numField = 0; numField < sizeField; ++numField)
1756       {
1757         if (0 != enabledFields[numField]->getRelGrid())
1758           gridIds.insert(CGrid::get(enabledFields[numField]->getRelGrid())->getId());
1759       }
1760     }
1761
1762     // Create all reference grids on server side
1763     StdString gridDefRoot("grid_definition");
1764     CGridGroup* gridPtr = CGridGroup::get(gridDefRoot);
1765     std::set<StdString>::const_iterator it, itE = gridIds.end();
1766     for (it = gridIds.begin(); it != itE; ++it)
1767     {
1768       gridPtr->sendCreateChild(*it);
1769       CGrid::get(*it)->sendAllAttributesToServer();
[540]1770       CGrid::get(*it)->sendAllDomains();
1771       CGrid::get(*it)->sendAllAxis();
[887]1772       CGrid::get(*it)->sendAllScalars();
[509]1773     }
1774   }
1775
[1232]1776   //! Client side: Send information of reference domain, axis and scalar of active fields
1777   void CContext::sendRefDomainsAxisScalars(const std::vector<CFile*>& activeFiles)
[569]1778   {
[887]1779     std::set<StdString> domainIds, axisIds, scalarIds;
[509]1780
[569]1781     // Find all reference domain and axis of all active fields
[1232]1782     int numEnabledFiles = activeFiles.size();
[569]1783     for (int i = 0; i < numEnabledFiles; ++i)
1784     {
[1232]1785       std::vector<CField*> enabledFields = activeFiles[i]->getEnabledFields();
[569]1786       int numEnabledFields = enabledFields.size();
1787       for (int j = 0; j < numEnabledFields; ++j)
1788       {
[887]1789         const std::vector<StdString>& prDomAxisScalarId = enabledFields[j]->getRefDomainAxisIds();
1790         if ("" != prDomAxisScalarId[0]) domainIds.insert(prDomAxisScalarId[0]);
1791         if ("" != prDomAxisScalarId[1]) axisIds.insert(prDomAxisScalarId[1]);
1792         if ("" != prDomAxisScalarId[2]) scalarIds.insert(prDomAxisScalarId[2]);
[569]1793       }
1794     }
1795
1796     // Create all reference axis on server side
[887]1797     std::set<StdString>::iterator itDom, itAxis, itScalar;
[569]1798     std::set<StdString>::const_iterator itE;
1799
[887]1800     StdString scalarDefRoot("scalar_definition");
1801     CScalarGroup* scalarPtr = CScalarGroup::get(scalarDefRoot);
1802     itE = scalarIds.end();
1803     for (itScalar = scalarIds.begin(); itScalar != itE; ++itScalar)
1804     {
1805       if (!itScalar->empty())
1806       {
1807         scalarPtr->sendCreateChild(*itScalar);
1808         CScalar::get(*itScalar)->sendAllAttributesToServer();
1809       }
1810     }
1811
[569]1812     StdString axiDefRoot("axis_definition");
1813     CAxisGroup* axisPtr = CAxisGroup::get(axiDefRoot);
1814     itE = axisIds.end();
1815     for (itAxis = axisIds.begin(); itAxis != itE; ++itAxis)
1816     {
1817       if (!itAxis->empty())
1818       {
1819         axisPtr->sendCreateChild(*itAxis);
1820         CAxis::get(*itAxis)->sendAllAttributesToServer();
1821       }
1822     }
1823
1824     // Create all reference domains on server side
1825     StdString domDefRoot("domain_definition");
1826     CDomainGroup* domPtr = CDomainGroup::get(domDefRoot);
1827     itE = domainIds.end();
1828     for (itDom = domainIds.begin(); itDom != itE; ++itDom)
1829     {
1830       if (!itDom->empty()) {
1831          domPtr->sendCreateChild(*itDom);
1832          CDomain::get(*itDom)->sendAllAttributesToServer();
1833       }
1834     }
1835   }
1836
[509]1837   //! Update calendar in each time step
[300]1838   void CContext::updateCalendar(int step)
1839   {
[1357]1840      int prevStep = calendar->getStep();
1841
1842      if (prevStep < step)
[639]1843      {
[1358]1844        if (hasClient && !hasServer) // For now we only use server level 1 to read data
1845        {
1846          doPreTimestepOperationsForEnabledReadModeFiles();
1847        }
1848
[1628]1849        //#pragma omp critical (_output)
1850        info(150) << "updateCalendar : before : " << calendar->getCurrentDate() << endl;
[1357]1851        calendar->update(step);
[1628]1852        //#pragma omp critical (_output)
1853        info(150) << "updateCalendar : after : " << calendar->getCurrentDate() << endl;
[1357]1854  #ifdef XIOS_MEMTRACK_LIGHT
[1601]1855        #pragma omp critical (_output)
[1357]1856        info(50) << " Current memory used by XIOS : "<<  MemTrack::getCurrentMemorySize()*1.0/(1024*1024)<<" Mbyte, at timestep "<<step<<" of context "<<this->getId()<<endl ;
1857  #endif
1858
1859        if (hasClient && !hasServer) // For now we only use server level 1 to read data
1860        {
1861          doPostTimestepOperationsForEnabledReadModeFiles();
1862          garbageCollector.invalidate(calendar->getCurrentDate());
1863        }
[639]1864      }
[1357]1865      else if (prevStep == step)
[1601]1866      {
1867        #pragma omp critical (_output)
[1357]1868        info(50) << "updateCalendar: already at step " << step << ", no operation done." << endl;
[1601]1869      }
[1357]1870      else // if (prevStep > step)
1871        ERROR("void CContext::updateCalendar(int step)",
1872              << "Illegal calendar update: previous step was " << prevStep << ", new step " << step << "is in the past!")
[300]1873   }
[509]1874
[1232]1875   void CContext::initReadFiles(void)
1876   {
1877      vector<CFile*>::const_iterator it;
1878
1879      for (it=enabledReadModeFiles.begin(); it != enabledReadModeFiles.end(); it++)
1880      {
1881         (*it)->initRead();
1882      }
1883   }
1884
[509]1885   //! Server side: Create header of netcdf file
[1232]1886   void CContext::createFileHeader(void)
[300]1887   {
[549]1888      vector<CFile*>::const_iterator it;
[509]1889
[300]1890      for (it=enabledFiles.begin(); it != enabledFiles.end(); it++)
[1232]1891      // for (it=enabledWriteModeFiles.begin(); it != enabledWriteModeFiles.end(); it++)
[300]1892      {
[1232]1893         (*it)->initWrite();
[300]1894      }
[509]1895   }
1896
1897   //! Get current context
[347]1898   CContext* CContext::getCurrent(void)
[300]1899   {
[549]1900     return CObjectFactory::GetObject<CContext>(CObjectFactory::GetCurrentContextId()).get();
[300]1901   }
[509]1902
1903   /*!
1904   \brief Set context with an id be the current context
1905   \param [in] id identity of context to be set to current
1906   */
[346]1907   void CContext::setCurrent(const string& id)
1908   {
1909     CObjectFactory::SetCurrentContextId(id);
1910     CGroupFactory::SetCurrentContextId(id);
1911   }
[509]1912
1913  /*!
1914  \brief Create a context with specific id
1915  \param [in] id identity of new context
1916  \return pointer to the new context or already-existed one with identity id
1917  */
[347]1918  CContext* CContext::create(const StdString& id)
[346]1919  {
[549]1920    CContext::setCurrent(id);
[509]1921
[346]1922    bool hasctxt = CContext::has(id);
[347]1923    CContext* context = CObjectFactory::CreateObject<CContext>(id).get();
[549]1924    getRoot();
[1601]1925    if (!hasctxt) CGroupFactory::AddChild(*root_ptr, context->getShared());
[346]1926
1927#define DECLARE_NODE(Name_, name_) \
1928    C##Name_##Definition::create(C##Name_##Definition::GetDefName());
1929#define DECLARE_NODE_PAR(Name_, name_)
1930#include "node_type.conf"
1931
1932    return (context);
1933  }
[697]1934
1935
1936     //! Server side: Receive a message to do some post processing
1937  void CContext::recvRegistry(CEventServer& event)
1938  {
1939    CBufferIn* buffer=event.subEvents.begin()->buffer;
1940    string id;
1941    *buffer>>id;
1942    get(id)->recvRegistry(*buffer);
1943  }
1944
1945  void CContext::recvRegistry(CBufferIn& buffer)
1946  {
1947    if (server->intraCommRank==0)
1948    {
1949      CRegistry registry(server->intraComm) ;
1950      registry.fromBuffer(buffer) ;
1951      registryOut->mergeRegistry(registry) ;
1952    }
1953  }
1954
1955  void CContext::sendRegistry(void)
[1158]1956  {
[697]1957    registryOut->hierarchicalGatherRegistry() ;
1958
[1009]1959    // Use correct context client to send message
[1030]1960    int nbSrvPools = (this->hasServer) ? (this->hasClient ? this->clientPrimServer.size() : 0) : 1;
[1009]1961    for (int i = 0; i < nbSrvPools; ++i)
1962    {
1963      CContextClient* contextClientTmp = (hasServer) ? clientPrimServer[i] : client;
1964      CEventClient event(CContext::GetType(), CContext::EVENT_ID_SEND_REGISTRY);
[1021]1965        if (contextClientTmp->isServerLeader())
[1009]1966        {
1967           CMessage msg ;
1968           if (hasServer)
1969             msg<<this->getIdServer(i);
1970           else
1971             msg<<this->getIdServer();
1972           if (contextClientTmp->clientRank==0) msg<<*registryOut ;
[1021]1973           const std::list<int>& ranks = contextClientTmp->getRanksServerLeader();
[1009]1974           for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
1975             event.push(*itRank,1,msg);
1976           contextClientTmp->sendEvent(event);
1977         }
1978         else contextClientTmp->sendEvent(event);
1979    }
[697]1980  }
1981
[1130]1982  /*!
1983  * \fn bool CContext::isFinalized(void)
[1139]1984  * Context is finalized if it received context post finalize event.
[1130]1985  */
[1054]1986  bool CContext::isFinalized(void)
1987  {
[1139]1988    return finalized;
[1054]1989  }
1990
[335]1991} // namespace xios
Note: See TracBrowser for help on using the repository browser.