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

Last change on this file since 1468 was 1468, checked in by yushan, 6 years ago

tests (client, complete, toy, rempa) work fine with 2-level server mode. Tested on ADA (2*2+2)

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