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

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

MARK: branch merged with trunk @1660. Test (test_complete, test_remap) on ADA with IntelMPI and _usingEP/_usingMPI as switch.

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