source: XIOS/dev/dev_olga/src/node/context.cpp @ 1208

Last change on this file since 1208 was 1208, checked in by oabramkina, 7 years ago

Two server levels: distibuting files among secondary servers according to the estimated data flux. Tested on Curie.

  • 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: 58.7 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
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 and check that we are above the minimum buffer 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     }
322
323     // Leaders will have to send some control events so ensure there is some room for those in the buffers
324     if (contextClient->isServerLeader())
325     {
326       const std::list<int>& ranks = contextClient->getRanksServerLeader();
327       for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
328       {
329         if (!bufferSize.count(*itRank))
330         {
331           bufferSize[*itRank] = minBufferSize;
332           maxEventSize[*itRank] = minEventSize;
333         }
334       }
335     }
336     contextClient->setBufferSize(bufferSize, maxEventSize);
337
338   }
339
340   //! Verify whether a context is initialized
341   bool CContext::isInitialized(void)
342   {
343     return hasClient;
344   }
345
346   void CContext::initServer(MPI_Comm intraComm, MPI_Comm interComm, CContext* cxtClient /*= 0*/)
347   {
348     hasServer=true;
349     server = new CContextServer(this,intraComm,interComm);
350
351     registryIn=new CRegistry(intraComm);
352     registryIn->setPath(getId()) ;
353     if (server->intraCommRank==0) registryIn->fromFile("xios_registry.bin") ;
354     registryIn->bcastRegistry() ;
355     registryOut=new CRegistry(intraComm) ;
356     registryOut->setPath(getId()) ;
357
358     MPI_Comm intraCommClient, interCommClient;
359     if (cxtClient) // Attached mode
360     {
361       intraCommClient = intraComm;
362       interCommClient = interComm;
363     }
364     else
365     {
366       MPI_Comm_dup(intraComm, &intraCommClient);
367       comms.push_back(intraCommClient);
368       MPI_Comm_dup(interComm, &interCommClient);
369       comms.push_back(interCommClient);
370     }
371     client = new CContextClient(this,intraCommClient,interCommClient, cxtClient);
372   }
373
374   //! Try to send the buffers and receive possible answers
375  bool CContext::checkBuffersAndListen(void)
376  {
377    bool clientReady, serverFinished;
378
379    // Only classical servers are non-blocking
380    if (CServer::serverLevel == 0)
381    {
382      client->checkBuffers();
383      bool hasTmpBufferedEvent = client->hasTemporarilyBufferedEvent();
384      if (hasTmpBufferedEvent)
385        hasTmpBufferedEvent = !client->sendTemporarilyBufferedEvent();
386      // Don't process events if there is a temporarily buffered event
387      return server->eventLoop(!hasTmpBufferedEvent);
388    }
389    else if (CServer::serverLevel == 1)
390    {
391      if (!finalized)
392        client->checkBuffers();
393      bool serverFinished = true;
394      if (!finalized)
395        serverFinished = server->eventLoop();
396      bool serverPrimFinished = true;
397      for (int i = 0; i < clientPrimServer.size(); ++i)
398      {
399        if (!finalized)
400          clientPrimServer[i]->checkBuffers();
401        if (!finalized)
402          serverPrimFinished *= serverPrimServer[i]->eventLoop();
403      }
404      return ( serverFinished && serverPrimFinished);
405    }
406
407    else if (CServer::serverLevel == 2)
408    {
409      client->checkBuffers();
410      return server->eventLoop();
411    }
412  }
413
414   //! Terminate a context
415   void CContext::finalize(void)
416   {
417     // Send registry upon calling the function the first time
418     if (countChildCtx_ == 0)
419       if (hasClient) sendRegistry() ;
420
421     // Client:
422     // (1) blocking send context finalize to its server
423     // (2) blocking receive context finalize from its server
424     // (3) some memory deallocations
425     if (CXios::isClient)
426     {
427       // Make sure that client (model) enters the loop only once
428       if (countChildCtx_ < 1)
429       {
430         ++countChildCtx_;
431
432         client->finalize();
433         while (client->havePendingRequests())
434            client->checkBuffers();
435
436         while (!server->hasFinished())
437           server->eventLoop();
438
439         if (hasServer) // Mode attache
440         {
441           closeAllFile();
442           registryOut->hierarchicalGatherRegistry() ;
443           if (server->intraCommRank==0) CXios::globalRegistry->mergeRegistry(*registryOut) ;
444         }
445
446         //! Deallocate client buffers
447         client->releaseBuffers();
448
449         //! Free internally allocated communicators
450         for (std::list<MPI_Comm>::iterator it = comms.begin(); it != comms.end(); ++it)
451           MPI_Comm_free(&(*it));
452         comms.clear();
453
454         info(20)<<"CContext: Context <"<<getId()<<"> is finalized."<<endl;
455       }
456     }
457     else if (CXios::isServer)
458     {
459       // First context finalize message received from a model
460       // Send context finalize to its child contexts (if any)
461       if (countChildCtx_ == 0)
462         for (int i = 0; i < clientPrimServer.size(); ++i)
463           clientPrimServer[i]->finalize();
464
465       // (Last) context finalized message received
466       if (countChildCtx_ == clientPrimServer.size())
467       {
468         // Blocking send of context finalize message to its client (e.g. primary server or model)
469         client->finalize();
470         bool bufferReleased;
471         do
472         {
473           client->checkBuffers();
474           bufferReleased = !client->havePendingRequests();
475         } while (!bufferReleased);
476         finalized = true;
477
478         if (hasServer && !hasClient)
479         {
480           closeAllFile();
481           registryOut->hierarchicalGatherRegistry() ;
482           if (server->intraCommRank==0) CXios::globalRegistry->mergeRegistry(*registryOut) ;
483         }
484
485         //! Deallocate client buffers
486         client->releaseBuffers();
487         for (int i = 0; i < clientPrimServer.size(); ++i)
488           clientPrimServer[i]->releaseBuffers();
489
490         //! Free internally allocated communicators
491         for (std::list<MPI_Comm>::iterator it = comms.begin(); it != comms.end(); ++it)
492           MPI_Comm_free(&(*it));
493         comms.clear();
494
495         info(20)<<"CContext: Context <"<<getId()<<"> is finalized."<<endl;
496       }
497
498       ++countChildCtx_;
499     }
500   }
501
502   //! Free internally allocated communicators
503   void CContext::freeComms(void)
504   {
505     for (std::list<MPI_Comm>::iterator it = comms.begin(); it != comms.end(); ++it)
506       MPI_Comm_free(&(*it));
507     comms.clear();
508   }
509
510   //! Deallocate buffers allocated by clientContexts
511   void CContext::releaseClientBuffers(void)
512   {
513     client->releaseBuffers();
514     for (int i = 0; i < clientPrimServer.size(); ++i)
515       clientPrimServer[i]->releaseBuffers();
516   }
517
518   void CContext::postProcessingGlobalAttributes()
519   {
520     if (allProcessed) return; 
521     
522     // After xml is parsed, there are some more works with post processing
523     postProcessing();
524
525     // Check grid and calculate its distribution
526     checkGridEnabledFields();   
527
528     // Distribute files between secondary servers according to the data size
529     distributeFiles();
530
531     // Buffer for primary server for connection to client will be allocated by default (to min size)
532     if (CServer::serverLevel != 1)
533       setClientServerBuffer(client);
534     if (hasServer)
535       for (int i = 0; i < clientPrimServer.size(); ++i)
536         setClientServerBuffer(clientPrimServer[i]);
537
538
539     if (hasClient)
540     {
541      // Send all attributes of current context to server
542      this->sendAllAttributesToServer();
543
544      // Send all attributes of current calendar
545      CCalendarWrapper::get(CCalendarWrapper::GetDefName())->sendAllAttributesToServer();
546
547      // We have enough information to send to server
548      // First of all, send all enabled files
549      sendEnabledFiles();
550
551      // Then, send all enabled fields
552      sendEnabledFields();
553
554      // At last, we have all info of domain and axis, then send them
555       sendRefDomainsAxis();
556
557       // After that, send all grid (if any)
558       sendRefGrid();
559
560       // We have a xml tree on the server side and now, it should be also processed
561       sendPostProcessing();
562
563       sendGridEnabledFields();       
564     }
565     allProcessed = true;
566   }
567
568   void CContext::sendPostProcessingGlobalAttributes()
569   {
570      // Use correct context client to send message
571     // int nbSrvPools = (hasServer) ? clientPrimServer.size() : 1;
572    int nbSrvPools = (this->hasServer) ? (this->hasClient ? this->clientPrimServer.size() : 0) : 1;
573     for (int i = 0; i < nbSrvPools; ++i)
574     {
575       CContextClient* contextClientTmp = (0 != clientPrimServer.size()) ? clientPrimServer[i] : client;
576       CEventClient event(getType(),EVENT_ID_POST_PROCESS_GLOBAL_ATTRIBUTES);
577
578       if (contextClientTmp->isServerLeader())
579       {
580         CMessage msg;
581         if (hasServer)
582           msg<<this->getIdServer(i);
583         else
584           msg<<this->getIdServer();
585         const std::list<int>& ranks = contextClientTmp->getRanksServerLeader();
586         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
587           event.push(*itRank,1,msg);
588         contextClientTmp->sendEvent(event);
589       }
590       else contextClientTmp->sendEvent(event);
591     }
592   }
593
594   void CContext::recvPostProcessingGlobalAttributes(CEventServer& event)
595   {
596      CBufferIn* buffer=event.subEvents.begin()->buffer;
597      string id;
598      *buffer>>id;
599      get(id)->recvPostProcessingGlobalAttributes(*buffer);
600   }
601
602   void CContext::recvPostProcessingGlobalAttributes(CBufferIn& buffer)
603   {     
604      postProcessingGlobalAttributes();
605   }
606
607   /*!
608   \brief Close all the context defintion and do processing data
609      After everything is well defined on client side, they will be processed and sent to server
610   From the version 2.0, sever and client work no more on the same database. Moreover, client(s) will send
611   all necessary information to server, from which each server can build its own database.
612   Because the role of server is to write out field data on a specific netcdf file,
613   the only information that it needs is the enabled files
614   and the active fields (fields will be written onto active files)
615   */
616   void CContext::closeDefinition(void)
617   {
618    CTimer::get("Context : close definition").resume() ;
619    postProcessingGlobalAttributes();
620
621    if (hasClient) sendPostProcessingGlobalAttributes();
622
623    // There are some processings that should be done after all of above. For example: check mask or index
624    this->buildFilterGraphOfEnabledFields();
625   
626     if (hasClient && !hasServer)
627    {
628      buildFilterGraphOfFieldsWithReadAccess();
629    }
630   
631    checkGridEnabledFields();   
632
633    if (hasClient) this->sendProcessingGridOfEnabledFields();
634    if (hasClient) this->sendCloseDefinition();
635
636    // Nettoyage de l'arborescence
637    if (hasClient) CleanTree(); // Only on client side??
638
639    if (hasClient)
640    {
641      sendCreateFileHeader();
642      if (!hasServer) startPrefetchingOfEnabledReadModeFiles();
643    }
644    CTimer::get("Context : close definition").suspend() ;
645   }
646
647   void CContext::findAllEnabledFields(void)
648   {
649     for (unsigned int i = 0; i < this->enabledFiles.size(); i++)
650     (void)this->enabledFiles[i]->getEnabledFields();
651   }
652
653   void CContext::findAllEnabledFieldsInReadModeFiles(void)
654   {
655     for (unsigned int i = 0; i < this->enabledReadModeFiles.size(); ++i)
656     (void)this->enabledReadModeFiles[i]->getEnabledFields();
657   }
658
659   void CContext::readAttributesOfEnabledFieldsInReadModeFiles()
660   {
661      for (unsigned int i = 0; i < this->enabledReadModeFiles.size(); ++i)
662        (void)this->enabledReadModeFiles[i]->readAttributesOfEnabledFieldsInReadMode();
663   }
664
665   void CContext::sendGridEnabledFields()
666   {
667     int size = this->enabledFiles.size();
668     for (int i = 0; i < size; ++i)
669     {       
670       this->enabledFiles[i]->sendGridOfEnabledFields();
671     }
672   }
673
674   void CContext::checkGridEnabledFields()
675   {
676     int size = this->enabledFiles.size();
677     for (int i = 0; i < size; ++i)
678     {
679       this->enabledFiles[i]->checkGridOfEnabledFields();       
680     }
681   }
682
683   void CContext::solveOnlyRefOfEnabledFields(bool sendToServer)
684   {
685     int size = this->enabledFiles.size();
686     for (int i = 0; i < size; ++i)
687     {
688       this->enabledFiles[i]->solveOnlyRefOfEnabledFields(sendToServer);
689     }
690
691     for (int i = 0; i < size; ++i)
692     {
693       this->enabledFiles[i]->generateNewTransformationGridDest();
694     }
695   }
696
697   void CContext::solveAllRefOfEnabledFieldsAndTransform(bool sendToServer)
698   {
699     int size = this->enabledFiles.size();
700     for (int i = 0; i < size; ++i)
701     {
702       this->enabledFiles[i]->solveAllRefOfEnabledFieldsAndTransform(sendToServer);
703     }
704   }
705
706   void CContext::buildFilterGraphOfEnabledFields()
707   {
708     int size = this->enabledFiles.size();
709     for (int i = 0; i < size; ++i)
710     {
711       this->enabledFiles[i]->buildFilterGraphOfEnabledFields(garbageCollector);
712     }
713   }
714
715   void CContext::startPrefetchingOfEnabledReadModeFiles()
716   {
717     int size = enabledReadModeFiles.size();
718     for (int i = 0; i < size; ++i)
719     {
720        enabledReadModeFiles[i]->prefetchEnabledReadModeFields();
721     }
722   }
723
724   void CContext::checkPrefetchingOfEnabledReadModeFiles()
725   {
726     int size = enabledReadModeFiles.size();
727     for (int i = 0; i < size; ++i)
728     {
729        enabledReadModeFiles[i]->prefetchEnabledReadModeFieldsIfNeeded();
730     }
731   }
732
733  void CContext::findFieldsWithReadAccess(void)
734  {
735    fieldsWithReadAccess.clear();
736    const vector<CField*> allFields = CField::getAll();
737    for (size_t i = 0; i < allFields.size(); ++i)
738    {
739      CField* field = allFields[i];
740
741      if (field->file && !field->file->mode.isEmpty() && field->file->mode == CFile::mode_attr::read)
742        field->read_access = true;
743      else if (!field->read_access.isEmpty() && field->read_access && (field->enabled.isEmpty() || field->enabled))
744        fieldsWithReadAccess.push_back(field);
745    }
746  }
747
748  void CContext::solveAllRefOfFieldsWithReadAccess()
749  {
750    for (size_t i = 0; i < fieldsWithReadAccess.size(); ++i)
751      fieldsWithReadAccess[i]->solveAllReferenceEnabledField(false);
752  }
753
754  void CContext::buildFilterGraphOfFieldsWithReadAccess()
755  {
756    for (size_t i = 0; i < fieldsWithReadAccess.size(); ++i)
757      fieldsWithReadAccess[i]->buildFilterGraph(garbageCollector, true);
758  }
759
760   void CContext::solveAllInheritance(bool apply)
761   {
762     // Résolution des héritages descendants (càd des héritages de groupes)
763     // pour chacun des contextes.
764      solveDescInheritance(apply);
765
766     // Résolution des héritages par référence au niveau des fichiers.
767      const vector<CFile*> allFiles=CFile::getAll();
768      const vector<CGrid*> allGrids= CGrid::getAll();
769
770      if (hasClient && !hasServer)
771      //if (hasClient)
772      {
773        for (unsigned int i = 0; i < allFiles.size(); i++)
774          allFiles[i]->solveFieldRefInheritance(apply);
775      }
776
777      unsigned int vecSize = allGrids.size();
778      unsigned int i = 0;
779      for (i = 0; i < vecSize; ++i)
780        allGrids[i]->solveDomainAxisRefInheritance(apply);
781
782   }
783
784   void CContext::findEnabledFiles(void)
785   {
786      const std::vector<CFile*> allFiles = CFile::getAll();
787      const CDate& initDate = calendar->getInitDate();
788
789      for (unsigned int i = 0; i < allFiles.size(); i++)
790         if (!allFiles[i]->enabled.isEmpty()) // Si l'attribut 'enabled' est défini.
791         {
792            if (allFiles[i]->enabled.getValue()) // Si l'attribut 'enabled' est fixé à vrai.
793            {
794              if ((initDate + allFiles[i]->output_freq.getValue()) < (initDate + this->getCalendar()->getTimeStep()))
795              {
796                error(0)<<"WARNING: void CContext::findEnabledFiles()"<<endl
797                    << "Output frequency in file \""<<allFiles[i]->getFileOutputName()
798                    <<"\" is less than the time step. File will not be written."<<endl;
799              }
800              else
801               enabledFiles.push_back(allFiles[i]);
802            }
803         }
804         else
805         {
806           if ( (initDate + allFiles[i]->output_freq.getValue()) < (initDate + this->getCalendar()->getTimeStep()))
807           {
808             error(0)<<"WARNING: void CContext::findEnabledFiles()"<<endl
809                 << "Output frequency in file \""<<allFiles[i]->getFileOutputName()
810                 <<"\" is less than the time step. File will not be written."<<endl;
811           }
812           else
813             enabledFiles.push_back(allFiles[i]); // otherwise true by default
814         }
815
816      if (enabledFiles.size() == 0)
817         DEBUG(<<"Aucun fichier ne va être sorti dans le contexte nommé \""
818               << getId() << "\" !");
819
820   }
821
822   void CContext::distributeFiles(void)
823   {
824     // If primary server
825     if (hasServer && hasClient)
826     {
827       // (1) Find all enabled files in write mode
828       for (int i = 0; i < this->enabledFiles.size(); ++i)
829       {
830         if (enabledFiles[i]->mode.isEmpty() || (!enabledFiles[i]->mode.isEmpty() && enabledFiles[i]->mode.getValue() == CFile::mode_attr::write ))
831          enabledWriteModeFiles.push_back(enabledFiles[i]);
832       }
833
834       // (2) Estimate the data volume for each file
835       int size = this->enabledWriteModeFiles.size();
836       std::vector<std::pair<StdSize, CFile*> > dataSizeMap;
837       for (size_t i = 0; i < size; ++i)
838       {
839         CFile* file = this->enabledWriteModeFiles[i];
840         StdSize dataSize;
841         std::vector<CField*> enabledFields = file->getEnabledFields();
842         size_t numEnabledFields = enabledFields.size();
843         for (size_t j = 0; j < numEnabledFields; ++j)
844         {
845           const std::vector<std::map<int, StdSize> > mapSize = enabledFields[j]->getGridDataBufferSize();
846           for (size_t c = 0; c < mapSize.size(); ++c)
847           {
848             std::map<int, StdSize>::const_iterator it = mapSize[c].begin(), itE = mapSize[c].end();
849             for (; it != itE; ++it)
850             {
851               dataSize += it->second;
852             }
853           }
854         }
855         CDuration outFreq = file->output_freq.getValue();
856         if (outFreq.timestep != 0.0)
857         {
858           outFreq = calendar->getTimeStep();
859         }
860         double outFreqSec = outFreq.second + 60.*(outFreq.minute + 60.*(outFreq.hour + 24.*(outFreq.day + outFreq.year*365.25) ) );
861         dataSize /= outFreqSec;
862         dataSizeMap.push_back(make_pair(dataSize,file));
863       }
864
865       // (3) Sort enabledWriteModeFiles
866       std::sort(dataSizeMap.begin(), dataSizeMap.end());
867       for (int i = 0; i < size; ++i)
868       {
869         enabledWriteModeFiles[i] = dataSizeMap[i].second;
870       }
871
872       // (4) Assign contextClient to each enabled file
873       int i,j;
874       for (i = 0, j=0; i < enabledFiles.size(); ++i)
875       {
876         if (enabledFiles[i]->mode.isEmpty() || (!enabledFiles[i]->mode.isEmpty() && enabledFiles[i]->mode.getValue() == CFile::mode_attr::write ))
877         {
878           int n = j / clientPrimServer.size();
879           int mod = j % clientPrimServer.size();
880           int poolId;
881           if (n % 2 == 0)
882             poolId =mod;
883           else
884             poolId = clientPrimServer.size()-1-mod;
885            enabledWriteModeFiles[j]->setContextClient(clientPrimServer[poolId]);
886           ++j;
887         }
888         else
889         {
890           enabledFiles[i]->setContextClient(client);
891         }
892       }
893     }
894     else
895     {
896       for (int i = 0; i < this->enabledFiles.size(); ++i)
897         enabledFiles[i]->setContextClient(client);
898     }
899   }
900
901   void CContext::findEnabledReadModeFiles(void)
902   {
903     int size = this->enabledFiles.size();
904     for (int i = 0; i < size; ++i)
905     {
906       if (!enabledFiles[i]->mode.isEmpty() && enabledFiles[i]->mode.getValue() == CFile::mode_attr::read)
907        enabledReadModeFiles.push_back(enabledFiles[i]);
908     }
909   }
910
911   void CContext::closeAllFile(void)
912   {
913     std::vector<CFile*>::const_iterator
914            it = this->enabledFiles.begin(), end = this->enabledFiles.end();
915
916     for (; it != end; it++)
917     {
918       info(30)<<"Closing File : "<<(*it)->getId()<<endl;
919       (*it)->close();
920     }
921   }
922
923   /*!
924   \brief Dispatch event received from client
925      Whenever a message is received in buffer of server, it will be processed depending on
926   its event type. A new event type should be added in the switch list to make sure
927   it processed on server side.
928   \param [in] event: Received message
929   */
930   bool CContext::dispatchEvent(CEventServer& event)
931   {
932
933      if (SuperClass::dispatchEvent(event)) return true;
934      else
935      {
936        switch(event.type)
937        {
938           case EVENT_ID_CLOSE_DEFINITION :
939             recvCloseDefinition(event);
940             return true;
941             break;
942           case EVENT_ID_UPDATE_CALENDAR:
943             recvUpdateCalendar(event);
944             return true;
945             break;
946           case EVENT_ID_CREATE_FILE_HEADER :
947             recvCreateFileHeader(event);
948             return true;
949             break;
950           case EVENT_ID_POST_PROCESS:
951             recvPostProcessing(event);
952             return true;
953            case EVENT_ID_SEND_REGISTRY:
954             recvRegistry(event);
955             return true;
956             break;
957            case EVENT_ID_POST_PROCESS_GLOBAL_ATTRIBUTES:
958             recvPostProcessingGlobalAttributes(event);
959             return true;
960             break;
961            case EVENT_ID_PROCESS_GRID_ENABLED_FIELDS:
962             recvProcessingGridOfEnabledFields(event);
963             return true;
964             break;
965           default :
966             ERROR("bool CContext::dispatchEvent(CEventServer& event)",
967                    <<"Unknown Event");
968           return false;
969         }
970      }
971   }
972
973   //! Client side: Send a message to server to make it close
974   void CContext::sendCloseDefinition(void)
975   {
976     // Use correct context client to send message
977     int nbSrvPools = (this->hasServer) ? (this->hasClient ? this->clientPrimServer.size() : 0) : 1;
978     for (int i = 0; i < nbSrvPools; ++i)
979     {
980       CContextClient* contextClientTmp = (hasServer) ? clientPrimServer[i] : client;
981       CEventClient event(getType(),EVENT_ID_CLOSE_DEFINITION);
982       if (contextClientTmp->isServerLeader())
983       {
984         CMessage msg;
985         if (hasServer)
986           msg<<this->getIdServer(i);
987         else
988           msg<<this->getIdServer();
989         const std::list<int>& ranks = contextClientTmp->getRanksServerLeader();
990         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
991           event.push(*itRank,1,msg);
992         contextClientTmp->sendEvent(event);
993       }
994       else contextClientTmp->sendEvent(event);
995     }
996   }
997
998   //! Server side: Receive a message of client announcing a context close
999   void CContext::recvCloseDefinition(CEventServer& event)
1000   {
1001      CBufferIn* buffer=event.subEvents.begin()->buffer;
1002      string id;
1003      *buffer>>id;
1004      get(id)->closeDefinition();
1005   }
1006
1007   //! Client side: Send a message to update calendar in each time step
1008   void CContext::sendUpdateCalendar(int step)
1009   {
1010     // Use correct context client to send message
1011    int nbSrvPools = (this->hasServer) ? (this->hasClient ? this->clientPrimServer.size() : 0) : 1;
1012     for (int i = 0; i < nbSrvPools; ++i)
1013     {
1014       CContextClient* contextClientTmp = (hasServer) ? clientPrimServer[i] : client;
1015       CEventClient event(getType(),EVENT_ID_UPDATE_CALENDAR);
1016
1017         if (contextClientTmp->isServerLeader())
1018         {
1019           CMessage msg;
1020           if (hasServer)
1021             msg<<this->getIdServer(i)<<step;
1022           else
1023             msg<<this->getIdServer()<<step;
1024           const std::list<int>& ranks = contextClientTmp->getRanksServerLeader();
1025           for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
1026             event.push(*itRank,1,msg);
1027           contextClientTmp->sendEvent(event);
1028         }
1029         else contextClientTmp->sendEvent(event);
1030     }
1031   }
1032
1033   //! Server side: Receive a message of client annoucing calendar update
1034   void CContext::recvUpdateCalendar(CEventServer& event)
1035   {
1036      CBufferIn* buffer=event.subEvents.begin()->buffer;
1037      string id;
1038      *buffer>>id;
1039      get(id)->recvUpdateCalendar(*buffer);
1040   }
1041
1042   //! Server side: Receive a message of client annoucing calendar update
1043   void CContext::recvUpdateCalendar(CBufferIn& buffer)
1044   {
1045      int step;
1046      buffer>>step;
1047      updateCalendar(step);
1048      if (hasClient && hasServer)
1049      {       
1050        sendUpdateCalendar(step);
1051      }
1052   }
1053
1054   //! Client side: Send a message to create header part of netcdf file
1055   void CContext::sendCreateFileHeader(void)
1056   {
1057     // Use correct context client to send message
1058     // int nbSrvPools = (hasServer) ? clientPrimServer.size() : 1;
1059     int nbSrvPools = (this->hasServer) ? (this->hasClient ? this->clientPrimServer.size() : 0) : 1;
1060     for (int i = 0; i < nbSrvPools; ++i)
1061     {
1062       CContextClient* contextClientTmp = (hasServer) ? clientPrimServer[i] : client;
1063       CEventClient event(getType(),EVENT_ID_CREATE_FILE_HEADER);
1064
1065       if (contextClientTmp->isServerLeader())
1066       {
1067         CMessage msg;
1068         if (hasServer)
1069           msg<<this->getIdServer(i);
1070         else
1071           msg<<this->getIdServer();
1072         const std::list<int>& ranks = contextClientTmp->getRanksServerLeader();
1073         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
1074           event.push(*itRank,1,msg) ;
1075         contextClientTmp->sendEvent(event);
1076       }
1077       else contextClientTmp->sendEvent(event);
1078     }
1079   }
1080
1081   //! Server side: Receive a message of client annoucing the creation of header part of netcdf file
1082   void CContext::recvCreateFileHeader(CEventServer& event)
1083   {
1084      CBufferIn* buffer=event.subEvents.begin()->buffer;
1085      string id;
1086      *buffer>>id;
1087      get(id)->recvCreateFileHeader(*buffer);
1088   }
1089
1090   //! Server side: Receive a message of client annoucing the creation of header part of netcdf file
1091   void CContext::recvCreateFileHeader(CBufferIn& buffer)
1092   {
1093      if (!hasClient && hasServer) 
1094        createFileHeader();
1095   }
1096
1097   //! Client side: Send a message to do some post processing on server
1098   void CContext::sendProcessingGridOfEnabledFields()
1099   {
1100      // Use correct context client to send message
1101     int nbSrvPools = (this->hasServer) ? (this->hasClient ? this->clientPrimServer.size() : 0) : 1;
1102     for (int i = 0; i < nbSrvPools; ++i)
1103     {
1104       CContextClient* contextClientTmp = (0 != clientPrimServer.size()) ? clientPrimServer[i] : client;
1105       CEventClient event(getType(),EVENT_ID_PROCESS_GRID_ENABLED_FIELDS);
1106
1107       if (contextClientTmp->isServerLeader())
1108       {
1109         CMessage msg;
1110         if (hasServer)
1111           msg<<this->getIdServer(i);
1112         else
1113           msg<<this->getIdServer();
1114         const std::list<int>& ranks = contextClientTmp->getRanksServerLeader();
1115         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
1116           event.push(*itRank,1,msg);
1117         contextClientTmp->sendEvent(event);
1118       }
1119       else contextClientTmp->sendEvent(event);
1120     }
1121   }
1122
1123   //! Server side: Receive a message to do some post processing
1124   void CContext::recvProcessingGridOfEnabledFields(CEventServer& event)
1125   {
1126      CBufferIn* buffer=event.subEvents.begin()->buffer;
1127      string id;
1128      *buffer>>id;     
1129   }
1130
1131   //! Client side: Send a message to do some post processing on server
1132   void CContext::sendPostProcessing()
1133   {
1134      // Use correct context client to send message
1135     // int nbSrvPools = (hasServer) ? clientPrimServer.size() : 1;
1136     int nbSrvPools = (this->hasServer) ? (this->hasClient ? this->clientPrimServer.size() : 0) : 1;
1137     for (int i = 0; i < nbSrvPools; ++i)
1138     {
1139       CContextClient* contextClientTmp = (hasServer) ? clientPrimServer[i] : client;
1140       CEventClient event(getType(),EVENT_ID_POST_PROCESS);
1141       if (contextClientTmp->isServerLeader())
1142       {
1143         CMessage msg;
1144         if (hasServer)
1145           msg<<this->getIdServer(i);
1146         else
1147           msg<<this->getIdServer();
1148         const std::list<int>& ranks = contextClientTmp->getRanksServerLeader();
1149         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
1150         event.push(*itRank,1,msg);
1151         contextClientTmp->sendEvent(event);
1152       }
1153       else contextClientTmp->sendEvent(event);
1154     }
1155   }
1156
1157   //! Server side: Receive a message to do some post processing
1158   void CContext::recvPostProcessing(CEventServer& event)
1159   {
1160      CBufferIn* buffer=event.subEvents.begin()->buffer;
1161      string id;
1162      *buffer>>id;
1163      get(id)->recvPostProcessing(*buffer);
1164   }
1165
1166   //! Server side: Receive a message to do some post processing
1167   void CContext::recvPostProcessing(CBufferIn& buffer)
1168   {
1169      CCalendarWrapper::get(CCalendarWrapper::GetDefName())->createCalendar();
1170      postProcessing();
1171   }
1172
1173   const StdString& CContext::getIdServer()
1174   {
1175      if (hasClient)
1176      {
1177        idServer_ = this->getId();
1178        idServer_ += "_server";
1179        return idServer_;
1180      }
1181      if (hasServer) return (this->getId());
1182   }
1183
1184   const StdString& CContext::getIdServer(const int i)
1185   {
1186     idServer_ = this->getId();
1187     idServer_ += "_server_";
1188     idServer_ += boost::lexical_cast<string>(i);
1189     return idServer_;
1190   }
1191
1192
1193   /*!
1194   \brief Do some simple post processings after parsing xml file
1195      After the xml file (iodef.xml) is parsed, it is necessary to build all relations among
1196   created object, e.g: inhertance among fields, domain, axis. After that, all fiels as well as their parents (reference fields),
1197   which will be written out into netcdf files, are processed
1198   */
1199   void CContext::postProcessing()
1200   {
1201     if (isPostProcessed) return;
1202
1203      // Make sure the calendar was correctly created
1204      if (!calendar)
1205        ERROR("CContext::postProcessing()", << "A calendar must be defined for the context \"" << getId() << "!\"")
1206      else if (calendar->getTimeStep() == NoneDu)
1207        ERROR("CContext::postProcessing()", << "A timestep must be defined for the context \"" << getId() << "!\"")
1208      // Calendar first update to set the current date equals to the start date
1209      calendar->update(0);
1210
1211      // Find all inheritance in xml structure
1212      this->solveAllInheritance();
1213
1214//      ShowTree(info(10));
1215
1216      // Check if some axis, domains or grids are eligible to for compressed indexed output.
1217      // Warning: This must be done after solving the inheritance and before the rest of post-processing
1218      checkAxisDomainsGridsEligibilityForCompressedOutput();     
1219
1220      // Check if some automatic time series should be generated
1221      // Warning: This must be done after solving the inheritance and before the rest of post-processing     
1222
1223      // The timeseries should only be prepared in client
1224      if (hasClient && !hasServer) prepareTimeseries();
1225
1226      //Initialisation du vecteur 'enabledFiles' contenant la liste des fichiers à sortir.
1227      this->findEnabledFiles();
1228     
1229      // For now, only read files with client and only one level server
1230      if (hasClient && !hasServer) this->findEnabledReadModeFiles();
1231
1232      // Find all enabled fields of each file
1233      this->findAllEnabledFields();
1234      // For now, only read files with client and only one level server
1235      if (hasClient && !hasServer) this->findAllEnabledFieldsInReadModeFiles();
1236
1237
1238      if (hasClient && !hasServer)
1239      {
1240       // Try to read attributes of fields in file then fill in corresponding grid (or domain, axis)
1241       this->readAttributesOfEnabledFieldsInReadModeFiles();
1242      }
1243
1244      // Only search and rebuild all reference objects of enable fields, don't transform
1245      this->solveOnlyRefOfEnabledFields(false);
1246
1247      // Search and rebuild all reference object of enabled fields, and transform
1248      this->solveAllRefOfEnabledFieldsAndTransform(false);
1249
1250      // Find all fields with read access from the public API
1251      if (hasClient && !hasServer) findFieldsWithReadAccess();
1252      // and solve the all reference for them
1253      if (hasClient && !hasServer) solveAllRefOfFieldsWithReadAccess();
1254
1255      isPostProcessed = true;
1256   }
1257
1258   /*!
1259    * Compute the required buffer size to send the attributes (mostly those grid related).
1260    *
1261    * \param maxEventSize [in/out] the size of the bigger event for each connected server
1262    */
1263   std::map<int, StdSize> CContext::getAttributesBufferSize(std::map<int, StdSize>& maxEventSize, CContextClient* contextClient)
1264   {
1265     std::map<int, StdSize> attributesSize;
1266
1267     if (hasClient)
1268     {
1269       size_t numEnabledFiles = this->enabledFiles.size();
1270       for (size_t i = 0; i < numEnabledFiles; ++i)
1271       {
1272         CFile* file = this->enabledFiles[i];
1273//         if (file->getContextClient() == contextClient)
1274         {
1275           std::vector<CField*> enabledFields = file->getEnabledFields();
1276           size_t numEnabledFields = enabledFields.size();
1277           for (size_t j = 0; j < numEnabledFields; ++j)
1278           {
1279             const std::map<int, StdSize> mapSize = enabledFields[j]->getGridAttributesBufferSize();
1280             std::map<int, StdSize>::const_iterator it = mapSize.begin(), itE = mapSize.end();
1281             for (; it != itE; ++it)
1282             {
1283               // If attributesSize[it->first] does not exist, it will be zero-initialized
1284               // so we can use it safely without checking for its existance
1285               if (attributesSize[it->first] < it->second)
1286                 attributesSize[it->first] = it->second;
1287
1288               if (maxEventSize[it->first] < it->second)
1289                 maxEventSize[it->first] = it->second;
1290             }
1291           }
1292         }
1293       }
1294     }
1295
1296     return attributesSize;
1297   }
1298
1299   /*!
1300    * Compute the required buffer size to send the fields data.
1301    *
1302    * \param maxEventSize [in/out] the size of the bigger event for each connected server
1303    */
1304   std::map<int, StdSize> CContext::getDataBufferSize(std::map<int, StdSize>& maxEventSize, CContextClient* contextClient)
1305   {
1306     CFile::mode_attr::t_enum mode = hasClient ? CFile::mode_attr::write : CFile::mode_attr::read;
1307
1308     std::map<int, StdSize> dataSize;
1309
1310     // Find all reference domain and axis of all active fields
1311     size_t numEnabledFiles = this->enabledFiles.size();
1312     for (size_t i = 0; i < numEnabledFiles; ++i)
1313     {
1314       CFile* file = this->enabledFiles[i];
1315       if (file->getContextClient() == contextClient)
1316       {
1317         CFile::mode_attr::t_enum fileMode = file->mode.isEmpty() ? CFile::mode_attr::write : file->mode.getValue();
1318
1319         if (fileMode == mode)
1320         {
1321           std::vector<CField*> enabledFields = file->getEnabledFields();
1322           size_t numEnabledFields = enabledFields.size();
1323           for (size_t j = 0; j < numEnabledFields; ++j)
1324           {
1325             const std::vector<std::map<int, StdSize> > mapSize = enabledFields[j]->getGridDataBufferSize();
1326             for (size_t c = 0; c < mapSize.size(); ++c)
1327             {
1328               std::map<int, StdSize>::const_iterator it = mapSize[c].begin(), itE = mapSize[c].end();
1329               for (; it != itE; ++it)
1330               {
1331                 // If dataSize[it->first] does not exist, it will be zero-initialized
1332                 // so we can use it safely without checking for its existance
1333                 if (CXios::isOptPerformance)
1334                   dataSize[it->first] += it->second;
1335                 else if (dataSize[it->first] < it->second)
1336                   dataSize[it->first] = it->second;
1337
1338                 if (maxEventSize[it->first] < it->second)
1339                   maxEventSize[it->first] = it->second;
1340               }
1341             }
1342           }
1343         }
1344       }
1345     }
1346
1347     return dataSize;
1348   }
1349
1350   //! Client side: Send infomation of active files (files are enabled to write out)
1351   void CContext::sendEnabledFiles()
1352   {
1353     int size = this->enabledFiles.size();
1354
1355     // In a context, each type has a root definition, e.g: axis, domain, field.
1356     // Every object must be a child of one of these root definition. In this case
1357     // all new file objects created on server must be children of the root "file_definition"
1358     StdString fileDefRoot("file_definition");
1359     CFileGroup* cfgrpPtr = CFileGroup::get(fileDefRoot);
1360
1361     for (int i = 0; i < size; ++i)
1362     {
1363       cfgrpPtr->sendCreateChild(this->enabledFiles[i]->getId(),enabledFiles[i]->getContextClient());
1364       this->enabledFiles[i]->sendAllAttributesToServer(enabledFiles[i]->getContextClient());
1365       this->enabledFiles[i]->sendAddAllVariables(enabledFiles[i]->getContextClient());
1366     }
1367   }
1368
1369   //! Client side: Send information of active fields (ones are written onto files)
1370   void CContext::sendEnabledFields()
1371   {
1372     int size = this->enabledFiles.size();
1373     for (int i = 0; i < size; ++i)
1374     {
1375       this->enabledFiles[i]->sendEnabledFields(enabledFiles[i]->getContextClient());
1376     }
1377   }
1378
1379   //! Client side: Check if the defined axis, domains and grids are eligible for compressed indexed output
1380   void CContext::checkAxisDomainsGridsEligibilityForCompressedOutput()
1381   {
1382     if (!hasClient) return;
1383
1384     const vector<CAxis*> allAxis = CAxis::getAll();
1385     for (vector<CAxis*>::const_iterator it = allAxis.begin(); it != allAxis.end(); it++)
1386       (*it)->checkEligibilityForCompressedOutput();
1387
1388     const vector<CDomain*> allDomains = CDomain::getAll();
1389     for (vector<CDomain*>::const_iterator it = allDomains.begin(); it != allDomains.end(); it++)
1390       (*it)->checkEligibilityForCompressedOutput();
1391
1392     const vector<CGrid*> allGrids = CGrid::getAll();
1393     for (vector<CGrid*>::const_iterator it = allGrids.begin(); it != allGrids.end(); it++)
1394       (*it)->checkEligibilityForCompressedOutput();
1395   }
1396
1397   //! Client side: Prepare the timeseries by adding the necessary files
1398   void CContext::prepareTimeseries()
1399   {
1400     if (!hasClient) return;
1401
1402     const std::vector<CFile*> allFiles = CFile::getAll();
1403     for (size_t i = 0; i < allFiles.size(); i++)
1404     {
1405       CFile* file = allFiles[i];
1406
1407       std::vector<CVariable*> fileVars, fieldVars, vars = file->getAllVariables();
1408       for (size_t k = 0; k < vars.size(); k++)
1409       {
1410         CVariable* var = vars[k];
1411
1412         if (var->ts_target.isEmpty()
1413              || var->ts_target == CVariable::ts_target_attr::file || var->ts_target == CVariable::ts_target_attr::both)
1414           fileVars.push_back(var);
1415
1416         if (!var->ts_target.isEmpty()
1417              && (var->ts_target == CVariable::ts_target_attr::field || var->ts_target == CVariable::ts_target_attr::both))
1418           fieldVars.push_back(var);
1419       }
1420
1421       if (!file->timeseries.isEmpty() && file->timeseries != CFile::timeseries_attr::none)
1422       {
1423         StdString fileNameStr("%file_name%") ;
1424         StdString tsPrefix = !file->ts_prefix.isEmpty() ? file->ts_prefix : fileNameStr ;
1425         
1426         StdString fileName=file->getFileOutputName();
1427         size_t pos=tsPrefix.find(fileNameStr) ;
1428         while (pos!=std::string::npos)
1429         {
1430           tsPrefix=tsPrefix.replace(pos,fileNameStr.size(),fileName) ;
1431           pos=tsPrefix.find(fileNameStr) ;
1432         }
1433       
1434         const std::vector<CField*> allFields = file->getAllFields();
1435         for (size_t j = 0; j < allFields.size(); j++)
1436         {
1437           CField* field = allFields[j];
1438
1439           if (!field->ts_enabled.isEmpty() && field->ts_enabled)
1440           {
1441             CFile* tsFile = CFile::create();
1442             tsFile->duplicateAttributes(file);
1443
1444             // Add variables originating from file and targeted to timeserie file
1445             for (size_t k = 0; k < fileVars.size(); k++)
1446               tsFile->getVirtualVariableGroup()->addChild(fileVars[k]);
1447
1448           
1449             tsFile->name = tsPrefix + "_";
1450             if (!field->name.isEmpty())
1451               tsFile->name.get() += field->name;
1452             else if (field->hasDirectFieldReference()) // We cannot use getBaseFieldReference() just yet
1453               tsFile->name.get() += field->field_ref;
1454             else
1455               tsFile->name.get() += field->getId();
1456
1457             if (!field->ts_split_freq.isEmpty())
1458               tsFile->split_freq = field->ts_split_freq;
1459
1460             CField* tsField = tsFile->addField();
1461             tsField->field_ref = field->getId();
1462
1463             // Add variables originating from file and targeted to timeserie field
1464             for (size_t k = 0; k < fieldVars.size(); k++)
1465               tsField->getVirtualVariableGroup()->addChild(fieldVars[k]);
1466
1467             vars = field->getAllVariables();
1468             for (size_t k = 0; k < vars.size(); k++)
1469             {
1470               CVariable* var = vars[k];
1471
1472               // Add variables originating from field and targeted to timeserie field
1473               if (var->ts_target.isEmpty()
1474                    || var->ts_target == CVariable::ts_target_attr::field || var->ts_target == CVariable::ts_target_attr::both)
1475                 tsField->getVirtualVariableGroup()->addChild(var);
1476
1477               // Add variables originating from field and targeted to timeserie file
1478               if (!var->ts_target.isEmpty()
1479                    && (var->ts_target == CVariable::ts_target_attr::file || var->ts_target == CVariable::ts_target_attr::both))
1480                 tsFile->getVirtualVariableGroup()->addChild(var);
1481             }
1482
1483             tsFile->solveFieldRefInheritance(true);
1484
1485             if (file->timeseries == CFile::timeseries_attr::exclusive)
1486               field->enabled = false;
1487           }
1488         }
1489
1490         // Finally disable the original file is need be
1491         if (file->timeseries == CFile::timeseries_attr::only)
1492          file->enabled = false;
1493       }
1494     }
1495   }
1496
1497   //! Client side: Send information of reference grid of active fields
1498   void CContext::sendRefGrid()
1499   {
1500     std::set<StdString> gridIds;
1501     int sizeFile = this->enabledFiles.size();
1502     CFile* filePtr(NULL);
1503
1504     // Firstly, find all reference grids of all active fields
1505     for (int i = 0; i < sizeFile; ++i)
1506     {
1507       filePtr = this->enabledFiles[i];
1508       std::vector<CField*> enabledFields = filePtr->getEnabledFields();
1509       int sizeField = enabledFields.size();
1510       for (int numField = 0; numField < sizeField; ++numField)
1511       {
1512         if (0 != enabledFields[numField]->getRelGrid())
1513           gridIds.insert(CGrid::get(enabledFields[numField]->getRelGrid())->getId());
1514       }
1515     }
1516
1517     // Create all reference grids on server side
1518     StdString gridDefRoot("grid_definition");
1519     CGridGroup* gridPtr = CGridGroup::get(gridDefRoot);
1520     std::set<StdString>::const_iterator it, itE = gridIds.end();
1521     for (it = gridIds.begin(); it != itE; ++it)
1522     {
1523       gridPtr->sendCreateChild(*it);
1524       CGrid::get(*it)->sendAllAttributesToServer();
1525       CGrid::get(*it)->sendAllDomains();
1526       CGrid::get(*it)->sendAllAxis();
1527       CGrid::get(*it)->sendAllScalars();
1528     }
1529   }
1530
1531
1532   //! Client side: Send information of reference domain and axis of active fields
1533   void CContext::sendRefDomainsAxis()
1534   {
1535     std::set<StdString> domainIds, axisIds, scalarIds;
1536
1537     // Find all reference domain and axis of all active fields
1538     int numEnabledFiles = this->enabledFiles.size();
1539     for (int i = 0; i < numEnabledFiles; ++i)
1540     {
1541       std::vector<CField*> enabledFields = this->enabledFiles[i]->getEnabledFields();
1542       int numEnabledFields = enabledFields.size();
1543       for (int j = 0; j < numEnabledFields; ++j)
1544       {
1545         const std::vector<StdString>& prDomAxisScalarId = enabledFields[j]->getRefDomainAxisIds();
1546         if ("" != prDomAxisScalarId[0]) domainIds.insert(prDomAxisScalarId[0]);
1547         if ("" != prDomAxisScalarId[1]) axisIds.insert(prDomAxisScalarId[1]);
1548         if ("" != prDomAxisScalarId[2]) scalarIds.insert(prDomAxisScalarId[2]);
1549       }
1550     }
1551
1552     // Create all reference axis on server side
1553     std::set<StdString>::iterator itDom, itAxis, itScalar;
1554     std::set<StdString>::const_iterator itE;
1555
1556     StdString scalarDefRoot("scalar_definition");
1557     CScalarGroup* scalarPtr = CScalarGroup::get(scalarDefRoot);
1558     itE = scalarIds.end();
1559     for (itScalar = scalarIds.begin(); itScalar != itE; ++itScalar)
1560     {
1561       if (!itScalar->empty())
1562       {
1563         scalarPtr->sendCreateChild(*itScalar);
1564         CScalar::get(*itScalar)->sendAllAttributesToServer();
1565       }
1566     }
1567
1568     StdString axiDefRoot("axis_definition");
1569     CAxisGroup* axisPtr = CAxisGroup::get(axiDefRoot);
1570     itE = axisIds.end();
1571     for (itAxis = axisIds.begin(); itAxis != itE; ++itAxis)
1572     {
1573       if (!itAxis->empty())
1574       {
1575         axisPtr->sendCreateChild(*itAxis);
1576         CAxis::get(*itAxis)->sendAllAttributesToServer();
1577       }
1578     }
1579
1580     // Create all reference domains on server side
1581     StdString domDefRoot("domain_definition");
1582     CDomainGroup* domPtr = CDomainGroup::get(domDefRoot);
1583     itE = domainIds.end();
1584     for (itDom = domainIds.begin(); itDom != itE; ++itDom)
1585     {
1586       if (!itDom->empty()) {
1587          domPtr->sendCreateChild(*itDom);
1588          CDomain::get(*itDom)->sendAllAttributesToServer();
1589       }
1590     }
1591   }
1592
1593   //! Update calendar in each time step
1594   void CContext::updateCalendar(int step)
1595   {
1596      info(50) << "updateCalendar : before : " << calendar->getCurrentDate() << endl;
1597      calendar->update(step);
1598      info(50) << "updateCalendar : after : " << calendar->getCurrentDate() << endl;
1599#ifdef XIOS_MEMTRACK_LIGHT
1600      info(50) << " Current memory used by XIOS : "<<  MemTrack::getCurrentMemorySize()*1.0/(1024*1024)<<" Mbyte, at timestep "<<step<<" of context "<<this->getId()<<endl ;
1601#endif
1602      if (hasClient)
1603      {
1604        checkPrefetchingOfEnabledReadModeFiles();
1605        garbageCollector.invalidate(calendar->getCurrentDate());
1606      }
1607   }
1608
1609   //! Server side: Create header of netcdf file
1610   void CContext::createFileHeader(void )
1611   {
1612      vector<CFile*>::const_iterator it;
1613
1614      for (it=enabledFiles.begin(); it != enabledFiles.end(); it++)
1615      {
1616         (*it)->initFile();
1617      }
1618   }
1619
1620   //! Get current context
1621   CContext* CContext::getCurrent(void)
1622   {
1623     return CObjectFactory::GetObject<CContext>(CObjectFactory::GetCurrentContextId()).get();
1624   }
1625
1626   /*!
1627   \brief Set context with an id be the current context
1628   \param [in] id identity of context to be set to current
1629   */
1630   void CContext::setCurrent(const string& id)
1631   {
1632     CObjectFactory::SetCurrentContextId(id);
1633     CGroupFactory::SetCurrentContextId(id);
1634   }
1635
1636  /*!
1637  \brief Create a context with specific id
1638  \param [in] id identity of new context
1639  \return pointer to the new context or already-existed one with identity id
1640  */
1641  CContext* CContext::create(const StdString& id)
1642  {
1643    CContext::setCurrent(id);
1644
1645    bool hasctxt = CContext::has(id);
1646    CContext* context = CObjectFactory::CreateObject<CContext>(id).get();
1647    getRoot();
1648    if (!hasctxt) CGroupFactory::AddChild(root, context->getShared());
1649
1650#define DECLARE_NODE(Name_, name_) \
1651    C##Name_##Definition::create(C##Name_##Definition::GetDefName());
1652#define DECLARE_NODE_PAR(Name_, name_)
1653#include "node_type.conf"
1654
1655    return (context);
1656  }
1657
1658
1659     //! Server side: Receive a message to do some post processing
1660  void CContext::recvRegistry(CEventServer& event)
1661  {
1662    CBufferIn* buffer=event.subEvents.begin()->buffer;
1663    string id;
1664    *buffer>>id;
1665    get(id)->recvRegistry(*buffer);
1666  }
1667
1668  void CContext::recvRegistry(CBufferIn& buffer)
1669  {
1670    if (server->intraCommRank==0)
1671    {
1672      CRegistry registry(server->intraComm) ;
1673      registry.fromBuffer(buffer) ;
1674      registryOut->mergeRegistry(registry) ;
1675    }
1676  }
1677
1678  void CContext::sendRegistry(void)
1679  {
1680    registryOut->hierarchicalGatherRegistry() ;
1681
1682    // Use correct context client to send message
1683    int nbSrvPools = (this->hasServer) ? (this->hasClient ? this->clientPrimServer.size() : 0) : 1;
1684    for (int i = 0; i < nbSrvPools; ++i)
1685    {
1686      CContextClient* contextClientTmp = (hasServer) ? clientPrimServer[i] : client;
1687      CEventClient event(CContext::GetType(), CContext::EVENT_ID_SEND_REGISTRY);
1688        if (contextClientTmp->isServerLeader())
1689        {
1690           CMessage msg ;
1691           if (hasServer)
1692             msg<<this->getIdServer(i);
1693           else
1694             msg<<this->getIdServer();
1695           if (contextClientTmp->clientRank==0) msg<<*registryOut ;
1696           const std::list<int>& ranks = contextClientTmp->getRanksServerLeader();
1697           for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
1698             event.push(*itRank,1,msg);
1699           contextClientTmp->sendEvent(event);
1700         }
1701         else contextClientTmp->sendEvent(event);
1702    }
1703  }
1704
1705  /*!
1706  * \fn bool CContext::isFinalized(void)
1707  * Context is finalized if it received context post finalize event.
1708  */
1709  bool CContext::isFinalized(void)
1710  {
1711    return finalized;
1712  }
1713
1714} // namespace xios
Note: See TracBrowser for help on using the repository browser.