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

Last change on this file since 1235 was 1232, checked in by mhnguyen, 7 years ago

Fixing the blocking problem where there are more servers than the number of grid band distribution

+) Correct this problem not only for writing but also for reading
+) Allow "zero-size" domain, axis (i.e: domain, axis with ni = 0, and/or nj=0)

Test
+) On Curie
+) Work in both cases: Read and Write data

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