source: XIOS/dev/dev_ym/XIOS_ONE_SIDED/src/node/context.cpp @ 2326

Last change on this file since 2326 was 1757, checked in by ymipsl, 5 years ago

Implement one sided communication in client/server protocol to avoid dead-lock when some buffer are full.

YM

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