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

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

Fixing a bug in sizes of client buffers. The sizes of client buffers are estimated for each type of client (a model or any type of servers).

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