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

Last change on this file since 1491 was 1491, checked in by yushan, 3 years ago

Branch EP merged with Dev_cmip6 @r1490

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