source: XIOS/dev/branch_openmp/src/node/context.cpp @ 1538

Last change on this file since 1538 was 1538, checked in by yushan, 6 years ago

tests in XIOS OK (client, complete, remap, toy)

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