source: XIOS/dev/XIOS_DEV_CMIP6/src/node/context.cpp @ 1357

Last change on this file since 1357 was 1357, checked in by rlacroix, 6 years ago

Add some extra checks when switching to the next timestep.

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