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

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

File dibution among secondary servers done in a more flexible way. Tested.

  • 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.9 KB
Line 
1#include "context.hpp"
2#include "attribute_template.hpp"
3#include "object_template.hpp"
4#include "group_template.hpp"
5
6#include "calendar_type.hpp"
7#include "duration.hpp"
8
9#include "context_client.hpp"
10#include "context_server.hpp"
11#include "nc4_data_output.hpp"
12#include "node_type.hpp"
13#include "message.hpp"
14#include "type.hpp"
15#include "xios_spl.hpp"
16#include "timer.hpp"
17#include "memtrack.hpp"
18
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       int nbPools = clientPrimServer.size();
828
829       // (1) Find all enabled files in write mode
830       for (int i = 0; i < this->enabledFiles.size(); ++i)
831       {
832         if (enabledFiles[i]->mode.isEmpty() || (!enabledFiles[i]->mode.isEmpty() && enabledFiles[i]->mode.getValue() == CFile::mode_attr::write ))
833          enabledWriteModeFiles.push_back(enabledFiles[i]);
834       }
835
836       // (2) Estimate the data volume for each file
837       int size = this->enabledWriteModeFiles.size();
838       std::vector<std::pair<StdSize, CFile*> > dataSizeMap;
839       StdSize dataPerPool = 0;
840       for (size_t i = 0; i < size; ++i)
841       {
842         CFile* file = this->enabledWriteModeFiles[i];
843         StdSize dataSize;
844         std::vector<CField*> enabledFields = file->getEnabledFields();
845         size_t numEnabledFields = enabledFields.size();
846         for (size_t j = 0; j < numEnabledFields; ++j)
847         {
848           const std::vector<std::map<int, StdSize> > mapSize = enabledFields[j]->getGridDataBufferSize();
849           for (size_t c = 0; c < mapSize.size(); ++c)
850           {
851             std::map<int, StdSize>::const_iterator it = mapSize[c].begin(), itE = mapSize[c].end();
852             for (; it != itE; ++it)
853             {
854               dataSize += it->second;
855             }
856           }
857         }
858         CDuration outFreq = file->output_freq.getValue();
859         if (outFreq.timestep != 0.0)
860         {
861           outFreq = calendar->getTimeStep();
862         }
863         double outFreqSec = outFreq.second + 60.*(outFreq.minute + 60.*(outFreq.hour + 24.*(outFreq.day + outFreq.year*365.25) ) );
864         dataSize /= outFreqSec;
865         dataSizeMap.push_back(make_pair(dataSize,file));
866         dataPerPool += dataSize;
867       }
868       dataPerPool /= nbPools;
869       std::sort(dataSizeMap.begin(), dataSizeMap.end());
870
871       // (3) Assign contextClient to each enabled file
872       std::vector<StdSize> poolData(nbPools);
873       int lazyPool = 0;
874       for (int i = dataSizeMap.size()-1; i >= 0; --i)
875       {
876         bool contextSet = false;
877         for (int j = 0; j < nbPools; ++j)
878         {
879           if (!contextSet)
880           {
881             if (dataSizeMap[i].first + poolData[j] < dataPerPool)
882             {
883               dataSizeMap[i].second->setContextClient(clientPrimServer[j]);
884               poolData[j] += dataSizeMap[i].first;
885               contextSet = true;
886             }
887           }
888           if (poolData[j] < poolData[lazyPool])
889             lazyPool = j;
890         }
891         if (!contextSet)
892         {
893           dataSizeMap[i].second->setContextClient(clientPrimServer[lazyPool]);
894           poolData[lazyPool] += dataSizeMap[i].first;
895         }
896       }
897
898       for (int i = 0; i < this->enabledReadModeFiles.size(); ++i)
899         enabledReadModeFiles[i]->setContextClient(client);
900     }
901     else
902     {
903       for (int i = 0; i < this->enabledFiles.size(); ++i)
904         enabledFiles[i]->setContextClient(client);
905     }
906   }
907
908   void CContext::findEnabledReadModeFiles(void)
909   {
910     int size = this->enabledFiles.size();
911     for (int i = 0; i < size; ++i)
912     {
913       if (!enabledFiles[i]->mode.isEmpty() && enabledFiles[i]->mode.getValue() == CFile::mode_attr::read)
914        enabledReadModeFiles.push_back(enabledFiles[i]);
915     }
916   }
917
918   void CContext::closeAllFile(void)
919   {
920     std::vector<CFile*>::const_iterator
921            it = this->enabledFiles.begin(), end = this->enabledFiles.end();
922
923     for (; it != end; it++)
924     {
925       info(30)<<"Closing File : "<<(*it)->getId()<<endl;
926       (*it)->close();
927     }
928   }
929
930   /*!
931   \brief Dispatch event received from client
932      Whenever a message is received in buffer of server, it will be processed depending on
933   its event type. A new event type should be added in the switch list to make sure
934   it processed on server side.
935   \param [in] event: Received message
936   */
937   bool CContext::dispatchEvent(CEventServer& event)
938   {
939
940      if (SuperClass::dispatchEvent(event)) return true;
941      else
942      {
943        switch(event.type)
944        {
945           case EVENT_ID_CLOSE_DEFINITION :
946             recvCloseDefinition(event);
947             return true;
948             break;
949           case EVENT_ID_UPDATE_CALENDAR:
950             recvUpdateCalendar(event);
951             return true;
952             break;
953           case EVENT_ID_CREATE_FILE_HEADER :
954             recvCreateFileHeader(event);
955             return true;
956             break;
957           case EVENT_ID_POST_PROCESS:
958             recvPostProcessing(event);
959             return true;
960            case EVENT_ID_SEND_REGISTRY:
961             recvRegistry(event);
962             return true;
963             break;
964            case EVENT_ID_POST_PROCESS_GLOBAL_ATTRIBUTES:
965             recvPostProcessingGlobalAttributes(event);
966             return true;
967             break;
968            case EVENT_ID_PROCESS_GRID_ENABLED_FIELDS:
969             recvProcessingGridOfEnabledFields(event);
970             return true;
971             break;
972           default :
973             ERROR("bool CContext::dispatchEvent(CEventServer& event)",
974                    <<"Unknown Event");
975           return false;
976         }
977      }
978   }
979
980   //! Client side: Send a message to server to make it close
981   void CContext::sendCloseDefinition(void)
982   {
983     // Use correct context client to send message
984     int nbSrvPools = (this->hasServer) ? (this->hasClient ? this->clientPrimServer.size() : 0) : 1;
985     for (int i = 0; i < nbSrvPools; ++i)
986     {
987       CContextClient* contextClientTmp = (hasServer) ? clientPrimServer[i] : client;
988       CEventClient event(getType(),EVENT_ID_CLOSE_DEFINITION);
989       if (contextClientTmp->isServerLeader())
990       {
991         CMessage msg;
992         if (hasServer)
993           msg<<this->getIdServer(i);
994         else
995           msg<<this->getIdServer();
996         const std::list<int>& ranks = contextClientTmp->getRanksServerLeader();
997         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
998           event.push(*itRank,1,msg);
999         contextClientTmp->sendEvent(event);
1000       }
1001       else contextClientTmp->sendEvent(event);
1002     }
1003   }
1004
1005   //! Server side: Receive a message of client announcing a context close
1006   void CContext::recvCloseDefinition(CEventServer& event)
1007   {
1008      CBufferIn* buffer=event.subEvents.begin()->buffer;
1009      string id;
1010      *buffer>>id;
1011      get(id)->closeDefinition();
1012   }
1013
1014   //! Client side: Send a message to update calendar in each time step
1015   void CContext::sendUpdateCalendar(int step)
1016   {
1017     // Use correct context client to send message
1018    int nbSrvPools = (this->hasServer) ? (this->hasClient ? this->clientPrimServer.size() : 0) : 1;
1019     for (int i = 0; i < nbSrvPools; ++i)
1020     {
1021       CContextClient* contextClientTmp = (hasServer) ? clientPrimServer[i] : client;
1022       CEventClient event(getType(),EVENT_ID_UPDATE_CALENDAR);
1023
1024         if (contextClientTmp->isServerLeader())
1025         {
1026           CMessage msg;
1027           if (hasServer)
1028             msg<<this->getIdServer(i)<<step;
1029           else
1030             msg<<this->getIdServer()<<step;
1031           const std::list<int>& ranks = contextClientTmp->getRanksServerLeader();
1032           for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
1033             event.push(*itRank,1,msg);
1034           contextClientTmp->sendEvent(event);
1035         }
1036         else contextClientTmp->sendEvent(event);
1037     }
1038   }
1039
1040   //! Server side: Receive a message of client annoucing calendar update
1041   void CContext::recvUpdateCalendar(CEventServer& event)
1042   {
1043      CBufferIn* buffer=event.subEvents.begin()->buffer;
1044      string id;
1045      *buffer>>id;
1046      get(id)->recvUpdateCalendar(*buffer);
1047   }
1048
1049   //! Server side: Receive a message of client annoucing calendar update
1050   void CContext::recvUpdateCalendar(CBufferIn& buffer)
1051   {
1052      int step;
1053      buffer>>step;
1054      updateCalendar(step);
1055      if (hasClient && hasServer)
1056      {       
1057        sendUpdateCalendar(step);
1058      }
1059   }
1060
1061   //! Client side: Send a message to create header part of netcdf file
1062   void CContext::sendCreateFileHeader(void)
1063   {
1064     // Use correct context client to send message
1065     // int nbSrvPools = (hasServer) ? clientPrimServer.size() : 1;
1066     int nbSrvPools = (this->hasServer) ? (this->hasClient ? this->clientPrimServer.size() : 0) : 1;
1067     for (int i = 0; i < nbSrvPools; ++i)
1068     {
1069       CContextClient* contextClientTmp = (hasServer) ? clientPrimServer[i] : client;
1070       CEventClient event(getType(),EVENT_ID_CREATE_FILE_HEADER);
1071
1072       if (contextClientTmp->isServerLeader())
1073       {
1074         CMessage msg;
1075         if (hasServer)
1076           msg<<this->getIdServer(i);
1077         else
1078           msg<<this->getIdServer();
1079         const std::list<int>& ranks = contextClientTmp->getRanksServerLeader();
1080         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
1081           event.push(*itRank,1,msg) ;
1082         contextClientTmp->sendEvent(event);
1083       }
1084       else contextClientTmp->sendEvent(event);
1085     }
1086   }
1087
1088   //! Server side: Receive a message of client annoucing the creation of header part of netcdf file
1089   void CContext::recvCreateFileHeader(CEventServer& event)
1090   {
1091      CBufferIn* buffer=event.subEvents.begin()->buffer;
1092      string id;
1093      *buffer>>id;
1094      get(id)->recvCreateFileHeader(*buffer);
1095   }
1096
1097   //! Server side: Receive a message of client annoucing the creation of header part of netcdf file
1098   void CContext::recvCreateFileHeader(CBufferIn& buffer)
1099   {
1100      if (!hasClient && hasServer) 
1101        createFileHeader();
1102   }
1103
1104   //! Client side: Send a message to do some post processing on server
1105   void CContext::sendProcessingGridOfEnabledFields()
1106   {
1107      // Use correct context client to send message
1108     int nbSrvPools = (this->hasServer) ? (this->hasClient ? this->clientPrimServer.size() : 0) : 1;
1109     for (int i = 0; i < nbSrvPools; ++i)
1110     {
1111       CContextClient* contextClientTmp = (0 != clientPrimServer.size()) ? clientPrimServer[i] : client;
1112       CEventClient event(getType(),EVENT_ID_PROCESS_GRID_ENABLED_FIELDS);
1113
1114       if (contextClientTmp->isServerLeader())
1115       {
1116         CMessage msg;
1117         if (hasServer)
1118           msg<<this->getIdServer(i);
1119         else
1120           msg<<this->getIdServer();
1121         const std::list<int>& ranks = contextClientTmp->getRanksServerLeader();
1122         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
1123           event.push(*itRank,1,msg);
1124         contextClientTmp->sendEvent(event);
1125       }
1126       else contextClientTmp->sendEvent(event);
1127     }
1128   }
1129
1130   //! Server side: Receive a message to do some post processing
1131   void CContext::recvProcessingGridOfEnabledFields(CEventServer& event)
1132   {
1133      CBufferIn* buffer=event.subEvents.begin()->buffer;
1134      string id;
1135      *buffer>>id;     
1136   }
1137
1138   //! Client side: Send a message to do some post processing on server
1139   void CContext::sendPostProcessing()
1140   {
1141      // Use correct context client to send message
1142     // int nbSrvPools = (hasServer) ? clientPrimServer.size() : 1;
1143     int nbSrvPools = (this->hasServer) ? (this->hasClient ? this->clientPrimServer.size() : 0) : 1;
1144     for (int i = 0; i < nbSrvPools; ++i)
1145     {
1146       CContextClient* contextClientTmp = (hasServer) ? clientPrimServer[i] : client;
1147       CEventClient event(getType(),EVENT_ID_POST_PROCESS);
1148       if (contextClientTmp->isServerLeader())
1149       {
1150         CMessage msg;
1151         if (hasServer)
1152           msg<<this->getIdServer(i);
1153         else
1154           msg<<this->getIdServer();
1155         const std::list<int>& ranks = contextClientTmp->getRanksServerLeader();
1156         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
1157         event.push(*itRank,1,msg);
1158         contextClientTmp->sendEvent(event);
1159       }
1160       else contextClientTmp->sendEvent(event);
1161     }
1162   }
1163
1164   //! Server side: Receive a message to do some post processing
1165   void CContext::recvPostProcessing(CEventServer& event)
1166   {
1167      CBufferIn* buffer=event.subEvents.begin()->buffer;
1168      string id;
1169      *buffer>>id;
1170      get(id)->recvPostProcessing(*buffer);
1171   }
1172
1173   //! Server side: Receive a message to do some post processing
1174   void CContext::recvPostProcessing(CBufferIn& buffer)
1175   {
1176      CCalendarWrapper::get(CCalendarWrapper::GetDefName())->createCalendar();
1177      postProcessing();
1178   }
1179
1180   const StdString& CContext::getIdServer()
1181   {
1182      if (hasClient)
1183      {
1184        idServer_ = this->getId();
1185        idServer_ += "_server";
1186        return idServer_;
1187      }
1188      if (hasServer) return (this->getId());
1189   }
1190
1191   const StdString& CContext::getIdServer(const int i)
1192   {
1193     idServer_ = this->getId();
1194     idServer_ += "_server_";
1195     idServer_ += boost::lexical_cast<string>(i);
1196     return idServer_;
1197   }
1198
1199
1200   /*!
1201   \brief Do some simple post processings after parsing xml file
1202      After the xml file (iodef.xml) is parsed, it is necessary to build all relations among
1203   created object, e.g: inhertance among fields, domain, axis. After that, all fiels as well as their parents (reference fields),
1204   which will be written out into netcdf files, are processed
1205   */
1206   void CContext::postProcessing()
1207   {
1208     if (isPostProcessed) return;
1209
1210      // Make sure the calendar was correctly created
1211      if (!calendar)
1212        ERROR("CContext::postProcessing()", << "A calendar must be defined for the context \"" << getId() << "!\"")
1213      else if (calendar->getTimeStep() == NoneDu)
1214        ERROR("CContext::postProcessing()", << "A timestep must be defined for the context \"" << getId() << "!\"")
1215      // Calendar first update to set the current date equals to the start date
1216      calendar->update(0);
1217
1218      // Find all inheritance in xml structure
1219      this->solveAllInheritance();
1220
1221//      ShowTree(info(10));
1222
1223      // Check if some axis, domains or grids are eligible to for compressed indexed output.
1224      // Warning: This must be done after solving the inheritance and before the rest of post-processing
1225      checkAxisDomainsGridsEligibilityForCompressedOutput();     
1226
1227      // Check if some automatic time series should be generated
1228      // Warning: This must be done after solving the inheritance and before the rest of post-processing     
1229
1230      // The timeseries should only be prepared in client
1231      if (hasClient && !hasServer) prepareTimeseries();
1232
1233      //Initialisation du vecteur 'enabledFiles' contenant la liste des fichiers à sortir.
1234      this->findEnabledFiles();
1235     
1236      // For now, only read files with client and only one level server
1237      if (hasClient && !hasServer) this->findEnabledReadModeFiles();
1238
1239      // Find all enabled fields of each file
1240      this->findAllEnabledFields();
1241      // For now, only read files with client and only one level server
1242      if (hasClient && !hasServer) this->findAllEnabledFieldsInReadModeFiles();
1243
1244
1245      if (hasClient && !hasServer)
1246      {
1247       // Try to read attributes of fields in file then fill in corresponding grid (or domain, axis)
1248       this->readAttributesOfEnabledFieldsInReadModeFiles();
1249      }
1250
1251      // Only search and rebuild all reference objects of enable fields, don't transform
1252      this->solveOnlyRefOfEnabledFields(false);
1253
1254      // Search and rebuild all reference object of enabled fields, and transform
1255      this->solveAllRefOfEnabledFieldsAndTransform(false);
1256
1257      // Find all fields with read access from the public API
1258      if (hasClient && !hasServer) findFieldsWithReadAccess();
1259      // and solve the all reference for them
1260      if (hasClient && !hasServer) solveAllRefOfFieldsWithReadAccess();
1261
1262      isPostProcessed = true;
1263   }
1264
1265   /*!
1266    * Compute the required buffer size to send the attributes (mostly those grid related).
1267    *
1268    * \param maxEventSize [in/out] the size of the bigger event for each connected server
1269    */
1270   std::map<int, StdSize> CContext::getAttributesBufferSize(std::map<int, StdSize>& maxEventSize, CContextClient* contextClient)
1271   {
1272     std::map<int, StdSize> attributesSize;
1273
1274     if (hasClient)
1275     {
1276       size_t numEnabledFiles = this->enabledFiles.size();
1277       for (size_t i = 0; i < numEnabledFiles; ++i)
1278       {
1279         CFile* file = this->enabledFiles[i];
1280//         if (file->getContextClient() == contextClient)
1281         {
1282           std::vector<CField*> enabledFields = file->getEnabledFields();
1283           size_t numEnabledFields = enabledFields.size();
1284           for (size_t j = 0; j < numEnabledFields; ++j)
1285           {
1286             const std::map<int, StdSize> mapSize = enabledFields[j]->getGridAttributesBufferSize();
1287             std::map<int, StdSize>::const_iterator it = mapSize.begin(), itE = mapSize.end();
1288             for (; it != itE; ++it)
1289             {
1290               // If attributesSize[it->first] does not exist, it will be zero-initialized
1291               // so we can use it safely without checking for its existance
1292               if (attributesSize[it->first] < it->second)
1293                 attributesSize[it->first] = it->second;
1294
1295               if (maxEventSize[it->first] < it->second)
1296                 maxEventSize[it->first] = it->second;
1297             }
1298           }
1299         }
1300       }
1301     }
1302
1303     return attributesSize;
1304   }
1305
1306   /*!
1307    * Compute the required buffer size to send the fields data.
1308    *
1309    * \param maxEventSize [in/out] the size of the bigger event for each connected server
1310    */
1311   std::map<int, StdSize> CContext::getDataBufferSize(std::map<int, StdSize>& maxEventSize, CContextClient* contextClient)
1312   {
1313     CFile::mode_attr::t_enum mode = hasClient ? CFile::mode_attr::write : CFile::mode_attr::read;
1314
1315     std::map<int, StdSize> dataSize;
1316
1317     // Find all reference domain and axis of all active fields
1318     size_t numEnabledFiles = this->enabledFiles.size();
1319     for (size_t i = 0; i < numEnabledFiles; ++i)
1320     {
1321       CFile* file = this->enabledFiles[i];
1322       if (file->getContextClient() == contextClient)
1323       {
1324         CFile::mode_attr::t_enum fileMode = file->mode.isEmpty() ? CFile::mode_attr::write : file->mode.getValue();
1325
1326         if (fileMode == mode)
1327         {
1328           std::vector<CField*> enabledFields = file->getEnabledFields();
1329           size_t numEnabledFields = enabledFields.size();
1330           for (size_t j = 0; j < numEnabledFields; ++j)
1331           {
1332             const std::vector<std::map<int, StdSize> > mapSize = enabledFields[j]->getGridDataBufferSize();
1333             for (size_t c = 0; c < mapSize.size(); ++c)
1334             {
1335               std::map<int, StdSize>::const_iterator it = mapSize[c].begin(), itE = mapSize[c].end();
1336               for (; it != itE; ++it)
1337               {
1338                 // If dataSize[it->first] does not exist, it will be zero-initialized
1339                 // so we can use it safely without checking for its existance
1340                 if (CXios::isOptPerformance)
1341                   dataSize[it->first] += it->second;
1342                 else if (dataSize[it->first] < it->second)
1343                   dataSize[it->first] = it->second;
1344
1345                 if (maxEventSize[it->first] < it->second)
1346                   maxEventSize[it->first] = it->second;
1347               }
1348             }
1349           }
1350         }
1351       }
1352     }
1353
1354     return dataSize;
1355   }
1356
1357   //! Client side: Send infomation of active files (files are enabled to write out)
1358   void CContext::sendEnabledFiles()
1359   {
1360     int size = this->enabledFiles.size();
1361
1362     // In a context, each type has a root definition, e.g: axis, domain, field.
1363     // Every object must be a child of one of these root definition. In this case
1364     // all new file objects created on server must be children of the root "file_definition"
1365     StdString fileDefRoot("file_definition");
1366     CFileGroup* cfgrpPtr = CFileGroup::get(fileDefRoot);
1367
1368     for (int i = 0; i < size; ++i)
1369     {
1370       cfgrpPtr->sendCreateChild(this->enabledFiles[i]->getId(),enabledFiles[i]->getContextClient());
1371       this->enabledFiles[i]->sendAllAttributesToServer(enabledFiles[i]->getContextClient());
1372       this->enabledFiles[i]->sendAddAllVariables(enabledFiles[i]->getContextClient());
1373     }
1374   }
1375
1376   //! Client side: Send information of active fields (ones are written onto files)
1377   void CContext::sendEnabledFields()
1378   {
1379     int size = this->enabledFiles.size();
1380     for (int i = 0; i < size; ++i)
1381     {
1382       this->enabledFiles[i]->sendEnabledFields(enabledFiles[i]->getContextClient());
1383     }
1384   }
1385
1386   //! Client side: Check if the defined axis, domains and grids are eligible for compressed indexed output
1387   void CContext::checkAxisDomainsGridsEligibilityForCompressedOutput()
1388   {
1389     if (!hasClient) return;
1390
1391     const vector<CAxis*> allAxis = CAxis::getAll();
1392     for (vector<CAxis*>::const_iterator it = allAxis.begin(); it != allAxis.end(); it++)
1393       (*it)->checkEligibilityForCompressedOutput();
1394
1395     const vector<CDomain*> allDomains = CDomain::getAll();
1396     for (vector<CDomain*>::const_iterator it = allDomains.begin(); it != allDomains.end(); it++)
1397       (*it)->checkEligibilityForCompressedOutput();
1398
1399     const vector<CGrid*> allGrids = CGrid::getAll();
1400     for (vector<CGrid*>::const_iterator it = allGrids.begin(); it != allGrids.end(); it++)
1401       (*it)->checkEligibilityForCompressedOutput();
1402   }
1403
1404   //! Client side: Prepare the timeseries by adding the necessary files
1405   void CContext::prepareTimeseries()
1406   {
1407     if (!hasClient) return;
1408
1409     const std::vector<CFile*> allFiles = CFile::getAll();
1410     for (size_t i = 0; i < allFiles.size(); i++)
1411     {
1412       CFile* file = allFiles[i];
1413
1414       std::vector<CVariable*> fileVars, fieldVars, vars = file->getAllVariables();
1415       for (size_t k = 0; k < vars.size(); k++)
1416       {
1417         CVariable* var = vars[k];
1418
1419         if (var->ts_target.isEmpty()
1420              || var->ts_target == CVariable::ts_target_attr::file || var->ts_target == CVariable::ts_target_attr::both)
1421           fileVars.push_back(var);
1422
1423         if (!var->ts_target.isEmpty()
1424              && (var->ts_target == CVariable::ts_target_attr::field || var->ts_target == CVariable::ts_target_attr::both))
1425           fieldVars.push_back(var);
1426       }
1427
1428       if (!file->timeseries.isEmpty() && file->timeseries != CFile::timeseries_attr::none)
1429       {
1430         StdString fileNameStr("%file_name%") ;
1431         StdString tsPrefix = !file->ts_prefix.isEmpty() ? file->ts_prefix : fileNameStr ;
1432         
1433         StdString fileName=file->getFileOutputName();
1434         size_t pos=tsPrefix.find(fileNameStr) ;
1435         while (pos!=std::string::npos)
1436         {
1437           tsPrefix=tsPrefix.replace(pos,fileNameStr.size(),fileName) ;
1438           pos=tsPrefix.find(fileNameStr) ;
1439         }
1440       
1441         const std::vector<CField*> allFields = file->getAllFields();
1442         for (size_t j = 0; j < allFields.size(); j++)
1443         {
1444           CField* field = allFields[j];
1445
1446           if (!field->ts_enabled.isEmpty() && field->ts_enabled)
1447           {
1448             CFile* tsFile = CFile::create();
1449             tsFile->duplicateAttributes(file);
1450
1451             // Add variables originating from file and targeted to timeserie file
1452             for (size_t k = 0; k < fileVars.size(); k++)
1453               tsFile->getVirtualVariableGroup()->addChild(fileVars[k]);
1454
1455           
1456             tsFile->name = tsPrefix + "_";
1457             if (!field->name.isEmpty())
1458               tsFile->name.get() += field->name;
1459             else if (field->hasDirectFieldReference()) // We cannot use getBaseFieldReference() just yet
1460               tsFile->name.get() += field->field_ref;
1461             else
1462               tsFile->name.get() += field->getId();
1463
1464             if (!field->ts_split_freq.isEmpty())
1465               tsFile->split_freq = field->ts_split_freq;
1466
1467             CField* tsField = tsFile->addField();
1468             tsField->field_ref = field->getId();
1469
1470             // Add variables originating from file and targeted to timeserie field
1471             for (size_t k = 0; k < fieldVars.size(); k++)
1472               tsField->getVirtualVariableGroup()->addChild(fieldVars[k]);
1473
1474             vars = field->getAllVariables();
1475             for (size_t k = 0; k < vars.size(); k++)
1476             {
1477               CVariable* var = vars[k];
1478
1479               // Add variables originating from field and targeted to timeserie field
1480               if (var->ts_target.isEmpty()
1481                    || var->ts_target == CVariable::ts_target_attr::field || var->ts_target == CVariable::ts_target_attr::both)
1482                 tsField->getVirtualVariableGroup()->addChild(var);
1483
1484               // Add variables originating from field and targeted to timeserie file
1485               if (!var->ts_target.isEmpty()
1486                    && (var->ts_target == CVariable::ts_target_attr::file || var->ts_target == CVariable::ts_target_attr::both))
1487                 tsFile->getVirtualVariableGroup()->addChild(var);
1488             }
1489
1490             tsFile->solveFieldRefInheritance(true);
1491
1492             if (file->timeseries == CFile::timeseries_attr::exclusive)
1493               field->enabled = false;
1494           }
1495         }
1496
1497         // Finally disable the original file is need be
1498         if (file->timeseries == CFile::timeseries_attr::only)
1499          file->enabled = false;
1500       }
1501     }
1502   }
1503
1504   //! Client side: Send information of reference grid of active fields
1505   void CContext::sendRefGrid()
1506   {
1507     std::set<StdString> gridIds;
1508     int sizeFile = this->enabledFiles.size();
1509     CFile* filePtr(NULL);
1510
1511     // Firstly, find all reference grids of all active fields
1512     for (int i = 0; i < sizeFile; ++i)
1513     {
1514       filePtr = this->enabledFiles[i];
1515       std::vector<CField*> enabledFields = filePtr->getEnabledFields();
1516       int sizeField = enabledFields.size();
1517       for (int numField = 0; numField < sizeField; ++numField)
1518       {
1519         if (0 != enabledFields[numField]->getRelGrid())
1520           gridIds.insert(CGrid::get(enabledFields[numField]->getRelGrid())->getId());
1521       }
1522     }
1523
1524     // Create all reference grids on server side
1525     StdString gridDefRoot("grid_definition");
1526     CGridGroup* gridPtr = CGridGroup::get(gridDefRoot);
1527     std::set<StdString>::const_iterator it, itE = gridIds.end();
1528     for (it = gridIds.begin(); it != itE; ++it)
1529     {
1530       gridPtr->sendCreateChild(*it);
1531       CGrid::get(*it)->sendAllAttributesToServer();
1532       CGrid::get(*it)->sendAllDomains();
1533       CGrid::get(*it)->sendAllAxis();
1534       CGrid::get(*it)->sendAllScalars();
1535     }
1536   }
1537
1538
1539   //! Client side: Send information of reference domain and axis of active fields
1540   void CContext::sendRefDomainsAxis()
1541   {
1542     std::set<StdString> domainIds, axisIds, scalarIds;
1543
1544     // Find all reference domain and axis of all active fields
1545     int numEnabledFiles = this->enabledFiles.size();
1546     for (int i = 0; i < numEnabledFiles; ++i)
1547     {
1548       std::vector<CField*> enabledFields = this->enabledFiles[i]->getEnabledFields();
1549       int numEnabledFields = enabledFields.size();
1550       for (int j = 0; j < numEnabledFields; ++j)
1551       {
1552         const std::vector<StdString>& prDomAxisScalarId = enabledFields[j]->getRefDomainAxisIds();
1553         if ("" != prDomAxisScalarId[0]) domainIds.insert(prDomAxisScalarId[0]);
1554         if ("" != prDomAxisScalarId[1]) axisIds.insert(prDomAxisScalarId[1]);
1555         if ("" != prDomAxisScalarId[2]) scalarIds.insert(prDomAxisScalarId[2]);
1556       }
1557     }
1558
1559     // Create all reference axis on server side
1560     std::set<StdString>::iterator itDom, itAxis, itScalar;
1561     std::set<StdString>::const_iterator itE;
1562
1563     StdString scalarDefRoot("scalar_definition");
1564     CScalarGroup* scalarPtr = CScalarGroup::get(scalarDefRoot);
1565     itE = scalarIds.end();
1566     for (itScalar = scalarIds.begin(); itScalar != itE; ++itScalar)
1567     {
1568       if (!itScalar->empty())
1569       {
1570         scalarPtr->sendCreateChild(*itScalar);
1571         CScalar::get(*itScalar)->sendAllAttributesToServer();
1572       }
1573     }
1574
1575     StdString axiDefRoot("axis_definition");
1576     CAxisGroup* axisPtr = CAxisGroup::get(axiDefRoot);
1577     itE = axisIds.end();
1578     for (itAxis = axisIds.begin(); itAxis != itE; ++itAxis)
1579     {
1580       if (!itAxis->empty())
1581       {
1582         axisPtr->sendCreateChild(*itAxis);
1583         CAxis::get(*itAxis)->sendAllAttributesToServer();
1584       }
1585     }
1586
1587     // Create all reference domains on server side
1588     StdString domDefRoot("domain_definition");
1589     CDomainGroup* domPtr = CDomainGroup::get(domDefRoot);
1590     itE = domainIds.end();
1591     for (itDom = domainIds.begin(); itDom != itE; ++itDom)
1592     {
1593       if (!itDom->empty()) {
1594          domPtr->sendCreateChild(*itDom);
1595          CDomain::get(*itDom)->sendAllAttributesToServer();
1596       }
1597     }
1598   }
1599
1600   //! Update calendar in each time step
1601   void CContext::updateCalendar(int step)
1602   {
1603      info(50) << "updateCalendar : before : " << calendar->getCurrentDate() << endl;
1604      calendar->update(step);
1605      info(50) << "updateCalendar : after : " << calendar->getCurrentDate() << endl;
1606#ifdef XIOS_MEMTRACK_LIGHT
1607      info(50) << " Current memory used by XIOS : "<<  MemTrack::getCurrentMemorySize()*1.0/(1024*1024)<<" Mbyte, at timestep "<<step<<" of context "<<this->getId()<<endl ;
1608#endif
1609      if (hasClient)
1610      {
1611        checkPrefetchingOfEnabledReadModeFiles();
1612        garbageCollector.invalidate(calendar->getCurrentDate());
1613      }
1614   }
1615
1616   //! Server side: Create header of netcdf file
1617   void CContext::createFileHeader(void )
1618   {
1619      vector<CFile*>::const_iterator it;
1620
1621      for (it=enabledFiles.begin(); it != enabledFiles.end(); it++)
1622      {
1623         (*it)->initFile();
1624      }
1625   }
1626
1627   //! Get current context
1628   CContext* CContext::getCurrent(void)
1629   {
1630     return CObjectFactory::GetObject<CContext>(CObjectFactory::GetCurrentContextId()).get();
1631   }
1632
1633   /*!
1634   \brief Set context with an id be the current context
1635   \param [in] id identity of context to be set to current
1636   */
1637   void CContext::setCurrent(const string& id)
1638   {
1639     CObjectFactory::SetCurrentContextId(id);
1640     CGroupFactory::SetCurrentContextId(id);
1641   }
1642
1643  /*!
1644  \brief Create a context with specific id
1645  \param [in] id identity of new context
1646  \return pointer to the new context or already-existed one with identity id
1647  */
1648  CContext* CContext::create(const StdString& id)
1649  {
1650    CContext::setCurrent(id);
1651
1652    bool hasctxt = CContext::has(id);
1653    CContext* context = CObjectFactory::CreateObject<CContext>(id).get();
1654    getRoot();
1655    if (!hasctxt) CGroupFactory::AddChild(root, context->getShared());
1656
1657#define DECLARE_NODE(Name_, name_) \
1658    C##Name_##Definition::create(C##Name_##Definition::GetDefName());
1659#define DECLARE_NODE_PAR(Name_, name_)
1660#include "node_type.conf"
1661
1662    return (context);
1663  }
1664
1665
1666     //! Server side: Receive a message to do some post processing
1667  void CContext::recvRegistry(CEventServer& event)
1668  {
1669    CBufferIn* buffer=event.subEvents.begin()->buffer;
1670    string id;
1671    *buffer>>id;
1672    get(id)->recvRegistry(*buffer);
1673  }
1674
1675  void CContext::recvRegistry(CBufferIn& buffer)
1676  {
1677    if (server->intraCommRank==0)
1678    {
1679      CRegistry registry(server->intraComm) ;
1680      registry.fromBuffer(buffer) ;
1681      registryOut->mergeRegistry(registry) ;
1682    }
1683  }
1684
1685  void CContext::sendRegistry(void)
1686  {
1687    registryOut->hierarchicalGatherRegistry() ;
1688
1689    // Use correct context client to send message
1690    int nbSrvPools = (this->hasServer) ? (this->hasClient ? this->clientPrimServer.size() : 0) : 1;
1691    for (int i = 0; i < nbSrvPools; ++i)
1692    {
1693      CContextClient* contextClientTmp = (hasServer) ? clientPrimServer[i] : client;
1694      CEventClient event(CContext::GetType(), CContext::EVENT_ID_SEND_REGISTRY);
1695        if (contextClientTmp->isServerLeader())
1696        {
1697           CMessage msg ;
1698           if (hasServer)
1699             msg<<this->getIdServer(i);
1700           else
1701             msg<<this->getIdServer();
1702           if (contextClientTmp->clientRank==0) msg<<*registryOut ;
1703           const std::list<int>& ranks = contextClientTmp->getRanksServerLeader();
1704           for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
1705             event.push(*itRank,1,msg);
1706           contextClientTmp->sendEvent(event);
1707         }
1708         else contextClientTmp->sendEvent(event);
1709    }
1710  }
1711
1712  /*!
1713  * \fn bool CContext::isFinalized(void)
1714  * Context is finalized if it received context post finalize event.
1715  */
1716  bool CContext::isFinalized(void)
1717  {
1718    return finalized;
1719  }
1720
1721} // namespace xios
Note: See TracBrowser for help on using the repository browser.