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

Last change on this file since 1215 was 1215, checked in by ymipsl, 7 years ago

Distribute files on servers 2 -> Ok test_dcmip2

YM

  • 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#include <limits>
19#include "server.hpp"
20
21namespace xios {
22
23  shared_ptr<CContextGroup> CContext::root;
24
25   /// ////////////////////// Définitions ////////////////////// ///
26
27   CContext::CContext(void)
28      : CObjectTemplate<CContext>(), CContextAttributes()
29      , calendar(), hasClient(false), hasServer(false)
30      , isPostProcessed(false), finalized(false)
31      , idServer_(), client(0), server(0)
32      , allProcessed(false), countChildCtx_(0)
33   { /* Ne rien faire de plus */ }
34
35   CContext::CContext(const StdString & id)
36      : CObjectTemplate<CContext>(id), CContextAttributes()
37      , calendar(), hasClient(false), hasServer(false)
38      , isPostProcessed(false), finalized(false)
39      , idServer_(), client(0), server(0)
40      , allProcessed(false), countChildCtx_(0)
41   { /* Ne rien faire de plus */ }
42
43   CContext::~CContext(void)
44   {
45     delete client;
46     delete server;
47     for (std::vector<CContextClient*>::iterator it = clientPrimServer.begin(); it != clientPrimServer.end(); it++)  delete *it;
48     for (std::vector<CContextServer*>::iterator it = serverPrimServer.begin(); it != serverPrimServer.end(); it++)  delete *it;
49
50   }
51
52   //----------------------------------------------------------------
53   //! Get name of context
54   StdString CContext::GetName(void)   { return (StdString("context")); }
55   StdString CContext::GetDefName(void){ return (CContext::GetName()); }
56   ENodeType CContext::GetType(void)   { return (eContext); }
57
58   //----------------------------------------------------------------
59
60   /*!
61   \brief Get context group (context root)
62   \return Context root
63   */
64   CContextGroup* CContext::getRoot(void)
65   {
66      if (root.get()==NULL) root=shared_ptr<CContextGroup>(new CContextGroup(xml::CXMLNode::GetRootName()));
67      return root.get();
68   }
69
70   //----------------------------------------------------------------
71
72   /*!
73   \brief Get calendar of a context
74   \return Calendar
75   */
76   boost::shared_ptr<CCalendar> CContext::getCalendar(void) const
77   {
78      return (this->calendar);
79   }
80
81   //----------------------------------------------------------------
82
83   /*!
84   \brief Set a context with a calendar
85   \param[in] newCalendar new calendar
86   */
87   void CContext::setCalendar(boost::shared_ptr<CCalendar> newCalendar)
88   {
89      this->calendar = newCalendar;
90   }
91
92   //----------------------------------------------------------------
93   /*!
94   \brief Parse xml file and write information into context object
95   \param [in] node xmld node corresponding in xml file
96   */
97   void CContext::parse(xml::CXMLNode & node)
98   {
99      CContext::SuperClass::parse(node);
100
101      // PARSING POUR GESTION DES ENFANTS
102      xml::THashAttributes attributes = node.getAttributes();
103
104      if (attributes.end() != attributes.find("src"))
105      {
106         StdIFStream ifs ( attributes["src"].c_str() , StdIFStream::in );
107         if ( (ifs.rdstate() & std::ifstream::failbit ) != 0 )
108            ERROR("void CContext::parse(xml::CXMLNode & node)",
109                  <<endl<< "Can not open <"<<attributes["src"].c_str()<<"> file" );
110         if (!ifs.good())
111            ERROR("CContext::parse(xml::CXMLNode & node)",
112                  << "[ filename = " << attributes["src"] << " ] Bad xml stream !");
113         xml::CXMLParser::ParseInclude(ifs, attributes["src"], *this);
114      }
115
116      if (node.getElementName().compare(CContext::GetName()))
117         DEBUG("Le noeud is wrong defined but will be considered as a context !");
118
119      if (!(node.goToChildElement()))
120      {
121         DEBUG("Le context ne contient pas d'enfant !");
122      }
123      else
124      {
125         do { // Parcours des contextes pour traitement.
126
127            StdString name = node.getElementName();
128            attributes.clear();
129            attributes = node.getAttributes();
130
131            if (attributes.end() != attributes.find("id"))
132            {
133              DEBUG(<< "Definition node has an id,"
134                    << "it will not be taking account !");
135            }
136
137#define DECLARE_NODE(Name_, name_)    \
138   if (name.compare(C##Name_##Definition::GetDefName()) == 0) \
139   { C##Name_##Definition::create(C##Name_##Definition::GetDefName()) -> parse(node); continue; }
140#define DECLARE_NODE_PAR(Name_, name_)
141#include "node_type.conf"
142
143            DEBUG(<< "The element \'"     << name
144                  << "\' in the context \'" << CContext::getCurrent()->getId()
145                  << "\' is not a definition !");
146
147         } while (node.goToNextElement());
148
149         node.goToParentElement(); // Retour au parent
150      }
151   }
152
153   //----------------------------------------------------------------
154   //! Show tree structure of context
155   void CContext::ShowTree(StdOStream & out)
156   {
157      StdString currentContextId = CContext::getCurrent() -> getId();
158      std::vector<CContext*> def_vector =
159         CContext::getRoot()->getChildList();
160      std::vector<CContext*>::iterator
161         it = def_vector.begin(), end = def_vector.end();
162
163      out << "<? xml version=\"1.0\" ?>" << std::endl;
164      out << "<"  << xml::CXMLNode::GetRootName() << " >" << std::endl;
165
166      for (; it != end; it++)
167      {
168         CContext* context = *it;
169         CContext::setCurrent(context->getId());
170         out << *context << std::endl;
171      }
172
173      out << "</" << xml::CXMLNode::GetRootName() << " >" << std::endl;
174      CContext::setCurrent(currentContextId);
175   }
176
177
178   //----------------------------------------------------------------
179
180   //! Convert context object into string (to print)
181   StdString CContext::toString(void) const
182   {
183      StdOStringStream oss;
184      oss << "<" << CContext::GetName()
185          << " id=\"" << this->getId() << "\" "
186          << SuperClassAttribute::toString() << ">" << std::endl;
187      if (!this->hasChild())
188      {
189         //oss << "<!-- No definition -->" << std::endl; // fait planter l'incrémentation
190      }
191      else
192      {
193
194#define DECLARE_NODE(Name_, name_)    \
195   if (C##Name_##Definition::has(C##Name_##Definition::GetDefName())) \
196   oss << * C##Name_##Definition::get(C##Name_##Definition::GetDefName()) << std::endl;
197#define DECLARE_NODE_PAR(Name_, name_)
198#include "node_type.conf"
199
200      }
201
202      oss << "</" << CContext::GetName() << " >";
203
204      return (oss.str());
205   }
206
207   //----------------------------------------------------------------
208
209   /*!
210   \brief Find all inheritace among objects in a context.
211   \param [in] apply (true) write attributes of parent into ones of child if they are empty
212                     (false) write attributes of parent into a new container of child
213   \param [in] parent unused
214   */
215   void CContext::solveDescInheritance(bool apply, const CAttributeMap * const UNUSED(parent))
216   {
217#define DECLARE_NODE(Name_, name_)    \
218   if (C##Name_##Definition::has(C##Name_##Definition::GetDefName())) \
219     C##Name_##Definition::get(C##Name_##Definition::GetDefName())->solveDescInheritance(apply);
220#define DECLARE_NODE_PAR(Name_, name_)
221#include "node_type.conf"
222   }
223
224   //----------------------------------------------------------------
225
226   //! Verify if all root definition in the context have child.
227   bool CContext::hasChild(void) const
228   {
229      return (
230#define DECLARE_NODE(Name_, name_)    \
231   C##Name_##Definition::has(C##Name_##Definition::GetDefName())   ||
232#define DECLARE_NODE_PAR(Name_, name_)
233#include "node_type.conf"
234      false);
235}
236
237   //----------------------------------------------------------------
238
239   void CContext::CleanTree(void)
240   {
241#define DECLARE_NODE(Name_, name_) C##Name_##Definition::ClearAllAttributes();
242#define DECLARE_NODE_PAR(Name_, name_)
243#include "node_type.conf"
244   }
245   ///---------------------------------------------------------------
246
247   //! Initialize client side
248   void CContext::initClient(MPI_Comm intraComm, MPI_Comm interComm, CContext* cxtServer /*= 0*/)
249   {
250
251     hasClient = true;
252     MPI_Comm intraCommServer, interCommServer;
253
254     if (CServer::serverLevel != 1)
255      // initClient is called by client
256     {
257       client = new CContextClient(this, intraComm, interComm, cxtServer);
258       if (cxtServer) // Attached mode
259       {
260         intraCommServer = intraComm;
261         interCommServer = interComm;
262       }
263       else
264       {
265         MPI_Comm_dup(intraComm, &intraCommServer);
266         comms.push_back(intraCommServer);
267         MPI_Comm_dup(interComm, &interCommServer);
268         comms.push_back(interCommServer);
269       }
270       registryIn=new CRegistry(intraComm);
271       registryIn->setPath(getId()) ;
272       if (client->clientRank==0) registryIn->fromFile("xios_registry.bin") ;
273       registryIn->bcastRegistry() ;
274       registryOut=new CRegistry(intraComm) ;
275       registryOut->setPath(getId()) ;
276
277       server = new CContextServer(this, intraCommServer, interCommServer);
278     }
279     else
280     // initClient is called by primary server
281     {
282       clientPrimServer.push_back(new CContextClient(this, intraComm, interComm));
283       MPI_Comm_dup(intraComm, &intraCommServer);
284       comms.push_back(intraCommServer);
285       MPI_Comm_dup(interComm, &interCommServer);
286       comms.push_back(interCommServer);
287       serverPrimServer.push_back(new CContextServer(this, intraCommServer, interCommServer));
288     }
289   }
290
291   void CContext::setClientServerBuffer(CContextClient* contextClient)
292   {
293      // Estimated minimum event size for small events (10 is an arbitrary constant just for safety)
294      const size_t minEventSize = CEventClient::headerSize + getIdServer().size() + 10 * sizeof(int);
295
296      // Ensure there is at least some room for 20 of such events in the buffers
297      size_t minBufferSize = std::max(CXios::minBufferSize, 20 * minEventSize);
298
299#define DECLARE_NODE(Name_, name_)    \
300     if (minBufferSize < sizeof(C##Name_##Definition)) minBufferSize = sizeof(C##Name_##Definition);
301#define DECLARE_NODE_PAR(Name_, name_)
302#include "node_type.conf"
303#undef DECLARE_NODE
304#undef DECLARE_NODE_PAR
305
306     // Compute the buffer sizes needed to send the attributes and data corresponding to fields
307     std::map<int, StdSize> maxEventSize;
308     std::map<int, StdSize> bufferSize = getAttributesBufferSize(maxEventSize, contextClient);
309     std::map<int, StdSize> dataBufferSize = getDataBufferSize(maxEventSize, contextClient);
310
311     std::map<int, StdSize>::iterator it, ite = dataBufferSize.end();
312     for (it = dataBufferSize.begin(); it != ite; ++it)
313       if (it->second > bufferSize[it->first]) bufferSize[it->first] = it->second;
314
315     // Apply the buffer size factor 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     double eps=std::numeric_limits<double>::epsilon()*10 ;
825     
826     // If primary server
827     if (hasServer && hasClient)
828     {
829       int nbPools = clientPrimServer.size();
830
831       // (1) Find all enabled files in write mode
832       for (int i = 0; i < this->enabledFiles.size(); ++i)
833       {
834         if (enabledFiles[i]->mode.isEmpty() || (!enabledFiles[i]->mode.isEmpty() && enabledFiles[i]->mode.getValue() == CFile::mode_attr::write ))
835          enabledWriteModeFiles.push_back(enabledFiles[i]);
836       }
837
838       // (2) Estimate the data volume for each file
839       int size = this->enabledWriteModeFiles.size();
840       std::vector<std::pair<double, CFile*> > dataSizeMap;
841       double dataPerPool = 0;
842       int nfield=0 ;
843       for (size_t i = 0; i < size; ++i)
844       {
845         CFile* file = this->enabledWriteModeFiles[i];
846         StdSize dataSize=0;
847         std::vector<CField*> enabledFields = file->getEnabledFields();
848         size_t numEnabledFields = enabledFields.size();
849         for (size_t j = 0; j < numEnabledFields; ++j) dataSize += enabledFields[j]->getGlobalWrittenSize() ;
850
851         double outFreqSec = (Time)(calendar->getCurrentDate()+file->output_freq)-(Time)(calendar->getCurrentDate()) ;
852         double dataSizeSec= dataSize/ outFreqSec;
853         nfield++ ;
854// add epsilon*nField to dataSizeSec in order to  preserve reproductive ordering when sorting
855         dataSizeMap.push_back(make_pair(dataSizeSec + dataSizeSec * eps * nfield , file));
856         dataPerPool += dataSizeSec;
857       }
858       dataPerPool /= nbPools;
859       std::sort(dataSizeMap.begin(), dataSizeMap.end());
860
861       // (3) Assign contextClient to each enabled file
862
863       std::multimap<double,int> poolDataSize ;
864// multimap is not garanty to preserve stable sorting in c++98 but it seems it does for c++11
865
866       int j;
867       double dataSize ;
868       for (j = 0 ; j < nbPools ; ++j) poolDataSize.insert(std::pair<double,int>(0.,j)) ; 
869             
870       for (int i = dataSizeMap.size()-1; i >= 0; --i)
871       {
872         dataSize=(*poolDataSize.begin()).first ;
873         j=(*poolDataSize.begin()).second ;
874         dataSizeMap[i].second->setContextClient(clientPrimServer[j]);
875         dataSize+=dataSizeMap[i].first;
876         poolDataSize.erase(poolDataSize.begin()) ;
877         poolDataSize.insert(std::pair<double,int>(dataSize,j)) ; 
878       }
879
880       for (std::multimap<double,int>:: iterator it=poolDataSize.begin() ; it!=poolDataSize.end(); ++it) info(30)<<"Load Balancing for servers (perfect=1) : "<<it->second<<" :  ratio "<<it->first*1./dataPerPool<<endl ;
881 
882       for (int i = 0; i < this->enabledReadModeFiles.size(); ++i)
883         enabledReadModeFiles[i]->setContextClient(client);
884     }
885     else
886     {
887       for (int i = 0; i < this->enabledFiles.size(); ++i)
888         enabledFiles[i]->setContextClient(client);
889     }
890   }
891
892   void CContext::findEnabledReadModeFiles(void)
893   {
894     int size = this->enabledFiles.size();
895     for (int i = 0; i < size; ++i)
896     {
897       if (!enabledFiles[i]->mode.isEmpty() && enabledFiles[i]->mode.getValue() == CFile::mode_attr::read)
898        enabledReadModeFiles.push_back(enabledFiles[i]);
899     }
900   }
901
902   void CContext::closeAllFile(void)
903   {
904     std::vector<CFile*>::const_iterator
905            it = this->enabledFiles.begin(), end = this->enabledFiles.end();
906
907     for (; it != end; it++)
908     {
909       info(30)<<"Closing File : "<<(*it)->getId()<<endl;
910       (*it)->close();
911     }
912   }
913
914   /*!
915   \brief Dispatch event received from client
916      Whenever a message is received in buffer of server, it will be processed depending on
917   its event type. A new event type should be added in the switch list to make sure
918   it processed on server side.
919   \param [in] event: Received message
920   */
921   bool CContext::dispatchEvent(CEventServer& event)
922   {
923
924      if (SuperClass::dispatchEvent(event)) return true;
925      else
926      {
927        switch(event.type)
928        {
929           case EVENT_ID_CLOSE_DEFINITION :
930             recvCloseDefinition(event);
931             return true;
932             break;
933           case EVENT_ID_UPDATE_CALENDAR:
934             recvUpdateCalendar(event);
935             return true;
936             break;
937           case EVENT_ID_CREATE_FILE_HEADER :
938             recvCreateFileHeader(event);
939             return true;
940             break;
941           case EVENT_ID_POST_PROCESS:
942             recvPostProcessing(event);
943             return true;
944            case EVENT_ID_SEND_REGISTRY:
945             recvRegistry(event);
946             return true;
947             break;
948            case EVENT_ID_POST_PROCESS_GLOBAL_ATTRIBUTES:
949             recvPostProcessingGlobalAttributes(event);
950             return true;
951             break;
952            case EVENT_ID_PROCESS_GRID_ENABLED_FIELDS:
953             recvProcessingGridOfEnabledFields(event);
954             return true;
955             break;
956           default :
957             ERROR("bool CContext::dispatchEvent(CEventServer& event)",
958                    <<"Unknown Event");
959           return false;
960         }
961      }
962   }
963
964   //! Client side: Send a message to server to make it close
965   void CContext::sendCloseDefinition(void)
966   {
967     // Use correct context client to send message
968     int nbSrvPools = (this->hasServer) ? (this->hasClient ? this->clientPrimServer.size() : 0) : 1;
969     for (int i = 0; i < nbSrvPools; ++i)
970     {
971       CContextClient* contextClientTmp = (hasServer) ? clientPrimServer[i] : client;
972       CEventClient event(getType(),EVENT_ID_CLOSE_DEFINITION);
973       if (contextClientTmp->isServerLeader())
974       {
975         CMessage msg;
976         if (hasServer)
977           msg<<this->getIdServer(i);
978         else
979           msg<<this->getIdServer();
980         const std::list<int>& ranks = contextClientTmp->getRanksServerLeader();
981         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
982           event.push(*itRank,1,msg);
983         contextClientTmp->sendEvent(event);
984       }
985       else contextClientTmp->sendEvent(event);
986     }
987   }
988
989   //! Server side: Receive a message of client announcing a context close
990   void CContext::recvCloseDefinition(CEventServer& event)
991   {
992      CBufferIn* buffer=event.subEvents.begin()->buffer;
993      string id;
994      *buffer>>id;
995      get(id)->closeDefinition();
996   }
997
998   //! Client side: Send a message to update calendar in each time step
999   void CContext::sendUpdateCalendar(int step)
1000   {
1001     // Use correct context client to send message
1002    int nbSrvPools = (this->hasServer) ? (this->hasClient ? this->clientPrimServer.size() : 0) : 1;
1003     for (int i = 0; i < nbSrvPools; ++i)
1004     {
1005       CContextClient* contextClientTmp = (hasServer) ? clientPrimServer[i] : client;
1006       CEventClient event(getType(),EVENT_ID_UPDATE_CALENDAR);
1007
1008         if (contextClientTmp->isServerLeader())
1009         {
1010           CMessage msg;
1011           if (hasServer)
1012             msg<<this->getIdServer(i)<<step;
1013           else
1014             msg<<this->getIdServer()<<step;
1015           const std::list<int>& ranks = contextClientTmp->getRanksServerLeader();
1016           for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
1017             event.push(*itRank,1,msg);
1018           contextClientTmp->sendEvent(event);
1019         }
1020         else contextClientTmp->sendEvent(event);
1021     }
1022   }
1023
1024   //! Server side: Receive a message of client annoucing calendar update
1025   void CContext::recvUpdateCalendar(CEventServer& event)
1026   {
1027      CBufferIn* buffer=event.subEvents.begin()->buffer;
1028      string id;
1029      *buffer>>id;
1030      get(id)->recvUpdateCalendar(*buffer);
1031   }
1032
1033   //! Server side: Receive a message of client annoucing calendar update
1034   void CContext::recvUpdateCalendar(CBufferIn& buffer)
1035   {
1036      int step;
1037      buffer>>step;
1038      updateCalendar(step);
1039      if (hasClient && hasServer)
1040      {       
1041        sendUpdateCalendar(step);
1042      }
1043   }
1044
1045   //! Client side: Send a message to create header part of netcdf file
1046   void CContext::sendCreateFileHeader(void)
1047   {
1048     // Use correct context client to send message
1049     // int nbSrvPools = (hasServer) ? clientPrimServer.size() : 1;
1050     int nbSrvPools = (this->hasServer) ? (this->hasClient ? this->clientPrimServer.size() : 0) : 1;
1051     for (int i = 0; i < nbSrvPools; ++i)
1052     {
1053       CContextClient* contextClientTmp = (hasServer) ? clientPrimServer[i] : client;
1054       CEventClient event(getType(),EVENT_ID_CREATE_FILE_HEADER);
1055
1056       if (contextClientTmp->isServerLeader())
1057       {
1058         CMessage msg;
1059         if (hasServer)
1060           msg<<this->getIdServer(i);
1061         else
1062           msg<<this->getIdServer();
1063         const std::list<int>& ranks = contextClientTmp->getRanksServerLeader();
1064         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
1065           event.push(*itRank,1,msg) ;
1066         contextClientTmp->sendEvent(event);
1067       }
1068       else contextClientTmp->sendEvent(event);
1069     }
1070   }
1071
1072   //! Server side: Receive a message of client annoucing the creation of header part of netcdf file
1073   void CContext::recvCreateFileHeader(CEventServer& event)
1074   {
1075      CBufferIn* buffer=event.subEvents.begin()->buffer;
1076      string id;
1077      *buffer>>id;
1078      get(id)->recvCreateFileHeader(*buffer);
1079   }
1080
1081   //! Server side: Receive a message of client annoucing the creation of header part of netcdf file
1082   void CContext::recvCreateFileHeader(CBufferIn& buffer)
1083   {
1084      if (!hasClient && hasServer) 
1085        createFileHeader();
1086   }
1087
1088   //! Client side: Send a message to do some post processing on server
1089   void CContext::sendProcessingGridOfEnabledFields()
1090   {
1091      // Use correct context client to send message
1092     int nbSrvPools = (this->hasServer) ? (this->hasClient ? this->clientPrimServer.size() : 0) : 1;
1093     for (int i = 0; i < nbSrvPools; ++i)
1094     {
1095       CContextClient* contextClientTmp = (0 != clientPrimServer.size()) ? clientPrimServer[i] : client;
1096       CEventClient event(getType(),EVENT_ID_PROCESS_GRID_ENABLED_FIELDS);
1097
1098       if (contextClientTmp->isServerLeader())
1099       {
1100         CMessage msg;
1101         if (hasServer)
1102           msg<<this->getIdServer(i);
1103         else
1104           msg<<this->getIdServer();
1105         const std::list<int>& ranks = contextClientTmp->getRanksServerLeader();
1106         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
1107           event.push(*itRank,1,msg);
1108         contextClientTmp->sendEvent(event);
1109       }
1110       else contextClientTmp->sendEvent(event);
1111     }
1112   }
1113
1114   //! Server side: Receive a message to do some post processing
1115   void CContext::recvProcessingGridOfEnabledFields(CEventServer& event)
1116   {
1117      CBufferIn* buffer=event.subEvents.begin()->buffer;
1118      string id;
1119      *buffer>>id;     
1120   }
1121
1122   //! Client side: Send a message to do some post processing on server
1123   void CContext::sendPostProcessing()
1124   {
1125      // Use correct context client to send message
1126     // int nbSrvPools = (hasServer) ? clientPrimServer.size() : 1;
1127     int nbSrvPools = (this->hasServer) ? (this->hasClient ? this->clientPrimServer.size() : 0) : 1;
1128     for (int i = 0; i < nbSrvPools; ++i)
1129     {
1130       CContextClient* contextClientTmp = (hasServer) ? clientPrimServer[i] : client;
1131       CEventClient event(getType(),EVENT_ID_POST_PROCESS);
1132       if (contextClientTmp->isServerLeader())
1133       {
1134         CMessage msg;
1135         if (hasServer)
1136           msg<<this->getIdServer(i);
1137         else
1138           msg<<this->getIdServer();
1139         const std::list<int>& ranks = contextClientTmp->getRanksServerLeader();
1140         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
1141         event.push(*itRank,1,msg);
1142         contextClientTmp->sendEvent(event);
1143       }
1144       else contextClientTmp->sendEvent(event);
1145     }
1146   }
1147
1148   //! Server side: Receive a message to do some post processing
1149   void CContext::recvPostProcessing(CEventServer& event)
1150   {
1151      CBufferIn* buffer=event.subEvents.begin()->buffer;
1152      string id;
1153      *buffer>>id;
1154      get(id)->recvPostProcessing(*buffer);
1155   }
1156
1157   //! Server side: Receive a message to do some post processing
1158   void CContext::recvPostProcessing(CBufferIn& buffer)
1159   {
1160      CCalendarWrapper::get(CCalendarWrapper::GetDefName())->createCalendar();
1161      postProcessing();
1162   }
1163
1164   const StdString& CContext::getIdServer()
1165   {
1166      if (hasClient)
1167      {
1168        idServer_ = this->getId();
1169        idServer_ += "_server";
1170        return idServer_;
1171      }
1172      if (hasServer) return (this->getId());
1173   }
1174
1175   const StdString& CContext::getIdServer(const int i)
1176   {
1177     idServer_ = this->getId();
1178     idServer_ += "_server_";
1179     idServer_ += boost::lexical_cast<string>(i);
1180     return idServer_;
1181   }
1182
1183
1184   /*!
1185   \brief Do some simple post processings after parsing xml file
1186      After the xml file (iodef.xml) is parsed, it is necessary to build all relations among
1187   created object, e.g: inhertance among fields, domain, axis. After that, all fiels as well as their parents (reference fields),
1188   which will be written out into netcdf files, are processed
1189   */
1190   void CContext::postProcessing()
1191   {
1192     if (isPostProcessed) return;
1193
1194      // Make sure the calendar was correctly created
1195      if (!calendar)
1196        ERROR("CContext::postProcessing()", << "A calendar must be defined for the context \"" << getId() << "!\"")
1197      else if (calendar->getTimeStep() == NoneDu)
1198        ERROR("CContext::postProcessing()", << "A timestep must be defined for the context \"" << getId() << "!\"")
1199      // Calendar first update to set the current date equals to the start date
1200      calendar->update(0);
1201
1202      // Find all inheritance in xml structure
1203      this->solveAllInheritance();
1204
1205//      ShowTree(info(10));
1206
1207      // Check if some axis, domains or grids are eligible to for compressed indexed output.
1208      // Warning: This must be done after solving the inheritance and before the rest of post-processing
1209      checkAxisDomainsGridsEligibilityForCompressedOutput();     
1210
1211      // Check if some automatic time series should be generated
1212      // Warning: This must be done after solving the inheritance and before the rest of post-processing     
1213
1214      // The timeseries should only be prepared in client
1215      if (hasClient && !hasServer) prepareTimeseries();
1216
1217      //Initialisation du vecteur 'enabledFiles' contenant la liste des fichiers à sortir.
1218      this->findEnabledFiles();
1219     
1220      // For now, only read files with client and only one level server
1221      if (hasClient && !hasServer) this->findEnabledReadModeFiles();
1222
1223      // Find all enabled fields of each file
1224      this->findAllEnabledFields();
1225      // For now, only read files with client and only one level server
1226      if (hasClient && !hasServer) this->findAllEnabledFieldsInReadModeFiles();
1227
1228
1229      if (hasClient && !hasServer)
1230      {
1231       // Try to read attributes of fields in file then fill in corresponding grid (or domain, axis)
1232       this->readAttributesOfEnabledFieldsInReadModeFiles();
1233      }
1234
1235      // Only search and rebuild all reference objects of enable fields, don't transform
1236      this->solveOnlyRefOfEnabledFields(false);
1237
1238      // Search and rebuild all reference object of enabled fields, and transform
1239      this->solveAllRefOfEnabledFieldsAndTransform(false);
1240
1241      // Find all fields with read access from the public API
1242      if (hasClient && !hasServer) findFieldsWithReadAccess();
1243      // and solve the all reference for them
1244      if (hasClient && !hasServer) solveAllRefOfFieldsWithReadAccess();
1245
1246      isPostProcessed = true;
1247   }
1248
1249   /*!
1250    * Compute the required buffer size to send the attributes (mostly those grid related).
1251    *
1252    * \param maxEventSize [in/out] the size of the bigger event for each connected server
1253    */
1254   std::map<int, StdSize> CContext::getAttributesBufferSize(std::map<int, StdSize>& maxEventSize, CContextClient* contextClient)
1255   {
1256     std::map<int, StdSize> attributesSize;
1257
1258     if (hasClient)
1259     {
1260       size_t numEnabledFiles = this->enabledFiles.size();
1261       for (size_t i = 0; i < numEnabledFiles; ++i)
1262       {
1263         CFile* file = this->enabledFiles[i];
1264//         if (file->getContextClient() == contextClient)
1265         {
1266           std::vector<CField*> enabledFields = file->getEnabledFields();
1267           size_t numEnabledFields = enabledFields.size();
1268           for (size_t j = 0; j < numEnabledFields; ++j)
1269           {
1270             const std::map<int, StdSize> mapSize = enabledFields[j]->getGridAttributesBufferSize();
1271             std::map<int, StdSize>::const_iterator it = mapSize.begin(), itE = mapSize.end();
1272             for (; it != itE; ++it)
1273             {
1274               // If attributesSize[it->first] does not exist, it will be zero-initialized
1275               // so we can use it safely without checking for its existance
1276               if (attributesSize[it->first] < it->second)
1277                 attributesSize[it->first] = it->second;
1278
1279               if (maxEventSize[it->first] < it->second)
1280                 maxEventSize[it->first] = it->second;
1281             }
1282           }
1283         }
1284       }
1285     }
1286
1287     return attributesSize;
1288   }
1289
1290   /*!
1291    * Compute the required buffer size to send the fields data.
1292    *
1293    * \param maxEventSize [in/out] the size of the bigger event for each connected server
1294    */
1295   std::map<int, StdSize> CContext::getDataBufferSize(std::map<int, StdSize>& maxEventSize, CContextClient* contextClient)
1296   {
1297     CFile::mode_attr::t_enum mode = hasClient ? CFile::mode_attr::write : CFile::mode_attr::read;
1298
1299     std::map<int, StdSize> dataSize;
1300
1301     // Find all reference domain and axis of all active fields
1302     size_t numEnabledFiles = this->enabledFiles.size();
1303     for (size_t i = 0; i < numEnabledFiles; ++i)
1304     {
1305       CFile* file = this->enabledFiles[i];
1306       if (file->getContextClient() == contextClient)
1307       {
1308         CFile::mode_attr::t_enum fileMode = file->mode.isEmpty() ? CFile::mode_attr::write : file->mode.getValue();
1309
1310         if (fileMode == mode)
1311         {
1312           std::vector<CField*> enabledFields = file->getEnabledFields();
1313           size_t numEnabledFields = enabledFields.size();
1314           for (size_t j = 0; j < numEnabledFields; ++j)
1315           {
1316             const std::vector<std::map<int, StdSize> > mapSize = enabledFields[j]->getGridDataBufferSize();
1317             for (size_t c = 0; c < mapSize.size(); ++c)
1318             {
1319               std::map<int, StdSize>::const_iterator it = mapSize[c].begin(), itE = mapSize[c].end();
1320               for (; it != itE; ++it)
1321               {
1322                 // If dataSize[it->first] does not exist, it will be zero-initialized
1323                 // so we can use it safely without checking for its existance
1324                 if (CXios::isOptPerformance)
1325                   dataSize[it->first] += it->second;
1326                 else if (dataSize[it->first] < it->second)
1327                   dataSize[it->first] = it->second;
1328
1329                 if (maxEventSize[it->first] < it->second)
1330                   maxEventSize[it->first] = it->second;
1331               }
1332             }
1333           }
1334         }
1335       }
1336     }
1337
1338     return dataSize;
1339   }
1340
1341   //! Client side: Send infomation of active files (files are enabled to write out)
1342   void CContext::sendEnabledFiles()
1343   {
1344     int size = this->enabledFiles.size();
1345
1346     // In a context, each type has a root definition, e.g: axis, domain, field.
1347     // Every object must be a child of one of these root definition. In this case
1348     // all new file objects created on server must be children of the root "file_definition"
1349     StdString fileDefRoot("file_definition");
1350     CFileGroup* cfgrpPtr = CFileGroup::get(fileDefRoot);
1351
1352     for (int i = 0; i < size; ++i)
1353     {
1354       cfgrpPtr->sendCreateChild(this->enabledFiles[i]->getId(),enabledFiles[i]->getContextClient());
1355       this->enabledFiles[i]->sendAllAttributesToServer(enabledFiles[i]->getContextClient());
1356       this->enabledFiles[i]->sendAddAllVariables(enabledFiles[i]->getContextClient());
1357     }
1358   }
1359
1360   //! Client side: Send information of active fields (ones are written onto files)
1361   void CContext::sendEnabledFields()
1362   {
1363     int size = this->enabledFiles.size();
1364     for (int i = 0; i < size; ++i)
1365     {
1366       this->enabledFiles[i]->sendEnabledFields(enabledFiles[i]->getContextClient());
1367     }
1368   }
1369
1370   //! Client side: Check if the defined axis, domains and grids are eligible for compressed indexed output
1371   void CContext::checkAxisDomainsGridsEligibilityForCompressedOutput()
1372   {
1373     if (!hasClient) return;
1374
1375     const vector<CAxis*> allAxis = CAxis::getAll();
1376     for (vector<CAxis*>::const_iterator it = allAxis.begin(); it != allAxis.end(); it++)
1377       (*it)->checkEligibilityForCompressedOutput();
1378
1379     const vector<CDomain*> allDomains = CDomain::getAll();
1380     for (vector<CDomain*>::const_iterator it = allDomains.begin(); it != allDomains.end(); it++)
1381       (*it)->checkEligibilityForCompressedOutput();
1382
1383     const vector<CGrid*> allGrids = CGrid::getAll();
1384     for (vector<CGrid*>::const_iterator it = allGrids.begin(); it != allGrids.end(); it++)
1385       (*it)->checkEligibilityForCompressedOutput();
1386   }
1387
1388   //! Client side: Prepare the timeseries by adding the necessary files
1389   void CContext::prepareTimeseries()
1390   {
1391     if (!hasClient) return;
1392
1393     const std::vector<CFile*> allFiles = CFile::getAll();
1394     for (size_t i = 0; i < allFiles.size(); i++)
1395     {
1396       CFile* file = allFiles[i];
1397
1398       std::vector<CVariable*> fileVars, fieldVars, vars = file->getAllVariables();
1399       for (size_t k = 0; k < vars.size(); k++)
1400       {
1401         CVariable* var = vars[k];
1402
1403         if (var->ts_target.isEmpty()
1404              || var->ts_target == CVariable::ts_target_attr::file || var->ts_target == CVariable::ts_target_attr::both)
1405           fileVars.push_back(var);
1406
1407         if (!var->ts_target.isEmpty()
1408              && (var->ts_target == CVariable::ts_target_attr::field || var->ts_target == CVariable::ts_target_attr::both))
1409           fieldVars.push_back(var);
1410       }
1411
1412       if (!file->timeseries.isEmpty() && file->timeseries != CFile::timeseries_attr::none)
1413       {
1414         StdString fileNameStr("%file_name%") ;
1415         StdString tsPrefix = !file->ts_prefix.isEmpty() ? file->ts_prefix : fileNameStr ;
1416         
1417         StdString fileName=file->getFileOutputName();
1418         size_t pos=tsPrefix.find(fileNameStr) ;
1419         while (pos!=std::string::npos)
1420         {
1421           tsPrefix=tsPrefix.replace(pos,fileNameStr.size(),fileName) ;
1422           pos=tsPrefix.find(fileNameStr) ;
1423         }
1424       
1425         const std::vector<CField*> allFields = file->getAllFields();
1426         for (size_t j = 0; j < allFields.size(); j++)
1427         {
1428           CField* field = allFields[j];
1429
1430           if (!field->ts_enabled.isEmpty() && field->ts_enabled)
1431           {
1432             CFile* tsFile = CFile::create();
1433             tsFile->duplicateAttributes(file);
1434
1435             // Add variables originating from file and targeted to timeserie file
1436             for (size_t k = 0; k < fileVars.size(); k++)
1437               tsFile->getVirtualVariableGroup()->addChild(fileVars[k]);
1438
1439           
1440             tsFile->name = tsPrefix + "_";
1441             if (!field->name.isEmpty())
1442               tsFile->name.get() += field->name;
1443             else if (field->hasDirectFieldReference()) // We cannot use getBaseFieldReference() just yet
1444               tsFile->name.get() += field->field_ref;
1445             else
1446               tsFile->name.get() += field->getId();
1447
1448             if (!field->ts_split_freq.isEmpty())
1449               tsFile->split_freq = field->ts_split_freq;
1450
1451             CField* tsField = tsFile->addField();
1452             tsField->field_ref = field->getId();
1453
1454             // Add variables originating from file and targeted to timeserie field
1455             for (size_t k = 0; k < fieldVars.size(); k++)
1456               tsField->getVirtualVariableGroup()->addChild(fieldVars[k]);
1457
1458             vars = field->getAllVariables();
1459             for (size_t k = 0; k < vars.size(); k++)
1460             {
1461               CVariable* var = vars[k];
1462
1463               // Add variables originating from field and targeted to timeserie field
1464               if (var->ts_target.isEmpty()
1465                    || var->ts_target == CVariable::ts_target_attr::field || var->ts_target == CVariable::ts_target_attr::both)
1466                 tsField->getVirtualVariableGroup()->addChild(var);
1467
1468               // Add variables originating from field and targeted to timeserie file
1469               if (!var->ts_target.isEmpty()
1470                    && (var->ts_target == CVariable::ts_target_attr::file || var->ts_target == CVariable::ts_target_attr::both))
1471                 tsFile->getVirtualVariableGroup()->addChild(var);
1472             }
1473
1474             tsFile->solveFieldRefInheritance(true);
1475
1476             if (file->timeseries == CFile::timeseries_attr::exclusive)
1477               field->enabled = false;
1478           }
1479         }
1480
1481         // Finally disable the original file is need be
1482         if (file->timeseries == CFile::timeseries_attr::only)
1483          file->enabled = false;
1484       }
1485     }
1486   }
1487
1488   //! Client side: Send information of reference grid of active fields
1489   void CContext::sendRefGrid()
1490   {
1491     std::set<StdString> gridIds;
1492     int sizeFile = this->enabledFiles.size();
1493     CFile* filePtr(NULL);
1494
1495     // Firstly, find all reference grids of all active fields
1496     for (int i = 0; i < sizeFile; ++i)
1497     {
1498       filePtr = this->enabledFiles[i];
1499       std::vector<CField*> enabledFields = filePtr->getEnabledFields();
1500       int sizeField = enabledFields.size();
1501       for (int numField = 0; numField < sizeField; ++numField)
1502       {
1503         if (0 != enabledFields[numField]->getRelGrid())
1504           gridIds.insert(CGrid::get(enabledFields[numField]->getRelGrid())->getId());
1505       }
1506     }
1507
1508     // Create all reference grids on server side
1509     StdString gridDefRoot("grid_definition");
1510     CGridGroup* gridPtr = CGridGroup::get(gridDefRoot);
1511     std::set<StdString>::const_iterator it, itE = gridIds.end();
1512     for (it = gridIds.begin(); it != itE; ++it)
1513     {
1514       gridPtr->sendCreateChild(*it);
1515       CGrid::get(*it)->sendAllAttributesToServer();
1516       CGrid::get(*it)->sendAllDomains();
1517       CGrid::get(*it)->sendAllAxis();
1518       CGrid::get(*it)->sendAllScalars();
1519     }
1520   }
1521
1522
1523   //! Client side: Send information of reference domain and axis of active fields
1524   void CContext::sendRefDomainsAxis()
1525   {
1526     std::set<StdString> domainIds, axisIds, scalarIds;
1527
1528     // Find all reference domain and axis of all active fields
1529     int numEnabledFiles = this->enabledFiles.size();
1530     for (int i = 0; i < numEnabledFiles; ++i)
1531     {
1532       std::vector<CField*> enabledFields = this->enabledFiles[i]->getEnabledFields();
1533       int numEnabledFields = enabledFields.size();
1534       for (int j = 0; j < numEnabledFields; ++j)
1535       {
1536         const std::vector<StdString>& prDomAxisScalarId = enabledFields[j]->getRefDomainAxisIds();
1537         if ("" != prDomAxisScalarId[0]) domainIds.insert(prDomAxisScalarId[0]);
1538         if ("" != prDomAxisScalarId[1]) axisIds.insert(prDomAxisScalarId[1]);
1539         if ("" != prDomAxisScalarId[2]) scalarIds.insert(prDomAxisScalarId[2]);
1540       }
1541     }
1542
1543     // Create all reference axis on server side
1544     std::set<StdString>::iterator itDom, itAxis, itScalar;
1545     std::set<StdString>::const_iterator itE;
1546
1547     StdString scalarDefRoot("scalar_definition");
1548     CScalarGroup* scalarPtr = CScalarGroup::get(scalarDefRoot);
1549     itE = scalarIds.end();
1550     for (itScalar = scalarIds.begin(); itScalar != itE; ++itScalar)
1551     {
1552       if (!itScalar->empty())
1553       {
1554         scalarPtr->sendCreateChild(*itScalar);
1555         CScalar::get(*itScalar)->sendAllAttributesToServer();
1556       }
1557     }
1558
1559     StdString axiDefRoot("axis_definition");
1560     CAxisGroup* axisPtr = CAxisGroup::get(axiDefRoot);
1561     itE = axisIds.end();
1562     for (itAxis = axisIds.begin(); itAxis != itE; ++itAxis)
1563     {
1564       if (!itAxis->empty())
1565       {
1566         axisPtr->sendCreateChild(*itAxis);
1567         CAxis::get(*itAxis)->sendAllAttributesToServer();
1568       }
1569     }
1570
1571     // Create all reference domains on server side
1572     StdString domDefRoot("domain_definition");
1573     CDomainGroup* domPtr = CDomainGroup::get(domDefRoot);
1574     itE = domainIds.end();
1575     for (itDom = domainIds.begin(); itDom != itE; ++itDom)
1576     {
1577       if (!itDom->empty()) {
1578          domPtr->sendCreateChild(*itDom);
1579          CDomain::get(*itDom)->sendAllAttributesToServer();
1580       }
1581     }
1582   }
1583
1584   //! Update calendar in each time step
1585   void CContext::updateCalendar(int step)
1586   {
1587      info(50) << "updateCalendar : before : " << calendar->getCurrentDate() << endl;
1588      calendar->update(step);
1589      info(50) << "updateCalendar : after : " << calendar->getCurrentDate() << endl;
1590#ifdef XIOS_MEMTRACK_LIGHT
1591      info(50) << " Current memory used by XIOS : "<<  MemTrack::getCurrentMemorySize()*1.0/(1024*1024)<<" Mbyte, at timestep "<<step<<" of context "<<this->getId()<<endl ;
1592#endif
1593      if (hasClient)
1594      {
1595        checkPrefetchingOfEnabledReadModeFiles();
1596        garbageCollector.invalidate(calendar->getCurrentDate());
1597      }
1598   }
1599
1600   //! Server side: Create header of netcdf file
1601   void CContext::createFileHeader(void )
1602   {
1603      vector<CFile*>::const_iterator it;
1604
1605      for (it=enabledFiles.begin(); it != enabledFiles.end(); it++)
1606      {
1607         (*it)->initFile();
1608      }
1609   }
1610
1611   //! Get current context
1612   CContext* CContext::getCurrent(void)
1613   {
1614     return CObjectFactory::GetObject<CContext>(CObjectFactory::GetCurrentContextId()).get();
1615   }
1616
1617   /*!
1618   \brief Set context with an id be the current context
1619   \param [in] id identity of context to be set to current
1620   */
1621   void CContext::setCurrent(const string& id)
1622   {
1623     CObjectFactory::SetCurrentContextId(id);
1624     CGroupFactory::SetCurrentContextId(id);
1625   }
1626
1627  /*!
1628  \brief Create a context with specific id
1629  \param [in] id identity of new context
1630  \return pointer to the new context or already-existed one with identity id
1631  */
1632  CContext* CContext::create(const StdString& id)
1633  {
1634    CContext::setCurrent(id);
1635
1636    bool hasctxt = CContext::has(id);
1637    CContext* context = CObjectFactory::CreateObject<CContext>(id).get();
1638    getRoot();
1639    if (!hasctxt) CGroupFactory::AddChild(root, context->getShared());
1640
1641#define DECLARE_NODE(Name_, name_) \
1642    C##Name_##Definition::create(C##Name_##Definition::GetDefName());
1643#define DECLARE_NODE_PAR(Name_, name_)
1644#include "node_type.conf"
1645
1646    return (context);
1647  }
1648
1649
1650     //! Server side: Receive a message to do some post processing
1651  void CContext::recvRegistry(CEventServer& event)
1652  {
1653    CBufferIn* buffer=event.subEvents.begin()->buffer;
1654    string id;
1655    *buffer>>id;
1656    get(id)->recvRegistry(*buffer);
1657  }
1658
1659  void CContext::recvRegistry(CBufferIn& buffer)
1660  {
1661    if (server->intraCommRank==0)
1662    {
1663      CRegistry registry(server->intraComm) ;
1664      registry.fromBuffer(buffer) ;
1665      registryOut->mergeRegistry(registry) ;
1666    }
1667  }
1668
1669  void CContext::sendRegistry(void)
1670  {
1671    registryOut->hierarchicalGatherRegistry() ;
1672
1673    // Use correct context client to send message
1674    int nbSrvPools = (this->hasServer) ? (this->hasClient ? this->clientPrimServer.size() : 0) : 1;
1675    for (int i = 0; i < nbSrvPools; ++i)
1676    {
1677      CContextClient* contextClientTmp = (hasServer) ? clientPrimServer[i] : client;
1678      CEventClient event(CContext::GetType(), CContext::EVENT_ID_SEND_REGISTRY);
1679        if (contextClientTmp->isServerLeader())
1680        {
1681           CMessage msg ;
1682           if (hasServer)
1683             msg<<this->getIdServer(i);
1684           else
1685             msg<<this->getIdServer();
1686           if (contextClientTmp->clientRank==0) msg<<*registryOut ;
1687           const std::list<int>& ranks = contextClientTmp->getRanksServerLeader();
1688           for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
1689             event.push(*itRank,1,msg);
1690           contextClientTmp->sendEvent(event);
1691         }
1692         else contextClientTmp->sendEvent(event);
1693    }
1694  }
1695
1696  /*!
1697  * \fn bool CContext::isFinalized(void)
1698  * Context is finalized if it received context post finalize event.
1699  */
1700  bool CContext::isFinalized(void)
1701  {
1702    return finalized;
1703  }
1704
1705} // namespace xios
Note: See TracBrowser for help on using the repository browser.