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

Last change on this file since 1237 was 1237, checked in by mhnguyen, 5 years ago

Fixing a minor bug on using same grid for reading and writing

+) Make sure all grid (for reading and writing) sent to servers

Test
+) On Curie
+) Work with 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: 63.2 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      // We have all info of domain, axis and scalar, so 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->enabledFiles);
567      // This code may be useful in the future when we want to seperate completely read and write
568      // sendRefGrid(this->enabledWriteModeFiles);
569      // if (!hasServer)
570      //   sendRefGrid(this->enabledReadModeFiles);
571
572       // We have a xml tree on the server side and now, it should be also processed
573       sendPostProcessing();
574       
575       sendGridEnabledFieldsInFiles(this->enabledWriteModeFiles);       
576       if (!hasServer)
577        sendGridEnabledFieldsInFiles(this->enabledReadModeFiles);       
578     }
579     allProcessed = true;
580   }
581
582   void CContext::sendPostProcessingGlobalAttributes()
583   {
584      // Use correct context client to send message
585     // int nbSrvPools = (hasServer) ? clientPrimServer.size() : 1;
586    int nbSrvPools = (this->hasServer) ? (this->hasClient ? this->clientPrimServer.size() : 0) : 1;
587     for (int i = 0; i < nbSrvPools; ++i)
588     {
589       CContextClient* contextClientTmp = (0 != clientPrimServer.size()) ? clientPrimServer[i] : client;
590       CEventClient event(getType(),EVENT_ID_POST_PROCESS_GLOBAL_ATTRIBUTES);
591
592       if (contextClientTmp->isServerLeader())
593       {
594         CMessage msg;
595         if (hasServer)
596           msg<<this->getIdServer(i);
597         else
598           msg<<this->getIdServer();
599         const std::list<int>& ranks = contextClientTmp->getRanksServerLeader();
600         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
601           event.push(*itRank,1,msg);
602         contextClientTmp->sendEvent(event);
603       }
604       else contextClientTmp->sendEvent(event);
605     }
606   }
607
608   void CContext::recvPostProcessingGlobalAttributes(CEventServer& event)
609   {
610      CBufferIn* buffer=event.subEvents.begin()->buffer;
611      string id;
612      *buffer>>id;
613      get(id)->recvPostProcessingGlobalAttributes(*buffer);
614   }
615
616   void CContext::recvPostProcessingGlobalAttributes(CBufferIn& buffer)
617   {     
618      postProcessingGlobalAttributes();
619   }
620
621   /*!
622   \brief Close all the context defintion and do processing data
623      After everything is well defined on client side, they will be processed and sent to server
624   From the version 2.0, sever and client work no more on the same database. Moreover, client(s) will send
625   all necessary information to server, from which each server can build its own database.
626   Because the role of server is to write out field data on a specific netcdf file,
627   the only information that it needs is the enabled files
628   and the active fields (fields will be written onto active files)
629   */
630   void CContext::closeDefinition(void)
631   {
632    CTimer::get("Context : close definition").resume() ;
633    postProcessingGlobalAttributes();
634
635    if (hasClient) sendPostProcessingGlobalAttributes();
636
637    // There are some processings that should be done after all of above. For example: check mask or index
638    this->buildFilterGraphOfEnabledFields();
639   
640     if (hasClient && !hasServer)
641    {
642      buildFilterGraphOfFieldsWithReadAccess();
643    }
644   
645    checkGridEnabledFields();   
646
647    if (hasClient) this->sendProcessingGridOfEnabledFields();
648    if (hasClient) this->sendCloseDefinition();
649
650    // Nettoyage de l'arborescence
651    if (hasClient) CleanTree(); // Only on client side??
652
653    if (hasClient)
654    {
655      sendCreateFileHeader();
656      if (!hasServer) startPrefetchingOfEnabledReadModeFiles();
657    }
658    CTimer::get("Context : close definition").suspend() ;
659   }
660
661   void CContext::findAllEnabledFieldsInFiles(const std::vector<CFile*>& activeFiles)
662   {
663     for (unsigned int i = 0; i < activeFiles.size(); i++)
664     (void)activeFiles[i]->getEnabledFields();
665   }
666
667   void CContext::readAttributesOfEnabledFieldsInReadModeFiles()
668   {
669      for (unsigned int i = 0; i < this->enabledReadModeFiles.size(); ++i)
670        (void)this->enabledReadModeFiles[i]->readAttributesOfEnabledFieldsInReadMode();
671   }
672
673   /*!
674      Send active (enabled) fields in file from a client to others
675      \param [in] activeFiles files contains enabled fields to send
676   */
677   void CContext::sendGridEnabledFieldsInFiles(const std::vector<CFile*>& activeFiles)
678   {
679     int size = activeFiles.size();
680     for (int i = 0; i < size; ++i)
681     {       
682       activeFiles[i]->sendGridOfEnabledFields();
683     }
684   }
685
686   void CContext::checkGridEnabledFields()
687   {
688     int size = enabledFiles.size();
689     for (int i = 0; i < size; ++i)
690     {
691       enabledFiles[i]->checkGridOfEnabledFields();       
692     }
693   }
694
695   /*!
696      Check grid of active (enabled) fields in file
697      \param [in] activeFiles files contains enabled fields whose grid needs checking
698   */
699   void CContext::checkGridEnabledFieldsInFiles(const std::vector<CFile*>& activeFiles)
700   {
701     int size = activeFiles.size();
702     for (int i = 0; i < size; ++i)
703     {
704       activeFiles[i]->checkGridOfEnabledFields();       
705     }
706   }
707
708    /*!
709      Go up the hierachical tree via field_ref and do check of attributes of fields
710      This can be done in a client then all computed information will be sent from this client to others
711      \param [in] sendToServer Flag to indicate whether calculated information will be sent
712   */
713   void CContext::solveOnlyRefOfEnabledFields(bool sendToServer)
714   {
715     int size = this->enabledFiles.size();
716     for (int i = 0; i < size; ++i)
717     {
718       this->enabledFiles[i]->solveOnlyRefOfEnabledFields(sendToServer);
719     }
720
721     for (int i = 0; i < size; ++i)
722     {
723       this->enabledFiles[i]->generateNewTransformationGridDest();
724     }
725   }
726
727    /*!
728      Go up the hierachical tree via field_ref and do check of attributes of fields.
729      The transformation can be done in this step.
730      All computed information will be sent from this client to others.
731      \param [in] sendToServer Flag to indicate whether calculated information will be sent
732   */
733   void CContext::solveAllRefOfEnabledFieldsAndTransform(bool sendToServer)
734   {
735     int size = this->enabledFiles.size();
736     for (int i = 0; i < size; ++i)
737     {
738       this->enabledFiles[i]->solveAllRefOfEnabledFieldsAndTransform(sendToServer);
739     }
740   }
741
742   void CContext::buildFilterGraphOfEnabledFields()
743   {
744     int size = this->enabledFiles.size();
745     for (int i = 0; i < size; ++i)
746     {
747       this->enabledFiles[i]->buildFilterGraphOfEnabledFields(garbageCollector);
748     }
749   }
750
751   void CContext::startPrefetchingOfEnabledReadModeFiles()
752   {
753     int size = enabledReadModeFiles.size();
754     for (int i = 0; i < size; ++i)
755     {
756        enabledReadModeFiles[i]->prefetchEnabledReadModeFields();
757     }
758   }
759
760   void CContext::checkPrefetchingOfEnabledReadModeFiles()
761   {
762     int size = enabledReadModeFiles.size();
763     for (int i = 0; i < size; ++i)
764     {
765        enabledReadModeFiles[i]->prefetchEnabledReadModeFieldsIfNeeded();
766     }
767   }
768
769  void CContext::findFieldsWithReadAccess(void)
770  {
771    fieldsWithReadAccess.clear();
772    const vector<CField*> allFields = CField::getAll();
773    for (size_t i = 0; i < allFields.size(); ++i)
774    {
775      CField* field = allFields[i];
776
777      if (field->file && !field->file->mode.isEmpty() && field->file->mode == CFile::mode_attr::read)
778        field->read_access = true;
779      else if (!field->read_access.isEmpty() && field->read_access && (field->enabled.isEmpty() || field->enabled))
780        fieldsWithReadAccess.push_back(field);
781    }
782  }
783
784  void CContext::solveAllRefOfFieldsWithReadAccess()
785  {
786    for (size_t i = 0; i < fieldsWithReadAccess.size(); ++i)
787      fieldsWithReadAccess[i]->solveAllReferenceEnabledField(false);
788  }
789
790  void CContext::buildFilterGraphOfFieldsWithReadAccess()
791  {
792    for (size_t i = 0; i < fieldsWithReadAccess.size(); ++i)
793      fieldsWithReadAccess[i]->buildFilterGraph(garbageCollector, true);
794  }
795
796   void CContext::solveAllInheritance(bool apply)
797   {
798     // Résolution des héritages descendants (càd des héritages de groupes)
799     // pour chacun des contextes.
800      solveDescInheritance(apply);
801
802     // Résolution des héritages par référence au niveau des fichiers.
803      const vector<CFile*> allFiles=CFile::getAll();
804      const vector<CGrid*> allGrids= CGrid::getAll();
805
806      if (hasClient && !hasServer)
807      //if (hasClient)
808      {
809        for (unsigned int i = 0; i < allFiles.size(); i++)
810          allFiles[i]->solveFieldRefInheritance(apply);
811      }
812
813      unsigned int vecSize = allGrids.size();
814      unsigned int i = 0;
815      for (i = 0; i < vecSize; ++i)
816        allGrids[i]->solveDomainAxisRefInheritance(apply);
817
818   }
819
820   void CContext::findEnabledFiles(void)
821   {
822      const std::vector<CFile*> allFiles = CFile::getAll();
823      const CDate& initDate = calendar->getInitDate();
824
825      for (unsigned int i = 0; i < allFiles.size(); i++)
826         if (!allFiles[i]->enabled.isEmpty()) // Si l'attribut 'enabled' est défini.
827         {
828            if (allFiles[i]->enabled.getValue()) // Si l'attribut 'enabled' est fixé à vrai.
829            {
830              if ((initDate + allFiles[i]->output_freq.getValue()) < (initDate + this->getCalendar()->getTimeStep()))
831              {
832                error(0)<<"WARNING: void CContext::findEnabledFiles()"<<endl
833                    << "Output frequency in file \""<<allFiles[i]->getFileOutputName()
834                    <<"\" is less than the time step. File will not be written."<<endl;
835              }
836              else
837               enabledFiles.push_back(allFiles[i]);
838            }
839         }
840         else
841         {
842           if ( (initDate + allFiles[i]->output_freq.getValue()) < (initDate + this->getCalendar()->getTimeStep()))
843           {
844             error(0)<<"WARNING: void CContext::findEnabledFiles()"<<endl
845                 << "Output frequency in file \""<<allFiles[i]->getFileOutputName()
846                 <<"\" is less than the time step. File will not be written."<<endl;
847           }
848           else
849             enabledFiles.push_back(allFiles[i]); // otherwise true by default
850         }
851
852      if (enabledFiles.size() == 0)
853         DEBUG(<<"Aucun fichier ne va être sorti dans le contexte nommé \""
854               << getId() << "\" !");
855
856   }
857
858   void CContext::distributeFiles(void)
859   {
860     double eps=std::numeric_limits<double>::epsilon()*10 ;
861     
862     // If primary server
863     if (hasServer && hasClient)
864     {
865       int nbPools = clientPrimServer.size();
866
867       // (1) Find all enabled files in write mode
868       // for (int i = 0; i < this->enabledFiles.size(); ++i)
869       // {
870       //   if (enabledFiles[i]->mode.isEmpty() || (!enabledFiles[i]->mode.isEmpty() && enabledFiles[i]->mode.getValue() == CFile::mode_attr::write ))
871       //    enabledWriteModeFiles.push_back(enabledFiles[i]);
872       // }
873
874       // (2) Estimate the data volume for each file
875       int size = this->enabledWriteModeFiles.size();
876       std::vector<std::pair<double, CFile*> > dataSizeMap;
877       double dataPerPool = 0;
878       int nfield=0 ;
879       for (size_t i = 0; i < size; ++i)
880       {
881         CFile* file = this->enabledWriteModeFiles[i];
882         StdSize dataSize=0;
883         std::vector<CField*> enabledFields = file->getEnabledFields();
884         size_t numEnabledFields = enabledFields.size();
885         for (size_t j = 0; j < numEnabledFields; ++j) dataSize += enabledFields[j]->getGlobalWrittenSize() ;
886
887         double outFreqSec = (Time)(calendar->getCurrentDate()+file->output_freq)-(Time)(calendar->getCurrentDate()) ;
888         double dataSizeSec= dataSize/ outFreqSec;
889         nfield++ ;
890// add epsilon*nField to dataSizeSec in order to  preserve reproductive ordering when sorting
891         dataSizeMap.push_back(make_pair(dataSizeSec + dataSizeSec * eps * nfield , file));
892         dataPerPool += dataSizeSec;
893       }
894       dataPerPool /= nbPools;
895       std::sort(dataSizeMap.begin(), dataSizeMap.end());
896
897       // (3) Assign contextClient to each enabled file
898
899       std::multimap<double,int> poolDataSize ;
900// multimap is not garanty to preserve stable sorting in c++98 but it seems it does for c++11
901
902       int j;
903       double dataSize ;
904       for (j = 0 ; j < nbPools ; ++j) poolDataSize.insert(std::pair<double,int>(0.,j)) ; 
905             
906       for (int i = dataSizeMap.size()-1; i >= 0; --i)
907       {
908         dataSize=(*poolDataSize.begin()).first ;
909         j=(*poolDataSize.begin()).second ;
910         dataSizeMap[i].second->setContextClient(clientPrimServer[j]);
911         dataSize+=dataSizeMap[i].first;
912         poolDataSize.erase(poolDataSize.begin()) ;
913         poolDataSize.insert(std::pair<double,int>(dataSize,j)) ; 
914       }
915
916       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 ;
917 
918       for (int i = 0; i < this->enabledReadModeFiles.size(); ++i)
919       {
920         enabledReadModeFiles[i]->setContextClient(client);         
921       }
922     }
923     else
924     {
925       for (int i = 0; i < this->enabledFiles.size(); ++i)
926         enabledFiles[i]->setContextClient(client);
927     }
928   }
929
930   /*!
931      Find all files in write mode
932   */
933   void CContext::findEnabledWriteModeFiles(void)
934   {
935     int size = this->enabledFiles.size();
936     for (int i = 0; i < size; ++i)
937     {
938       if (enabledFiles[i]->mode.isEmpty() || 
939          (!enabledFiles[i]->mode.isEmpty() && enabledFiles[i]->mode.getValue() == CFile::mode_attr::write ))
940        enabledWriteModeFiles.push_back(enabledFiles[i]);
941     }
942   }
943
944   /*!
945      Find all files in read mode
946   */
947   void CContext::findEnabledReadModeFiles(void)
948   {
949     int size = this->enabledFiles.size();
950     for (int i = 0; i < size; ++i)
951     {
952       if (!enabledFiles[i]->mode.isEmpty() && enabledFiles[i]->mode.getValue() == CFile::mode_attr::read)
953        enabledReadModeFiles.push_back(enabledFiles[i]);
954     }
955   }
956
957   void CContext::closeAllFile(void)
958   {
959     std::vector<CFile*>::const_iterator
960            it = this->enabledFiles.begin(), end = this->enabledFiles.end();
961
962     for (; it != end; it++)
963     {
964       info(30)<<"Closing File : "<<(*it)->getId()<<endl;
965       (*it)->close();
966     }
967   }
968
969   /*!
970   \brief Dispatch event received from client
971      Whenever a message is received in buffer of server, it will be processed depending on
972   its event type. A new event type should be added in the switch list to make sure
973   it processed on server side.
974   \param [in] event: Received message
975   */
976   bool CContext::dispatchEvent(CEventServer& event)
977   {
978
979      if (SuperClass::dispatchEvent(event)) return true;
980      else
981      {
982        switch(event.type)
983        {
984           case EVENT_ID_CLOSE_DEFINITION :
985             recvCloseDefinition(event);
986             return true;
987             break;
988           case EVENT_ID_UPDATE_CALENDAR:
989             recvUpdateCalendar(event);
990             return true;
991             break;
992           case EVENT_ID_CREATE_FILE_HEADER :
993             recvCreateFileHeader(event);
994             return true;
995             break;
996           case EVENT_ID_POST_PROCESS:
997             recvPostProcessing(event);
998             return true;
999            case EVENT_ID_SEND_REGISTRY:
1000             recvRegistry(event);
1001             return true;
1002             break;
1003            case EVENT_ID_POST_PROCESS_GLOBAL_ATTRIBUTES:
1004             recvPostProcessingGlobalAttributes(event);
1005             return true;
1006             break;
1007            case EVENT_ID_PROCESS_GRID_ENABLED_FIELDS:
1008             recvProcessingGridOfEnabledFields(event);
1009             return true;
1010             break;
1011           default :
1012             ERROR("bool CContext::dispatchEvent(CEventServer& event)",
1013                    <<"Unknown Event");
1014           return false;
1015         }
1016      }
1017   }
1018
1019   //! Client side: Send a message to server to make it close
1020   void CContext::sendCloseDefinition(void)
1021   {
1022     // Use correct context client to send message
1023     int nbSrvPools = (this->hasServer) ? (this->hasClient ? this->clientPrimServer.size() : 0) : 1;
1024     for (int i = 0; i < nbSrvPools; ++i)
1025     {
1026       CContextClient* contextClientTmp = (hasServer) ? clientPrimServer[i] : client;
1027       CEventClient event(getType(),EVENT_ID_CLOSE_DEFINITION);
1028       if (contextClientTmp->isServerLeader())
1029       {
1030         CMessage msg;
1031         if (hasServer)
1032           msg<<this->getIdServer(i);
1033         else
1034           msg<<this->getIdServer();
1035         const std::list<int>& ranks = contextClientTmp->getRanksServerLeader();
1036         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
1037           event.push(*itRank,1,msg);
1038         contextClientTmp->sendEvent(event);
1039       }
1040       else contextClientTmp->sendEvent(event);
1041     }
1042   }
1043
1044   //! Server side: Receive a message of client announcing a context close
1045   void CContext::recvCloseDefinition(CEventServer& event)
1046   {
1047      CBufferIn* buffer=event.subEvents.begin()->buffer;
1048      string id;
1049      *buffer>>id;
1050      get(id)->closeDefinition();
1051   }
1052
1053   //! Client side: Send a message to update calendar in each time step
1054   void CContext::sendUpdateCalendar(int step)
1055   {
1056     // Use correct context client to send message
1057    int nbSrvPools = (this->hasServer) ? (this->hasClient ? this->clientPrimServer.size() : 0) : 1;
1058     for (int i = 0; i < nbSrvPools; ++i)
1059     {
1060       CContextClient* contextClientTmp = (hasServer) ? clientPrimServer[i] : client;
1061       CEventClient event(getType(),EVENT_ID_UPDATE_CALENDAR);
1062
1063         if (contextClientTmp->isServerLeader())
1064         {
1065           CMessage msg;
1066           if (hasServer)
1067             msg<<this->getIdServer(i)<<step;
1068           else
1069             msg<<this->getIdServer()<<step;
1070           const std::list<int>& ranks = contextClientTmp->getRanksServerLeader();
1071           for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
1072             event.push(*itRank,1,msg);
1073           contextClientTmp->sendEvent(event);
1074         }
1075         else contextClientTmp->sendEvent(event);
1076     }
1077   }
1078
1079   //! Server side: Receive a message of client annoucing calendar update
1080   void CContext::recvUpdateCalendar(CEventServer& event)
1081   {
1082      CBufferIn* buffer=event.subEvents.begin()->buffer;
1083      string id;
1084      *buffer>>id;
1085      get(id)->recvUpdateCalendar(*buffer);
1086   }
1087
1088   //! Server side: Receive a message of client annoucing calendar update
1089   void CContext::recvUpdateCalendar(CBufferIn& buffer)
1090   {
1091      int step;
1092      buffer>>step;
1093      updateCalendar(step);
1094      if (hasClient && hasServer)
1095      {       
1096        sendUpdateCalendar(step);
1097      }
1098   }
1099
1100   //! Client side: Send a message to create header part of netcdf file
1101   void CContext::sendCreateFileHeader(void)
1102   {
1103     // Use correct context client to send message
1104     // int nbSrvPools = (hasServer) ? clientPrimServer.size() : 1;
1105     int nbSrvPools = (this->hasServer) ? (this->hasClient ? this->clientPrimServer.size() : 0) : 1;
1106     for (int i = 0; i < nbSrvPools; ++i)
1107     {
1108       CContextClient* contextClientTmp = (hasServer) ? clientPrimServer[i] : client;
1109       CEventClient event(getType(),EVENT_ID_CREATE_FILE_HEADER);
1110
1111       if (contextClientTmp->isServerLeader())
1112       {
1113         CMessage msg;
1114         if (hasServer)
1115           msg<<this->getIdServer(i);
1116         else
1117           msg<<this->getIdServer();
1118         const std::list<int>& ranks = contextClientTmp->getRanksServerLeader();
1119         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
1120           event.push(*itRank,1,msg) ;
1121         contextClientTmp->sendEvent(event);
1122       }
1123       else contextClientTmp->sendEvent(event);
1124     }
1125   }
1126
1127   //! Server side: Receive a message of client annoucing the creation of header part of netcdf file
1128   void CContext::recvCreateFileHeader(CEventServer& event)
1129   {
1130      CBufferIn* buffer=event.subEvents.begin()->buffer;
1131      string id;
1132      *buffer>>id;
1133      get(id)->recvCreateFileHeader(*buffer);
1134   }
1135
1136   //! Server side: Receive a message of client annoucing the creation of header part of netcdf file
1137   void CContext::recvCreateFileHeader(CBufferIn& buffer)
1138   {
1139      if (!hasClient && hasServer) 
1140        createFileHeader();
1141   }
1142
1143   //! Client side: Send a message to do some post processing on server
1144   void CContext::sendProcessingGridOfEnabledFields()
1145   {
1146      // Use correct context client to send message
1147     int nbSrvPools = (this->hasServer) ? (this->hasClient ? this->clientPrimServer.size() : 0) : 1;
1148     for (int i = 0; i < nbSrvPools; ++i)
1149     {
1150       CContextClient* contextClientTmp = (0 != clientPrimServer.size()) ? clientPrimServer[i] : client;
1151       CEventClient event(getType(),EVENT_ID_PROCESS_GRID_ENABLED_FIELDS);
1152
1153       if (contextClientTmp->isServerLeader())
1154       {
1155         CMessage msg;
1156         if (hasServer)
1157           msg<<this->getIdServer(i);
1158         else
1159           msg<<this->getIdServer();
1160         const std::list<int>& ranks = contextClientTmp->getRanksServerLeader();
1161         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
1162           event.push(*itRank,1,msg);
1163         contextClientTmp->sendEvent(event);
1164       }
1165       else contextClientTmp->sendEvent(event);
1166     }
1167   }
1168
1169   //! Server side: Receive a message to do some post processing
1170   void CContext::recvProcessingGridOfEnabledFields(CEventServer& event)
1171   {
1172      CBufferIn* buffer=event.subEvents.begin()->buffer;
1173      string id;
1174      *buffer>>id;     
1175   }
1176
1177   //! Client side: Send a message to do some post processing on server
1178   void CContext::sendPostProcessing()
1179   {
1180      // Use correct context client to send message
1181     // int nbSrvPools = (hasServer) ? clientPrimServer.size() : 1;
1182     int nbSrvPools = (this->hasServer) ? (this->hasClient ? this->clientPrimServer.size() : 0) : 1;
1183     for (int i = 0; i < nbSrvPools; ++i)
1184     {
1185       CContextClient* contextClientTmp = (hasServer) ? clientPrimServer[i] : client;
1186       CEventClient event(getType(),EVENT_ID_POST_PROCESS);
1187       if (contextClientTmp->isServerLeader())
1188       {
1189         CMessage msg;
1190         if (hasServer)
1191           msg<<this->getIdServer(i);
1192         else
1193           msg<<this->getIdServer();
1194         const std::list<int>& ranks = contextClientTmp->getRanksServerLeader();
1195         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
1196         event.push(*itRank,1,msg);
1197         contextClientTmp->sendEvent(event);
1198       }
1199       else contextClientTmp->sendEvent(event);
1200     }
1201   }
1202
1203   //! Server side: Receive a message to do some post processing
1204   void CContext::recvPostProcessing(CEventServer& event)
1205   {
1206      CBufferIn* buffer=event.subEvents.begin()->buffer;
1207      string id;
1208      *buffer>>id;
1209      get(id)->recvPostProcessing(*buffer);
1210   }
1211
1212   //! Server side: Receive a message to do some post processing
1213   void CContext::recvPostProcessing(CBufferIn& buffer)
1214   {
1215      CCalendarWrapper::get(CCalendarWrapper::GetDefName())->createCalendar();
1216      postProcessing();
1217   }
1218
1219   const StdString& CContext::getIdServer()
1220   {
1221      if (hasClient)
1222      {
1223        idServer_ = this->getId();
1224        idServer_ += "_server";
1225        return idServer_;
1226      }
1227      if (hasServer) return (this->getId());
1228   }
1229
1230   const StdString& CContext::getIdServer(const int i)
1231   {
1232     idServer_ = this->getId();
1233     idServer_ += "_server_";
1234     idServer_ += boost::lexical_cast<string>(i);
1235     return idServer_;
1236   }
1237
1238
1239   /*!
1240   \brief Do some simple post processings after parsing xml file
1241      After the xml file (iodef.xml) is parsed, it is necessary to build all relations among
1242   created object, e.g: inhertance among fields, domain, axis. After that, all fiels as well as their parents (reference fields),
1243   which will be written out into netcdf files, are processed
1244   */
1245   void CContext::postProcessing()
1246   {
1247     if (isPostProcessed) return;
1248
1249      // Make sure the calendar was correctly created
1250      if (!calendar)
1251        ERROR("CContext::postProcessing()", << "A calendar must be defined for the context \"" << getId() << "!\"")
1252      else if (calendar->getTimeStep() == NoneDu)
1253        ERROR("CContext::postProcessing()", << "A timestep must be defined for the context \"" << getId() << "!\"")
1254      // Calendar first update to set the current date equals to the start date
1255      calendar->update(0);
1256
1257      // Find all inheritance in xml structure
1258      this->solveAllInheritance();
1259
1260//      ShowTree(info(10));
1261
1262      // Check if some axis, domains or grids are eligible to for compressed indexed output.
1263      // Warning: This must be done after solving the inheritance and before the rest of post-processing
1264      checkAxisDomainsGridsEligibilityForCompressedOutput();     
1265
1266      // Check if some automatic time series should be generated
1267      // Warning: This must be done after solving the inheritance and before the rest of post-processing     
1268
1269      // The timeseries should only be prepared in client
1270      if (hasClient && !hasServer) prepareTimeseries();
1271
1272      //Initialisation du vecteur 'enabledFiles' contenant la liste des fichiers à sortir.
1273      findEnabledFiles();
1274      findEnabledWriteModeFiles();
1275      findEnabledReadModeFiles();
1276
1277      // For now, only read files with client and only one level server
1278      // if (hasClient && !hasServer) findEnabledReadModeFiles();     
1279
1280      // Find all enabled fields of each file     
1281      findAllEnabledFieldsInFiles(this->enabledWriteModeFiles);
1282      findAllEnabledFieldsInFiles(this->enabledReadModeFiles);
1283
1284      // For now, only read files with client and only one level server
1285      // if (hasClient && !hasServer)
1286      //   findAllEnabledFieldsInFiles(this->enabledReadModeFiles);     
1287
1288      if (hasClient && !hasServer)
1289      {
1290        initReadFiles();
1291        // Try to read attributes of fields in file then fill in corresponding grid (or domain, axis)
1292        this->readAttributesOfEnabledFieldsInReadModeFiles();
1293      }
1294
1295      // Only search and rebuild all reference objects of enable fields, don't transform
1296      this->solveOnlyRefOfEnabledFields(false);
1297
1298      // Search and rebuild all reference object of enabled fields, and transform
1299      this->solveAllRefOfEnabledFieldsAndTransform(false);
1300
1301      // Find all fields with read access from the public API
1302      if (hasClient && !hasServer) findFieldsWithReadAccess();
1303      // and solve the all reference for them
1304      if (hasClient && !hasServer) solveAllRefOfFieldsWithReadAccess();
1305
1306      isPostProcessed = true;
1307   }
1308
1309   /*!
1310    * Compute the required buffer size to send the attributes (mostly those grid related).
1311    *
1312    * \param maxEventSize [in/out] the size of the bigger event for each connected server
1313    */
1314   std::map<int, StdSize> CContext::getAttributesBufferSize(std::map<int, StdSize>& maxEventSize, CContextClient* contextClient)
1315   {
1316     std::map<int, StdSize> attributesSize;
1317
1318     if (hasClient)
1319     {
1320       size_t numEnabledFiles = this->enabledWriteModeFiles.size();
1321       for (size_t i = 0; i < numEnabledFiles; ++i)
1322       {
1323         CFile* file = this->enabledWriteModeFiles[i];
1324         // if (file->getContextClient() == contextClient)
1325         {
1326           std::vector<CField*> enabledFields = file->getEnabledFields();
1327           size_t numEnabledFields = enabledFields.size();
1328           for (size_t j = 0; j < numEnabledFields; ++j)
1329           {
1330             const std::map<int, StdSize> mapSize = enabledFields[j]->getGridAttributesBufferSize(contextClient);
1331             std::map<int, StdSize>::const_iterator it = mapSize.begin(), itE = mapSize.end();
1332             for (; it != itE; ++it)
1333             {
1334               // If attributesSize[it->first] does not exist, it will be zero-initialized
1335               // so we can use it safely without checking for its existance
1336               if (attributesSize[it->first] < it->second)
1337                 attributesSize[it->first] = it->second;
1338
1339               if (maxEventSize[it->first] < it->second)
1340                 maxEventSize[it->first] = it->second;
1341             }
1342           }
1343         }
1344       }
1345
1346      // Not a good approach here, duplicate code
1347       if (!hasServer)
1348       {
1349         size_t numEnabledFiles = this->enabledReadModeFiles.size();
1350         for (size_t i = 0; i < numEnabledFiles; ++i)
1351         {
1352           CFile* file = this->enabledReadModeFiles[i]; 
1353           {
1354             std::vector<CField*> enabledFields = file->getEnabledFields();
1355             size_t numEnabledFields = enabledFields.size();
1356             for (size_t j = 0; j < numEnabledFields; ++j)
1357             {
1358               const std::map<int, StdSize> mapSize = enabledFields[j]->getGridAttributesBufferSize(contextClient);
1359               std::map<int, StdSize>::const_iterator it = mapSize.begin(), itE = mapSize.end();
1360               for (; it != itE; ++it)
1361               {
1362                 // If attributesSize[it->first] does not exist, it will be zero-initialized
1363                 // so we can use it safely without checking for its existance
1364                 if (attributesSize[it->first] < it->second)
1365                   attributesSize[it->first] = it->second;
1366
1367                 if (maxEventSize[it->first] < it->second)
1368                   maxEventSize[it->first] = it->second;
1369               }
1370             }
1371           }
1372         }
1373       }
1374     }
1375
1376     return attributesSize;
1377   }
1378
1379   /*!
1380    * Compute the required buffer size to send the fields data.
1381    *
1382    * \param maxEventSize [in/out] the size of the bigger event for each connected server
1383    */
1384   std::map<int, StdSize> CContext::getDataBufferSize(std::map<int, StdSize>& maxEventSize, CContextClient* contextClient)
1385   {
1386     CFile::mode_attr::t_enum mode = hasClient ? CFile::mode_attr::write : CFile::mode_attr::read;
1387
1388     std::map<int, StdSize> dataSize;
1389
1390     // Find all reference domain and axis of all active fields
1391     size_t numEnabledFiles = this->enabledFiles.size();
1392     for (size_t i = 0; i < numEnabledFiles; ++i)
1393     {
1394       CFile* file = this->enabledFiles[i];
1395       if (file->getContextClient() == contextClient)
1396       {
1397         CFile::mode_attr::t_enum fileMode = file->mode.isEmpty() ? CFile::mode_attr::write : file->mode.getValue();
1398
1399         if (fileMode == mode)
1400         {
1401           std::vector<CField*> enabledFields = file->getEnabledFields();
1402           size_t numEnabledFields = enabledFields.size();
1403           for (size_t j = 0; j < numEnabledFields; ++j)
1404           {
1405             // const std::vector<std::map<int, StdSize> > mapSize = enabledFields[j]->getGridDataBufferSize(contextClient);
1406            const std::map<int, StdSize> mapSize = enabledFields[j]->getGridDataBufferSize(contextClient);
1407             // for (size_t c = 0; c < mapSize.size(); ++c)
1408             // {
1409               std::map<int, StdSize>::const_iterator it = mapSize.begin(), itE = mapSize.end();
1410               for (; it != itE; ++it)
1411               {
1412                 // If dataSize[it->first] does not exist, it will be zero-initialized
1413                 // so we can use it safely without checking for its existance
1414                 if (CXios::isOptPerformance)
1415                   dataSize[it->first] += it->second;
1416                 else if (dataSize[it->first] < it->second)
1417                   dataSize[it->first] = it->second;
1418
1419                 if (maxEventSize[it->first] < it->second)
1420                   maxEventSize[it->first] = it->second;
1421               }
1422             // }
1423           }
1424         }
1425       }
1426     }
1427
1428     return dataSize;
1429   }
1430
1431   //! Client side: Send infomation of active files (files are enabled to write out)
1432   void CContext::sendEnabledFiles(const std::vector<CFile*>& activeFiles)
1433   {
1434     int size = activeFiles.size();
1435
1436     // In a context, each type has a root definition, e.g: axis, domain, field.
1437     // Every object must be a child of one of these root definition. In this case
1438     // all new file objects created on server must be children of the root "file_definition"
1439     StdString fileDefRoot("file_definition");
1440     CFileGroup* cfgrpPtr = CFileGroup::get(fileDefRoot);
1441
1442     for (int i = 0; i < size; ++i)
1443     {
1444       CFile* f = activeFiles[i];
1445       cfgrpPtr->sendCreateChild(f->getId(),f->getContextClient());
1446       f->sendAllAttributesToServer(f->getContextClient());
1447       f->sendAddAllVariables(f->getContextClient());
1448     }
1449   }
1450
1451   //! Client side: Send information of active fields (ones are written onto files)
1452   void CContext::sendEnabledFieldsInFiles(const std::vector<CFile*>& activeFiles)
1453   {
1454     int size = activeFiles.size();
1455     for (int i = 0; i < size; ++i)
1456     {
1457       activeFiles[i]->sendEnabledFields(activeFiles[i]->getContextClient());
1458     }
1459   }
1460
1461   //! Client side: Check if the defined axis, domains and grids are eligible for compressed indexed output
1462   void CContext::checkAxisDomainsGridsEligibilityForCompressedOutput()
1463   {
1464     if (!hasClient) return;
1465
1466     const vector<CAxis*> allAxis = CAxis::getAll();
1467     for (vector<CAxis*>::const_iterator it = allAxis.begin(); it != allAxis.end(); it++)
1468       (*it)->checkEligibilityForCompressedOutput();
1469
1470     const vector<CDomain*> allDomains = CDomain::getAll();
1471     for (vector<CDomain*>::const_iterator it = allDomains.begin(); it != allDomains.end(); it++)
1472       (*it)->checkEligibilityForCompressedOutput();
1473
1474     const vector<CGrid*> allGrids = CGrid::getAll();
1475     for (vector<CGrid*>::const_iterator it = allGrids.begin(); it != allGrids.end(); it++)
1476       (*it)->checkEligibilityForCompressedOutput();
1477   }
1478
1479   //! Client side: Prepare the timeseries by adding the necessary files
1480   void CContext::prepareTimeseries()
1481   {
1482     if (!hasClient) return;
1483
1484     const std::vector<CFile*> allFiles = CFile::getAll();
1485     for (size_t i = 0; i < allFiles.size(); i++)
1486     {
1487       CFile* file = allFiles[i];
1488
1489       std::vector<CVariable*> fileVars, fieldVars, vars = file->getAllVariables();
1490       for (size_t k = 0; k < vars.size(); k++)
1491       {
1492         CVariable* var = vars[k];
1493
1494         if (var->ts_target.isEmpty()
1495              || var->ts_target == CVariable::ts_target_attr::file || var->ts_target == CVariable::ts_target_attr::both)
1496           fileVars.push_back(var);
1497
1498         if (!var->ts_target.isEmpty()
1499              && (var->ts_target == CVariable::ts_target_attr::field || var->ts_target == CVariable::ts_target_attr::both))
1500           fieldVars.push_back(var);
1501       }
1502
1503       if (!file->timeseries.isEmpty() && file->timeseries != CFile::timeseries_attr::none)
1504       {
1505         StdString fileNameStr("%file_name%") ;
1506         StdString tsPrefix = !file->ts_prefix.isEmpty() ? file->ts_prefix : fileNameStr ;
1507         
1508         StdString fileName=file->getFileOutputName();
1509         size_t pos=tsPrefix.find(fileNameStr) ;
1510         while (pos!=std::string::npos)
1511         {
1512           tsPrefix=tsPrefix.replace(pos,fileNameStr.size(),fileName) ;
1513           pos=tsPrefix.find(fileNameStr) ;
1514         }
1515       
1516         const std::vector<CField*> allFields = file->getAllFields();
1517         for (size_t j = 0; j < allFields.size(); j++)
1518         {
1519           CField* field = allFields[j];
1520
1521           if (!field->ts_enabled.isEmpty() && field->ts_enabled)
1522           {
1523             CFile* tsFile = CFile::create();
1524             tsFile->duplicateAttributes(file);
1525
1526             // Add variables originating from file and targeted to timeserie file
1527             for (size_t k = 0; k < fileVars.size(); k++)
1528               tsFile->getVirtualVariableGroup()->addChild(fileVars[k]);
1529
1530           
1531             tsFile->name = tsPrefix + "_";
1532             if (!field->name.isEmpty())
1533               tsFile->name.get() += field->name;
1534             else if (field->hasDirectFieldReference()) // We cannot use getBaseFieldReference() just yet
1535               tsFile->name.get() += field->field_ref;
1536             else
1537               tsFile->name.get() += field->getId();
1538
1539             if (!field->ts_split_freq.isEmpty())
1540               tsFile->split_freq = field->ts_split_freq;
1541
1542             CField* tsField = tsFile->addField();
1543             tsField->field_ref = field->getId();
1544
1545             // Add variables originating from file and targeted to timeserie field
1546             for (size_t k = 0; k < fieldVars.size(); k++)
1547               tsField->getVirtualVariableGroup()->addChild(fieldVars[k]);
1548
1549             vars = field->getAllVariables();
1550             for (size_t k = 0; k < vars.size(); k++)
1551             {
1552               CVariable* var = vars[k];
1553
1554               // Add variables originating from field and targeted to timeserie field
1555               if (var->ts_target.isEmpty()
1556                    || var->ts_target == CVariable::ts_target_attr::field || var->ts_target == CVariable::ts_target_attr::both)
1557                 tsField->getVirtualVariableGroup()->addChild(var);
1558
1559               // Add variables originating from field and targeted to timeserie file
1560               if (!var->ts_target.isEmpty()
1561                    && (var->ts_target == CVariable::ts_target_attr::file || var->ts_target == CVariable::ts_target_attr::both))
1562                 tsFile->getVirtualVariableGroup()->addChild(var);
1563             }
1564
1565             tsFile->solveFieldRefInheritance(true);
1566
1567             if (file->timeseries == CFile::timeseries_attr::exclusive)
1568               field->enabled = false;
1569           }
1570         }
1571
1572         // Finally disable the original file is need be
1573         if (file->timeseries == CFile::timeseries_attr::only)
1574          file->enabled = false;
1575       }
1576     }
1577   }
1578
1579   //! Client side: Send information of reference grid of active fields
1580   void CContext::sendRefGrid(const std::vector<CFile*>& activeFiles)
1581   {
1582     std::set<StdString> gridIds;
1583     int sizeFile = activeFiles.size();
1584     CFile* filePtr(NULL);
1585
1586     // Firstly, find all reference grids of all active fields
1587     for (int i = 0; i < sizeFile; ++i)
1588     {
1589       filePtr = activeFiles[i];
1590       std::vector<CField*> enabledFields = filePtr->getEnabledFields();
1591       int sizeField = enabledFields.size();
1592       for (int numField = 0; numField < sizeField; ++numField)
1593       {
1594         if (0 != enabledFields[numField]->getRelGrid())
1595           gridIds.insert(CGrid::get(enabledFields[numField]->getRelGrid())->getId());
1596       }
1597     }
1598
1599     // Create all reference grids on server side
1600     StdString gridDefRoot("grid_definition");
1601     CGridGroup* gridPtr = CGridGroup::get(gridDefRoot);
1602     std::set<StdString>::const_iterator it, itE = gridIds.end();
1603     for (it = gridIds.begin(); it != itE; ++it)
1604     {
1605       gridPtr->sendCreateChild(*it);
1606       CGrid::get(*it)->sendAllAttributesToServer();
1607       CGrid::get(*it)->sendAllDomains();
1608       CGrid::get(*it)->sendAllAxis();
1609       CGrid::get(*it)->sendAllScalars();
1610     }
1611   }
1612
1613   //! Client side: Send information of reference domain, axis and scalar of active fields
1614   void CContext::sendRefDomainsAxisScalars(const std::vector<CFile*>& activeFiles)
1615   {
1616     std::set<StdString> domainIds, axisIds, scalarIds;
1617
1618     // Find all reference domain and axis of all active fields
1619     int numEnabledFiles = activeFiles.size();
1620     for (int i = 0; i < numEnabledFiles; ++i)
1621     {
1622       std::vector<CField*> enabledFields = activeFiles[i]->getEnabledFields();
1623       int numEnabledFields = enabledFields.size();
1624       for (int j = 0; j < numEnabledFields; ++j)
1625       {
1626         const std::vector<StdString>& prDomAxisScalarId = enabledFields[j]->getRefDomainAxisIds();
1627         if ("" != prDomAxisScalarId[0]) domainIds.insert(prDomAxisScalarId[0]);
1628         if ("" != prDomAxisScalarId[1]) axisIds.insert(prDomAxisScalarId[1]);
1629         if ("" != prDomAxisScalarId[2]) scalarIds.insert(prDomAxisScalarId[2]);
1630       }
1631     }
1632
1633     // Create all reference axis on server side
1634     std::set<StdString>::iterator itDom, itAxis, itScalar;
1635     std::set<StdString>::const_iterator itE;
1636
1637     StdString scalarDefRoot("scalar_definition");
1638     CScalarGroup* scalarPtr = CScalarGroup::get(scalarDefRoot);
1639     itE = scalarIds.end();
1640     for (itScalar = scalarIds.begin(); itScalar != itE; ++itScalar)
1641     {
1642       if (!itScalar->empty())
1643       {
1644         scalarPtr->sendCreateChild(*itScalar);
1645         CScalar::get(*itScalar)->sendAllAttributesToServer();
1646       }
1647     }
1648
1649     StdString axiDefRoot("axis_definition");
1650     CAxisGroup* axisPtr = CAxisGroup::get(axiDefRoot);
1651     itE = axisIds.end();
1652     for (itAxis = axisIds.begin(); itAxis != itE; ++itAxis)
1653     {
1654       if (!itAxis->empty())
1655       {
1656         axisPtr->sendCreateChild(*itAxis);
1657         CAxis::get(*itAxis)->sendAllAttributesToServer();
1658       }
1659     }
1660
1661     // Create all reference domains on server side
1662     StdString domDefRoot("domain_definition");
1663     CDomainGroup* domPtr = CDomainGroup::get(domDefRoot);
1664     itE = domainIds.end();
1665     for (itDom = domainIds.begin(); itDom != itE; ++itDom)
1666     {
1667       if (!itDom->empty()) {
1668          domPtr->sendCreateChild(*itDom);
1669          CDomain::get(*itDom)->sendAllAttributesToServer();
1670       }
1671     }
1672   }
1673
1674   //! Update calendar in each time step
1675   void CContext::updateCalendar(int step)
1676   {
1677      info(50) << "updateCalendar : before : " << calendar->getCurrentDate() << endl;
1678      calendar->update(step);
1679      info(50) << "updateCalendar : after : " << calendar->getCurrentDate() << endl;
1680#ifdef XIOS_MEMTRACK_LIGHT
1681      info(50) << " Current memory used by XIOS : "<<  MemTrack::getCurrentMemorySize()*1.0/(1024*1024)<<" Mbyte, at timestep "<<step<<" of context "<<this->getId()<<endl ;
1682#endif
1683      //if (hasClient)
1684      if (hasClient && !hasServer) // For now we only use server level 1 to read data
1685      {
1686        checkPrefetchingOfEnabledReadModeFiles();
1687        garbageCollector.invalidate(calendar->getCurrentDate());
1688      }
1689   }
1690
1691   void CContext::initReadFiles(void)
1692   {
1693      vector<CFile*>::const_iterator it;
1694
1695      for (it=enabledReadModeFiles.begin(); it != enabledReadModeFiles.end(); it++)
1696      {
1697         (*it)->initRead();
1698      }
1699   }
1700
1701   //! Server side: Create header of netcdf file
1702   void CContext::createFileHeader(void)
1703   {
1704      vector<CFile*>::const_iterator it;
1705
1706      for (it=enabledFiles.begin(); it != enabledFiles.end(); it++)
1707      // for (it=enabledWriteModeFiles.begin(); it != enabledWriteModeFiles.end(); it++)
1708      {
1709         (*it)->initWrite();
1710      }
1711   }
1712
1713   //! Get current context
1714   CContext* CContext::getCurrent(void)
1715   {
1716     return CObjectFactory::GetObject<CContext>(CObjectFactory::GetCurrentContextId()).get();
1717   }
1718
1719   /*!
1720   \brief Set context with an id be the current context
1721   \param [in] id identity of context to be set to current
1722   */
1723   void CContext::setCurrent(const string& id)
1724   {
1725     CObjectFactory::SetCurrentContextId(id);
1726     CGroupFactory::SetCurrentContextId(id);
1727   }
1728
1729  /*!
1730  \brief Create a context with specific id
1731  \param [in] id identity of new context
1732  \return pointer to the new context or already-existed one with identity id
1733  */
1734  CContext* CContext::create(const StdString& id)
1735  {
1736    CContext::setCurrent(id);
1737
1738    bool hasctxt = CContext::has(id);
1739    CContext* context = CObjectFactory::CreateObject<CContext>(id).get();
1740    getRoot();
1741    if (!hasctxt) CGroupFactory::AddChild(root, context->getShared());
1742
1743#define DECLARE_NODE(Name_, name_) \
1744    C##Name_##Definition::create(C##Name_##Definition::GetDefName());
1745#define DECLARE_NODE_PAR(Name_, name_)
1746#include "node_type.conf"
1747
1748    return (context);
1749  }
1750
1751
1752     //! Server side: Receive a message to do some post processing
1753  void CContext::recvRegistry(CEventServer& event)
1754  {
1755    CBufferIn* buffer=event.subEvents.begin()->buffer;
1756    string id;
1757    *buffer>>id;
1758    get(id)->recvRegistry(*buffer);
1759  }
1760
1761  void CContext::recvRegistry(CBufferIn& buffer)
1762  {
1763    if (server->intraCommRank==0)
1764    {
1765      CRegistry registry(server->intraComm) ;
1766      registry.fromBuffer(buffer) ;
1767      registryOut->mergeRegistry(registry) ;
1768    }
1769  }
1770
1771  void CContext::sendRegistry(void)
1772  {
1773    registryOut->hierarchicalGatherRegistry() ;
1774
1775    // Use correct context client to send message
1776    int nbSrvPools = (this->hasServer) ? (this->hasClient ? this->clientPrimServer.size() : 0) : 1;
1777    for (int i = 0; i < nbSrvPools; ++i)
1778    {
1779      CContextClient* contextClientTmp = (hasServer) ? clientPrimServer[i] : client;
1780      CEventClient event(CContext::GetType(), CContext::EVENT_ID_SEND_REGISTRY);
1781        if (contextClientTmp->isServerLeader())
1782        {
1783           CMessage msg ;
1784           if (hasServer)
1785             msg<<this->getIdServer(i);
1786           else
1787             msg<<this->getIdServer();
1788           if (contextClientTmp->clientRank==0) msg<<*registryOut ;
1789           const std::list<int>& ranks = contextClientTmp->getRanksServerLeader();
1790           for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
1791             event.push(*itRank,1,msg);
1792           contextClientTmp->sendEvent(event);
1793         }
1794         else contextClientTmp->sendEvent(event);
1795    }
1796  }
1797
1798  /*!
1799  * \fn bool CContext::isFinalized(void)
1800  * Context is finalized if it received context post finalize event.
1801  */
1802  bool CContext::isFinalized(void)
1803  {
1804    return finalized;
1805  }
1806
1807} // namespace xios
Note: See TracBrowser for help on using the repository browser.