source: XIOS/dev/dev_olga/src/node/context.cpp @ 1612

Last change on this file since 1612 was 1612, checked in by oabramkina, 5 years ago

Dev: adding exception handling.

To activate it, compilation flag -DXIOS_EXCEPTION should be added.

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