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

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

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

YM

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