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

Last change on this file since 1538 was 1538, checked in by yushan, 3 years ago

tests in XIOS OK (client, complete, remap, toy)

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