source: XIOS2/trunk/src/node/context.cpp @ 2428

Last change on this file since 2428 was 2428, checked in by jderouillat, 17 months ago

Backport the XIOS3 system to log the memory consumption (commit ID [2418-2420,2425-2426])

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