source: XIOS/dev/dev_ym/XIOS_SERVICES/src/node/context.cpp @ 1766

Last change on this file since 1766 was 1766, checked in by ymipsl, 2 years ago

more cleaning...
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: 76.8 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 <fstream>
20#include "server.hpp"
21#include "distribute_file_server2.hpp"
22#include "services_manager.hpp"
23#include "contexts_manager.hpp"
24#include "cxios.hpp"
25#include "client.hpp"
26
27namespace xios {
28
29  std::shared_ptr<CContextGroup> CContext::root;
30
31   /// ////////////////////// Définitions ////////////////////// ///
32
33   CContext::CContext(void)
34      : CObjectTemplate<CContext>(), CContextAttributes()
35      , calendar(), hasClient(false), hasServer(false)
36      , isPostProcessed(false), finalized(false)
37      , idServer_(), client(nullptr), server(nullptr)
38      , allProcessed(false), countChildContextFinalized_(0), isProcessingEvent_(false)
39
40   { /* Ne rien faire de plus */ }
41
42   CContext::CContext(const StdString & id)
43      : CObjectTemplate<CContext>(id), CContextAttributes()
44      , calendar(), hasClient(false), hasServer(false)
45      , isPostProcessed(false), finalized(false)
46      , idServer_(), client(nullptr), server(nullptr)
47      , allProcessed(false), countChildContextFinalized_(0), isProcessingEvent_(false)
48   { /* Ne rien faire de plus */ }
49
50   CContext::~CContext(void)
51   {
52     delete client;
53     delete server;
54     for (std::vector<CContextClient*>::iterator it = clientPrimServer.begin(); it != clientPrimServer.end(); it++)  delete *it;
55     for (std::vector<CContextServer*>::iterator it = serverPrimServer.begin(); it != serverPrimServer.end(); it++)  delete *it;
56
57   }
58
59   //----------------------------------------------------------------
60   //! Get name of context
61   StdString CContext::GetName(void)   { return (StdString("context")); }
62   StdString CContext::GetDefName(void){ return (CContext::GetName()); }
63   ENodeType CContext::GetType(void)   { return (eContext); }
64
65   //----------------------------------------------------------------
66
67   /*!
68   \brief Get context group (context root)
69   \return Context root
70   */
71   CContextGroup* CContext::getRoot(void)
72   TRY
73   {
74      if (root.get()==NULL) root=std::shared_ptr<CContextGroup>(new CContextGroup(xml::CXMLNode::GetRootName()));
75      return root.get();
76   }
77   CATCH
78
79   //----------------------------------------------------------------
80
81   /*!
82   \brief Get calendar of a context
83   \return Calendar
84   */
85   std::shared_ptr<CCalendar> CContext::getCalendar(void) const
86   TRY
87   {
88      return (this->calendar);
89   }
90   CATCH
91
92   //----------------------------------------------------------------
93
94   /*!
95   \brief Set a context with a calendar
96   \param[in] newCalendar new calendar
97   */
98   void CContext::setCalendar(std::shared_ptr<CCalendar> newCalendar)
99   TRY
100   {
101      this->calendar = newCalendar;
102   }
103   CATCH_DUMP_ATTR
104
105   //----------------------------------------------------------------
106   /*!
107   \brief Parse xml file and write information into context object
108   \param [in] node xmld node corresponding in xml file
109   */
110   void CContext::parse(xml::CXMLNode & node)
111   TRY
112   {
113      CContext::SuperClass::parse(node);
114
115      // PARSING POUR GESTION DES ENFANTS
116      xml::THashAttributes attributes = node.getAttributes();
117
118      if (attributes.end() != attributes.find("src"))
119      {
120         StdIFStream ifs ( attributes["src"].c_str() , StdIFStream::in );
121         if ( (ifs.rdstate() & std::ifstream::failbit ) != 0 )
122            ERROR("void CContext::parse(xml::CXMLNode & node)",
123                  <<endl<< "Can not open <"<<attributes["src"].c_str()<<"> file" );
124         if (!ifs.good())
125            ERROR("CContext::parse(xml::CXMLNode & node)",
126                  << "[ filename = " << attributes["src"] << " ] Bad xml stream !");
127         xml::CXMLParser::ParseInclude(ifs, attributes["src"], *this);
128      }
129
130      if (node.getElementName().compare(CContext::GetName()))
131         DEBUG("Le noeud is wrong defined but will be considered as a context !");
132
133      if (!(node.goToChildElement()))
134      {
135         DEBUG("Le context ne contient pas d'enfant !");
136      }
137      else
138      {
139         do { // Parcours des contextes pour traitement.
140
141            StdString name = node.getElementName();
142            attributes.clear();
143            attributes = node.getAttributes();
144
145            if (attributes.end() != attributes.find("id"))
146            {
147              DEBUG(<< "Definition node has an id,"
148                    << "it will not be taking account !");
149            }
150
151#define DECLARE_NODE(Name_, name_)    \
152   if (name.compare(C##Name_##Definition::GetDefName()) == 0) \
153   { C##Name_##Definition::create(C##Name_##Definition::GetDefName()) -> parse(node); continue; }
154#define DECLARE_NODE_PAR(Name_, name_)
155#include "node_type.conf"
156
157            DEBUG(<< "The element \'"     << name
158                  << "\' in the context \'" << CContext::getCurrent()->getId()
159                  << "\' is not a definition !");
160
161         } while (node.goToNextElement());
162
163         node.goToParentElement(); // Retour au parent
164      }
165   }
166   CATCH_DUMP_ATTR
167
168   //----------------------------------------------------------------
169   //! Show tree structure of context
170   void CContext::ShowTree(StdOStream & out)
171   TRY
172   {
173      StdString currentContextId = CContext::getCurrent() -> getId();
174      std::vector<CContext*> def_vector =
175         CContext::getRoot()->getChildList();
176      std::vector<CContext*>::iterator
177         it = def_vector.begin(), end = def_vector.end();
178
179      out << "<? xml version=\"1.0\" ?>" << std::endl;
180      out << "<"  << xml::CXMLNode::GetRootName() << " >" << std::endl;
181
182      for (; it != end; it++)
183      {
184         CContext* context = *it;
185         CContext::setCurrent(context->getId());
186         out << *context << std::endl;
187      }
188
189      out << "</" << xml::CXMLNode::GetRootName() << " >" << std::endl;
190      CContext::setCurrent(currentContextId);
191   }
192   CATCH
193
194   //----------------------------------------------------------------
195
196   //! Convert context object into string (to print)
197   StdString CContext::toString(void) const
198   TRY
199   {
200      StdOStringStream oss;
201      oss << "<" << CContext::GetName()
202          << " id=\"" << this->getId() << "\" "
203          << SuperClassAttribute::toString() << ">" << std::endl;
204      if (!this->hasChild())
205      {
206         //oss << "<!-- No definition -->" << std::endl; // fait planter l'incrémentation
207      }
208      else
209      {
210
211#define DECLARE_NODE(Name_, name_)    \
212   if (C##Name_##Definition::has(C##Name_##Definition::GetDefName())) \
213   oss << * C##Name_##Definition::get(C##Name_##Definition::GetDefName()) << std::endl;
214#define DECLARE_NODE_PAR(Name_, name_)
215#include "node_type.conf"
216
217      }
218      oss << "</" << CContext::GetName() << " >";
219      return (oss.str());
220   }
221   CATCH
222
223   //----------------------------------------------------------------
224
225   /*!
226   \brief Find all inheritace among objects in a context.
227   \param [in] apply (true) write attributes of parent into ones of child if they are empty
228                     (false) write attributes of parent into a new container of child
229   \param [in] parent unused
230   */
231   void CContext::solveDescInheritance(bool apply, const CAttributeMap * const UNUSED(parent))
232   TRY
233   {
234#define DECLARE_NODE(Name_, name_)    \
235   if (C##Name_##Definition::has(C##Name_##Definition::GetDefName())) \
236     C##Name_##Definition::get(C##Name_##Definition::GetDefName())->solveDescInheritance(apply);
237#define DECLARE_NODE_PAR(Name_, name_)
238#include "node_type.conf"
239   }
240   CATCH_DUMP_ATTR
241
242   //----------------------------------------------------------------
243
244   //! Verify if all root definition in the context have child.
245   bool CContext::hasChild(void) const
246   TRY
247   {
248      return (
249#define DECLARE_NODE(Name_, name_)    \
250   C##Name_##Definition::has(C##Name_##Definition::GetDefName())   ||
251#define DECLARE_NODE_PAR(Name_, name_)
252#include "node_type.conf"
253      false);
254}
255   CATCH
256
257   //----------------------------------------------------------------
258
259   void CContext::CleanTree(void)
260   TRY
261   {
262#define DECLARE_NODE(Name_, name_) C##Name_##Definition::ClearAllAttributes();
263#define DECLARE_NODE_PAR(Name_, name_)
264#include "node_type.conf"
265   }
266   CATCH
267
268   ///---------------------------------------------------------------
269
270
271    /*!
272    Sets client buffers.
273    \param [in] contextClient
274    \param [in] bufferForWriting True if buffers are used for sending data for writing
275    This flag is only true for client and server-1 for communication with server-2
276  */
277   void CContext::setClientServerBuffer(CContextClient* contextClient, bool bufferForWriting)
278   TRY
279   {
280      // Estimated minimum event size for small events (10 is an arbitrary constant just for safety)
281     const size_t minEventSize = CEventClient::headerSize + getIdServer().size() + 10 * sizeof(int);
282
283      // Ensure there is at least some room for 20 of such events in the buffers
284      size_t minBufferSize = std::max(CXios::minBufferSize, 20 * minEventSize);
285
286#define DECLARE_NODE(Name_, name_)    \
287     if (minBufferSize < sizeof(C##Name_##Definition)) minBufferSize = sizeof(C##Name_##Definition);
288#define DECLARE_NODE_PAR(Name_, name_)
289#include "node_type.conf"
290#undef DECLARE_NODE
291#undef DECLARE_NODE_PAR
292
293     // Compute the buffer sizes needed to send the attributes and data corresponding to fields
294     std::map<int, StdSize> maxEventSize;
295     std::map<int, StdSize> bufferSize = getAttributesBufferSize(maxEventSize, contextClient, bufferForWriting);
296     std::map<int, StdSize> dataBufferSize = getDataBufferSize(maxEventSize, contextClient, bufferForWriting);
297
298     std::map<int, StdSize>::iterator it, ite = dataBufferSize.end();
299     for (it = dataBufferSize.begin(); it != ite; ++it)
300       if (it->second > bufferSize[it->first]) bufferSize[it->first] = it->second;
301
302     // Apply the buffer size factor, check that we are above the minimum buffer size and below the maximum size
303     ite = bufferSize.end();
304     for (it = bufferSize.begin(); it != ite; ++it)
305     {
306       it->second *= CXios::bufferSizeFactor;
307       if (it->second < minBufferSize) it->second = minBufferSize;
308       if (it->second > CXios::maxBufferSize) it->second = CXios::maxBufferSize;
309     }
310
311     // Leaders will have to send some control events so ensure there is some room for those in the buffers
312     if (contextClient->isServerLeader())
313     {
314       const std::list<int>& ranks = contextClient->getRanksServerLeader();
315       for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
316       {
317         if (!bufferSize.count(*itRank))
318         {
319           bufferSize[*itRank] = minBufferSize;
320           maxEventSize[*itRank] = minEventSize;
321         }
322       }
323     }
324     contextClient->setBufferSize(bufferSize, maxEventSize);
325   }
326   CATCH_DUMP_ATTR
327
328   //! Verify whether a context is initialized
329   bool CContext::isInitialized(void)
330   TRY
331   {
332     return hasClient;
333   }
334   CATCH_DUMP_ATTR
335
336
337   void CContext::init(CServerContext* parentServerContext, MPI_Comm intraComm, int serviceType)
338   TRY
339   {
340     parentServerContext_ = parentServerContext ;
341     if (serviceType==CServicesManager::CLIENT) 
342       initClient(intraComm, serviceType) ;
343     else
344       initServer(intraComm, serviceType) ;
345    }
346    CATCH_DUMP_ATTR
347
348
349
350//! Initialize client side
351   void CContext::initClient(MPI_Comm intraComm, int serviceType)
352   TRY
353   {
354      intraComm_=intraComm ;
355      serviceType_ = CServicesManager::CLIENT ;
356      if (serviceType_==CServicesManager::CLIENT)
357      {
358        hasClient=true ;
359        hasServer=false ;
360      }
361      contextId_ = getId() ;
362     
363      attached_mode=true ;
364      if (!CXios::isUsingServer()) attached_mode=false ;
365
366
367      string contextRegistryId=getId() ;
368      registryIn=new CRegistry(intraComm);
369      registryIn->setPath(contextRegistryId) ;
370     
371      int commRank ;
372      MPI_Comm_rank(intraComm_,&commRank) ;
373      if (commRank==0) registryIn->fromFile("xios_registry.bin") ;
374      registryIn->bcastRegistry() ;
375      registryOut=new CRegistry(intraComm_) ;
376      registryOut->setPath(contextRegistryId) ;
377     
378   }
379   CATCH_DUMP_ATTR
380
381   
382   void CContext::initServer(MPI_Comm intraComm, int serviceType)
383   TRY
384   {
385     hasServer=true;
386     intraComm_=intraComm ;
387     serviceType_=serviceType ;
388
389     if (serviceType_==CServicesManager::GATHERER)
390     {
391       hasClient=true ;
392       hasServer=true ;
393     }
394     else if (serviceType_==CServicesManager::IO_SERVER || serviceType_==CServicesManager::OUT_SERVER)
395     {
396       hasClient=false ;
397       hasServer=true ;
398     }
399
400     CXios::getContextsManager()->getContextId(getId(), contextId_, intraComm) ;
401     
402     registryIn=new CRegistry(intraComm);
403     registryIn->setPath(contextId_) ;
404     
405     int commRank ;
406     MPI_Comm_rank(intraComm_,&commRank) ;
407     if (commRank==0) registryIn->fromFile("xios_registry.bin") ;
408   
409     registryIn->bcastRegistry() ;
410     registryOut=new CRegistry(intraComm) ;
411     registryOut->setPath(contextId_) ;
412
413   }
414   CATCH_DUMP_ATTR
415
416
417  void CContext::createClientInterComm(MPI_Comm interCommClient, MPI_Comm interCommServer) // for servers
418  TRY
419  {
420    MPI_Comm intraCommClient ;
421    MPI_Comm_dup(intraComm_, &intraCommClient);
422    comms.push_back(intraCommClient);
423    // attached_mode=parentServerContext_->isAttachedMode() ; //ym probably inherited from source context
424    server = new CContextServer(this,intraComm_, interCommServer); // check if we need to dupl. intraComm_ ?
425    client = new CContextClient(this,intraCommClient,interCommClient);
426
427  }
428  CATCH_DUMP_ATTR
429
430  void CContext::createServerInterComm(void) 
431  TRY
432  {
433   
434    MPI_Comm interCommClient, interCommServer ;
435
436    if (serviceType_ == CServicesManager::CLIENT)
437    {
438
439      int commRank ;
440      MPI_Comm_rank(intraComm_,&commRank) ;
441      if (commRank==0)
442      {
443        if (attached_mode) CXios::getContextsManager()->createServerContext(CClient::getPoolRessource()->getId(), CXios::defaultServerId, 0, getContextId()) ;
444        else if (CXios::usingServer2) CXios::getContextsManager()->createServerContext(CXios::defaultPoolId, CXios::defaultGathererId, 0, getContextId()) ;
445        else  CXios::getContextsManager()->createServerContext(CXios::defaultPoolId, CXios::defaultServerId, 0, getContextId()) ;
446      }
447
448      MPI_Comm interComm ;
449     
450      if (attached_mode)
451      {
452        parentServerContext_->createIntercomm(CClient::getPoolRessource()->getId(), CXios::defaultServerId, 0, getContextId(), intraComm_, 
453                                              interCommClient, interCommServer) ;
454        int type ; 
455        if (commRank==0) CXios::getServicesManager()->getServiceType(CClient::getPoolRessource()->getId(), CXios::defaultServerId, 0, type) ;
456        MPI_Bcast(&type,1,MPI_INT,0,intraComm_) ;
457        setIdServer(CXios::getContextsManager()->getServerContextName(CClient::getPoolRessource()->getId(), CXios::defaultServerId, 0, type, getContextId())) ;
458        setCurrent(getId()) ; // getCurrent/setCurrent may be supress, it can cause a lot of trouble
459      }
460      else if (CXios::usingServer2)
461      { 
462//      CXios::getContextsManager()->createServerContextIntercomm(CXios::defaultPoolId, CXios::defaultGathererId, 0, getContextId(), intraComm_, interComm) ;
463        parentServerContext_->createIntercomm(CXios::defaultPoolId, CXios::defaultGathererId, 0, getContextId(), intraComm_,
464                                              interCommClient, interCommServer) ;
465        int type ; 
466        if (commRank==0) CXios::getServicesManager()->getServiceType(CXios::defaultPoolId, CXios::defaultGathererId, 0, type) ;
467        MPI_Bcast(&type,1,MPI_INT,0,intraComm_) ;
468        setIdServer(CXios::getContextsManager()->getServerContextName(CXios::defaultPoolId, CXios::defaultGathererId, 0, type, getContextId())) ;
469      }
470      else
471      {
472        //CXios::getContextsManager()->createServerContextIntercomm(CXios::defaultPoolId, CXios::defaultServerId, 0, getContextId(), intraComm_, interComm) ;
473        parentServerContext_->createIntercomm(CXios::defaultPoolId, CXios::defaultServerId, 0, getContextId(), intraComm_,
474                                              interCommClient, interCommServer) ;
475        int type ; 
476        if (commRank==0) CXios::getServicesManager()->getServiceType(CXios::defaultPoolId, CXios::defaultServerId, 0, type) ;
477        MPI_Bcast(&type,1,MPI_INT,0,intraComm_) ;
478        setIdServer(CXios::getContextsManager()->getServerContextName(CXios::defaultPoolId, CXios::defaultServerId, 0, type, getContextId())) ;
479      }
480
481        // intraComm client is not duplicated. In all the code we use client->intraComm for MPI
482        // in future better to replace it by intracommuncator associated to the context
483   
484      MPI_Comm intraCommClient, intraCommServer ;
485      intraCommClient=intraComm_ ;
486      MPI_Comm_dup(intraComm_, &intraCommServer) ;
487      client = new CContextClient(this, intraCommClient, interCommClient);
488      server = new CContextServer(this, intraCommServer, interCommServer);
489   
490    }
491   
492    if (serviceType_ == CServicesManager::GATHERER)
493    {
494      int commRank ;
495      MPI_Comm_rank(intraComm_,&commRank) ;
496     
497      int nbPartitions ;
498      if (commRank==0) 
499      { 
500        CXios::getServicesManager()->getServiceNbPartitions(CXios::defaultPoolId, CXios::defaultServerId, 0, nbPartitions) ;
501        for(int i=0 ; i<nbPartitions; i++)
502          CXios::getContextsManager()->createServerContext(CXios::defaultPoolId, CXios::defaultServerId, i, getContextId()) ;
503      }     
504      MPI_Bcast(&nbPartitions, 1, MPI_INT, 0, intraComm_) ;
505     
506      MPI_Comm interComm ;
507      for(int i=0 ; i<nbPartitions; i++)
508      {
509        parentServerContext_->createIntercomm(CXios::defaultPoolId, CXios::defaultServerId, i, getContextId(), intraComm_, interCommClient, interCommServer) ;
510        int type ; 
511        if (commRank==0) CXios::getServicesManager()->getServiceType(CXios::defaultPoolId, CXios::defaultServerId, 0, type) ;
512        MPI_Bcast(&type,1,MPI_INT,0,intraComm_) ;
513        primServerId_.push_back(CXios::getContextsManager()->getServerContextName(CXios::defaultPoolId, CXios::defaultServerId, i, type, getContextId())) ;
514
515        // intraComm client is not duplicated. In all the code we use client->intraComm for MPI
516        // in future better to replace it by intracommuncator associated to the context
517     
518        MPI_Comm intraCommClient, intraCommServer ;
519
520        intraCommClient=intraComm_ ;
521        MPI_Comm_dup(intraComm_, &intraCommServer) ;
522
523
524        clientPrimServer.push_back(new CContextClient(this, intraCommClient, interCommClient));
525        serverPrimServer.push_back(new CContextServer(this, intraCommServer, interCommServer)); 
526     
527      }
528    }
529  }
530  CATCH_DUMP_ATTR
531
532   
533
534  bool CContext::eventLoop(bool enableEventsProcessing)
535  {
536    bool finished=true; 
537
538    if (client!=nullptr && !finalized) client->checkBuffers();
539   
540    for (int i = 0; i < clientPrimServer.size(); ++i)
541    {
542      if (!finalized) clientPrimServer[i]->checkBuffers();
543      if (!finalized) finished &= serverPrimServer[i]->eventLoop(enableEventsProcessing);
544    }
545
546    if (server!=nullptr) if (!finalized) finished &= server->eventLoop(enableEventsProcessing);
547 
548    return finalized && finished ;
549  }
550
551 
552 
553  void CContext::globalEventLoop(void)
554  {
555    CXios::getDaemonsManager()->eventLoop() ;
556    setCurrent(getId()) ;
557  }
558
559
560   void CContext::finalize(void)
561   TRY
562   {
563      registryOut->hierarchicalGatherRegistry() ;
564      if (server->intraCommRank==0) CXios::globalRegistry->mergeRegistry(*registryOut) ;
565
566      if (hasClient && !hasServer)
567      {
568        doPreTimestepOperationsForEnabledReadModeFiles(); // For now we only use server level 1 to read data
569
570        info(100)<<"DEBUG: context "<<getId()<<" Send client finalize"<<endl ;
571        client->finalize();
572        info(100)<<"DEBUG: context "<<getId()<<" Client finalize sent"<<endl ;
573        while (client->havePendingRequests()) client->checkBuffers();
574        info(100)<<"DEBUG: context "<<getId()<<" no pending request ok"<<endl ;
575        bool notifiedFinalized=false ;
576        do
577        {
578          notifiedFinalized=client->isNotifiedFinalized() ;
579        } while (!notifiedFinalized) ;
580        client->releaseBuffers();
581        info(100)<<"DEBUG: context "<<getId()<<" release client ok"<<endl ;
582      }
583      else if (hasClient && hasServer)
584      {
585         for (int i = 0; i < clientPrimServer.size(); ++i)
586         {
587           clientPrimServer[i]->finalize();
588           bool bufferReleased;
589           do
590           {
591             clientPrimServer[i]->checkBuffers();
592             bufferReleased = !clientPrimServer[i]->havePendingRequests();
593           } while (!bufferReleased);
594           
595           bool notifiedFinalized=false ;
596           do
597           {
598             notifiedFinalized=clientPrimServer[i]->isNotifiedFinalized() ;
599           } while (!notifiedFinalized) ;
600           clientPrimServer[i]->releaseBuffers();
601         }
602         closeAllFile();
603
604      }
605      else if (!hasClient && hasServer)
606      {
607        closeAllFile();
608      }
609
610      freeComms() ;
611       
612      parentServerContext_->freeComm() ;
613      finalized = true;
614      info(20)<<"CContext: Context <"<<getId()<<"> is finalized."<<endl;
615   }
616   CATCH_DUMP_ATTR
617
618   //! Free internally allocated communicators
619   void CContext::freeComms(void)
620   TRY
621   {
622     for (std::list<MPI_Comm>::iterator it = comms.begin(); it != comms.end(); ++it)
623       MPI_Comm_free(&(*it));
624     comms.clear();
625   }
626   CATCH_DUMP_ATTR
627
628   //! Deallocate buffers allocated by clientContexts
629   void CContext::releaseClientBuffers(void)
630   TRY
631   {
632     client->releaseBuffers();
633     for (int i = 0; i < clientPrimServer.size(); ++i)
634       clientPrimServer[i]->releaseBuffers();
635   }
636   CATCH_DUMP_ATTR
637
638   void CContext::postProcessingGlobalAttributes()
639   TRY
640   {
641     if (allProcessed) return; 
642     
643    // create intercommunicator with servers.
644    // not sure it is the good place to be called here
645    createServerInterComm() ;
646
647
648     // After xml is parsed, there are some more works with post processing
649     postProcessing();
650
651     // Check grid and calculate its distribution
652     checkGridEnabledFields();
653 
654     // Distribute files between secondary servers according to the data size
655     distributeFiles();
656
657     setClientServerBuffer(client, (hasClient && !hasServer));
658     for (int i = 0; i < clientPrimServer.size(); ++i)
659         setClientServerBuffer(clientPrimServer[i], true);
660
661     if (hasClient)
662     {
663      // Send all attributes of current context to server
664      this->sendAllAttributesToServer();
665
666      // Send all attributes of current calendar
667      CCalendarWrapper::get(CCalendarWrapper::GetDefName())->sendAllAttributesToServer();
668
669      // We have enough information to send to server
670      // First of all, send all enabled files
671      sendEnabledFiles(this->enabledWriteModeFiles);
672      // We only use server-level 1 (for now) to read data
673      if (!hasServer)
674        sendEnabledFiles(this->enabledReadModeFiles);
675
676      // Then, send all enabled fields     
677      sendEnabledFieldsInFiles(this->enabledWriteModeFiles);
678      if (!hasServer)
679        sendEnabledFieldsInFiles(this->enabledReadModeFiles);
680
681      // Then, check whether we have domain_ref, axis_ref or scalar_ref attached to the enabled fields
682      // If any, so send them to server
683       sendRefDomainsAxisScalars(this->enabledWriteModeFiles);
684      if (!hasServer)
685        sendRefDomainsAxisScalars(this->enabledReadModeFiles);       
686
687       // Check whether enabled fields have grid_ref, if any, send this info to server
688      sendRefGrid(this->enabledFiles);
689      // This code may be useful in the future when we want to seperate completely read and write
690      // sendRefGrid(this->enabledWriteModeFiles);
691      // if (!hasServer)
692      //   sendRefGrid(this->enabledReadModeFiles);
693     
694      // A grid of enabled fields composed of several components which must be checked then their
695      // checked attributes should be sent to server
696      sendGridComponentEnabledFieldsInFiles(this->enabledFiles); // This code can be seperated in two (one for reading, another for writing)
697
698       // We have a xml tree on the server side and now, it should be also processed
699      sendPostProcessing();
700       
701      // Finally, we send information of grid itself to server
702      sendGridEnabledFieldsInFiles(this->enabledWriteModeFiles);       
703      if (!hasServer)
704        sendGridEnabledFieldsInFiles(this->enabledReadModeFiles);       
705     }
706     allProcessed = true;
707   }
708   CATCH_DUMP_ATTR
709
710   void CContext::sendPostProcessingGlobalAttributes()
711   TRY
712   {
713      // Use correct context client to send message
714     // int nbSrvPools = (hasServer) ? clientPrimServer.size() : 1;
715    int nbSrvPools = (this->hasServer) ? (this->hasClient ? this->clientPrimServer.size() : 0) : 1;
716     for (int i = 0; i < nbSrvPools; ++i)
717     {
718       CContextClient* contextClientTmp = (0 != clientPrimServer.size()) ? clientPrimServer[i] : client;
719       CEventClient event(getType(),EVENT_ID_POST_PROCESS_GLOBAL_ATTRIBUTES);
720
721       if (contextClientTmp->isServerLeader())
722       {
723         CMessage msg;
724         if (hasServer)
725           msg<<this->getIdServer(i);
726         else
727           msg<<this->getIdServer();
728         const std::list<int>& ranks = contextClientTmp->getRanksServerLeader();
729         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
730           event.push(*itRank,1,msg);
731         contextClientTmp->sendEvent(event);
732       }
733       else contextClientTmp->sendEvent(event);
734     }
735   }
736   CATCH_DUMP_ATTR
737
738   void CContext::recvPostProcessingGlobalAttributes(CEventServer& event)
739   TRY
740   {
741      CBufferIn* buffer=event.subEvents.begin()->buffer;
742      string id;
743      *buffer>>id;
744      get(id)->recvPostProcessingGlobalAttributes(*buffer);
745   }
746   CATCH
747
748   void CContext::recvPostProcessingGlobalAttributes(CBufferIn& buffer)
749   TRY
750   {     
751      postProcessingGlobalAttributes();
752   }
753   CATCH_DUMP_ATTR
754
755   /*!
756   \brief Close all the context defintion and do processing data
757      After everything is well defined on client side, they will be processed and sent to server
758   From the version 2.0, sever and client work no more on the same database. Moreover, client(s) will send
759   all necessary information to server, from which each server can build its own database.
760   Because the role of server is to write out field data on a specific netcdf file,
761   the only information that it needs is the enabled files
762   and the active fields (fields will be written onto active files)
763   */
764
765   void CContext::closeDefinition(void)
766   TRY
767   {
768     CTimer::get("Context : close definition").resume() ;
769   
770    //
771    postProcessingGlobalAttributes();
772
773    if (hasClient) sendPostProcessingGlobalAttributes();
774
775    // There are some processings that should be done after all of above. For example: check mask or index
776    this->buildFilterGraphOfEnabledFields();
777   
778     if (hasClient && !hasServer)
779    {
780      buildFilterGraphOfFieldsWithReadAccess();
781      postProcessFilterGraph();
782    }
783   
784    checkGridEnabledFields();   
785
786    if (hasClient) this->sendProcessingGridOfEnabledFields();
787    if (hasClient) this->sendCloseDefinition();
788
789    // Nettoyage de l'arborescence
790    if (hasClient) CleanTree(); // Only on client side??
791
792    if (hasClient)
793    {
794      sendCreateFileHeader();
795      if (!hasServer) startPrefetchingOfEnabledReadModeFiles();
796    }
797    CTimer::get("Context : close definition").suspend() ;
798   }
799   CATCH_DUMP_ATTR
800
801   void CContext::findAllEnabledFieldsInFiles(const std::vector<CFile*>& activeFiles)
802   TRY
803   {
804     for (unsigned int i = 0; i < activeFiles.size(); i++)
805     (void)activeFiles[i]->getEnabledFields();
806   }
807   CATCH_DUMP_ATTR
808
809   void CContext::readAttributesOfEnabledFieldsInReadModeFiles()
810   TRY
811   {
812      for (unsigned int i = 0; i < this->enabledReadModeFiles.size(); ++i)
813        (void)this->enabledReadModeFiles[i]->readAttributesOfEnabledFieldsInReadMode();
814   }
815   CATCH_DUMP_ATTR
816
817   void CContext::sendGridComponentEnabledFieldsInFiles(const std::vector<CFile*>& activeFiles)
818   TRY
819   {
820     int size = activeFiles.size();
821     for (int i = 0; i < size; ++i)
822     {       
823       activeFiles[i]->sendGridComponentOfEnabledFields();
824     }
825   }
826   CATCH_DUMP_ATTR
827
828   /*!
829      Send active (enabled) fields in file from a client to others
830      \param [in] activeFiles files contains enabled fields to send
831   */
832   void CContext::sendGridEnabledFieldsInFiles(const std::vector<CFile*>& activeFiles)
833   TRY
834   {
835     int size = activeFiles.size();
836     for (int i = 0; i < size; ++i)
837     {       
838       activeFiles[i]->sendGridOfEnabledFields();
839     }
840   }
841   CATCH_DUMP_ATTR
842
843   void CContext::checkGridEnabledFields()
844   TRY
845   {
846     int size = enabledFiles.size();
847     for (int i = 0; i < size; ++i)
848     {
849       enabledFiles[i]->checkGridOfEnabledFields();       
850     }
851   }
852   CATCH_DUMP_ATTR
853
854   /*!
855      Check grid of active (enabled) fields in file
856      \param [in] activeFiles files contains enabled fields whose grid needs checking
857   */
858   void CContext::checkGridEnabledFieldsInFiles(const std::vector<CFile*>& activeFiles)
859   TRY
860   {
861     int size = activeFiles.size();
862     for (int i = 0; i < size; ++i)
863     {
864       activeFiles[i]->checkGridOfEnabledFields();       
865     }
866   }
867   CATCH_DUMP_ATTR
868
869    /*!
870      Go up the hierachical tree via field_ref and do check of attributes of fields
871      This can be done in a client then all computed information will be sent from this client to others
872      \param [in] sendToServer Flag to indicate whether calculated information will be sent
873   */
874   void CContext::solveOnlyRefOfEnabledFields(bool sendToServer)
875   TRY
876   {
877     int size = this->enabledFiles.size();
878     for (int i = 0; i < size; ++i)
879     {
880       this->enabledFiles[i]->solveOnlyRefOfEnabledFields(sendToServer);
881     }
882
883     for (int i = 0; i < size; ++i)
884     {
885       this->enabledFiles[i]->generateNewTransformationGridDest();
886     }
887   }
888   CATCH_DUMP_ATTR
889
890    /*!
891      Go up the hierachical tree via field_ref and do check of attributes of fields.
892      The transformation can be done in this step.
893      All computed information will be sent from this client to others.
894      \param [in] sendToServer Flag to indicate whether calculated information will be sent
895   */
896   void CContext::solveAllRefOfEnabledFieldsAndTransform(bool sendToServer)
897   TRY
898   {
899     int size = this->enabledFiles.size();
900     for (int i = 0; i < size; ++i)
901     {
902       this->enabledFiles[i]->solveAllRefOfEnabledFieldsAndTransform(sendToServer);
903     }
904   }
905   CATCH_DUMP_ATTR
906
907   void CContext::buildFilterGraphOfEnabledFields()
908   TRY
909   {
910     int size = this->enabledFiles.size();
911     for (int i = 0; i < size; ++i)
912     {
913       this->enabledFiles[i]->buildFilterGraphOfEnabledFields(garbageCollector);
914     }
915   }
916   CATCH_DUMP_ATTR
917
918   void CContext::postProcessFilterGraph()
919   TRY
920   {
921     int size = enabledFiles.size();
922     for (int i = 0; i < size; ++i)
923     {
924        enabledFiles[i]->postProcessFilterGraph();
925     }
926   }
927   CATCH_DUMP_ATTR
928
929   void CContext::startPrefetchingOfEnabledReadModeFiles()
930   TRY
931   {
932     int size = enabledReadModeFiles.size();
933     for (int i = 0; i < size; ++i)
934     {
935        enabledReadModeFiles[i]->prefetchEnabledReadModeFields();
936     }
937   }
938   CATCH_DUMP_ATTR
939
940   void CContext::doPreTimestepOperationsForEnabledReadModeFiles()
941   TRY
942   {
943     int size = enabledReadModeFiles.size();
944     for (int i = 0; i < size; ++i)
945     {
946        enabledReadModeFiles[i]->doPreTimestepOperationsForEnabledReadModeFields();
947     }
948   }
949   CATCH_DUMP_ATTR
950
951   void CContext::doPostTimestepOperationsForEnabledReadModeFiles()
952   TRY
953   {
954     int size = enabledReadModeFiles.size();
955     for (int i = 0; i < size; ++i)
956     {
957        enabledReadModeFiles[i]->doPostTimestepOperationsForEnabledReadModeFields();
958     }
959   }
960   CATCH_DUMP_ATTR
961
962  void CContext::findFieldsWithReadAccess(void)
963  TRY
964  {
965    fieldsWithReadAccess.clear();
966    const vector<CField*> allFields = CField::getAll();
967    for (size_t i = 0; i < allFields.size(); ++i)
968    {
969      CField* field = allFields[i];
970
971      if (field->file && !field->file->mode.isEmpty() && field->file->mode == CFile::mode_attr::read)
972        field->read_access = true;
973      else if (!field->read_access.isEmpty() && field->read_access && (field->enabled.isEmpty() || field->enabled))
974        fieldsWithReadAccess.push_back(field);
975    }
976  }
977  CATCH_DUMP_ATTR
978
979  void CContext::solveAllRefOfFieldsWithReadAccess()
980  TRY
981  {
982    for (size_t i = 0; i < fieldsWithReadAccess.size(); ++i)
983      fieldsWithReadAccess[i]->solveAllReferenceEnabledField(false);
984  }
985  CATCH_DUMP_ATTR
986
987  void CContext::buildFilterGraphOfFieldsWithReadAccess()
988  TRY
989  {
990    for (size_t i = 0; i < fieldsWithReadAccess.size(); ++i)
991      fieldsWithReadAccess[i]->buildFilterGraph(garbageCollector, true);
992  }
993  CATCH_DUMP_ATTR
994
995   void CContext::solveAllInheritance(bool apply)
996   TRY
997   {
998     // Résolution des héritages descendants (càd des héritages de groupes)
999     // pour chacun des contextes.
1000      solveDescInheritance(apply);
1001
1002     // Résolution des héritages par référence au niveau des fichiers.
1003      const vector<CFile*> allFiles=CFile::getAll();
1004      const vector<CGrid*> allGrids= CGrid::getAll();
1005
1006      if (hasClient && !hasServer)
1007      //if (hasClient)
1008      {
1009        for (unsigned int i = 0; i < allFiles.size(); i++)
1010          allFiles[i]->solveFieldRefInheritance(apply);
1011      }
1012
1013      unsigned int vecSize = allGrids.size();
1014      unsigned int i = 0;
1015      for (i = 0; i < vecSize; ++i)
1016        allGrids[i]->solveDomainAxisRefInheritance(apply);
1017
1018   }
1019  CATCH_DUMP_ATTR
1020
1021   void CContext::findEnabledFiles(void)
1022   TRY
1023   {
1024      const std::vector<CFile*> allFiles = CFile::getAll();
1025      const CDate& initDate = calendar->getInitDate();
1026
1027      for (unsigned int i = 0; i < allFiles.size(); i++)
1028         if (!allFiles[i]->enabled.isEmpty()) // Si l'attribut 'enabled' est défini.
1029         {
1030            if (allFiles[i]->enabled.getValue()) // Si l'attribut 'enabled' est fixé à vrai.
1031            {
1032              if (allFiles[i]->output_freq.isEmpty())
1033              {
1034                 ERROR("CContext::findEnabledFiles()",
1035                     << "Mandatory attribute output_freq must be defined for file \""<<allFiles[i]->getFileOutputName()
1036                     <<" \".")
1037              }
1038              if ((initDate + allFiles[i]->output_freq.getValue()) < (initDate + this->getCalendar()->getTimeStep()))
1039              {
1040                error(0)<<"WARNING: void CContext::findEnabledFiles()"<<endl
1041                    << "Output frequency in file \""<<allFiles[i]->getFileOutputName()
1042                    <<"\" is less than the time step. File will not be written."<<endl;
1043              }
1044              else
1045               enabledFiles.push_back(allFiles[i]);
1046            }
1047         }
1048         else
1049         {
1050           if (allFiles[i]->output_freq.isEmpty())
1051           {
1052              ERROR("CContext::findEnabledFiles()",
1053                  << "Mandatory attribute output_freq must be defined for file \""<<allFiles[i]->getFileOutputName()
1054                  <<" \".")
1055           }
1056           if ( (initDate + allFiles[i]->output_freq.getValue()) < (initDate + this->getCalendar()->getTimeStep()))
1057           {
1058             error(0)<<"WARNING: void CContext::findEnabledFiles()"<<endl
1059                 << "Output frequency in file \""<<allFiles[i]->getFileOutputName()
1060                 <<"\" is less than the time step. File will not be written."<<endl;
1061           }
1062           else
1063             enabledFiles.push_back(allFiles[i]); // otherwise true by default
1064         }
1065
1066      if (enabledFiles.size() == 0)
1067         DEBUG(<<"Aucun fichier ne va être sorti dans le contexte nommé \""
1068               << getId() << "\" !");
1069
1070   }
1071   CATCH_DUMP_ATTR
1072
1073   void CContext::distributeFiles(void)
1074   TRY
1075   {
1076     bool distFileMemory=false ;
1077     distFileMemory=CXios::getin<bool>("server2_dist_file_memory", distFileMemory);
1078
1079     if (distFileMemory) distributeFileOverMemoryBandwith() ;
1080     else distributeFileOverBandwith() ;
1081   }
1082   CATCH_DUMP_ATTR
1083
1084   void CContext::distributeFileOverBandwith(void)
1085   TRY
1086   {
1087     double eps=std::numeric_limits<double>::epsilon()*10 ;
1088     
1089     // If primary server
1090     if (hasServer && hasClient)
1091     {
1092       std::ofstream ofs(("distribute_file_"+getId()+".dat").c_str(), std::ofstream::out);
1093       int nbPools = clientPrimServer.size();
1094
1095       // (1) Find all enabled files in write mode
1096       // for (int i = 0; i < this->enabledFiles.size(); ++i)
1097       // {
1098       //   if (enabledFiles[i]->mode.isEmpty() || (!enabledFiles[i]->mode.isEmpty() && enabledFiles[i]->mode.getValue() == CFile::mode_attr::write ))
1099       //    enabledWriteModeFiles.push_back(enabledFiles[i]);
1100       // }
1101
1102       // (2) Estimate the data volume for each file
1103       int size = this->enabledWriteModeFiles.size();
1104       std::vector<std::pair<double, CFile*> > dataSizeMap;
1105       double dataPerPool = 0;
1106       int nfield=0 ;
1107       ofs<<size<<endl ;
1108       for (size_t i = 0; i < size; ++i)
1109       {
1110         CFile* file = this->enabledWriteModeFiles[i];
1111         ofs<<file->getId()<<endl ;
1112         StdSize dataSize=0;
1113         std::vector<CField*> enabledFields = file->getEnabledFields();
1114         size_t numEnabledFields = enabledFields.size();
1115         ofs<<numEnabledFields<<endl ;
1116         for (size_t j = 0; j < numEnabledFields; ++j)
1117         {
1118           dataSize += enabledFields[j]->getGlobalWrittenSize() ;
1119           ofs<<enabledFields[j]->grid->getId()<<endl ;
1120           ofs<<enabledFields[j]->getGlobalWrittenSize()<<endl ;
1121         }
1122         double outFreqSec = (Time)(calendar->getCurrentDate()+file->output_freq)-(Time)(calendar->getCurrentDate()) ;
1123         double dataSizeSec= dataSize/ outFreqSec;
1124         ofs<<dataSizeSec<<endl ;
1125         nfield++ ;
1126// add epsilon*nField to dataSizeSec in order to  preserve reproductive ordering when sorting
1127         dataSizeMap.push_back(make_pair(dataSizeSec + dataSizeSec * eps * nfield , file));
1128         dataPerPool += dataSizeSec;
1129       }
1130       dataPerPool /= nbPools;
1131       std::sort(dataSizeMap.begin(), dataSizeMap.end());
1132
1133       // (3) Assign contextClient to each enabled file
1134
1135       std::multimap<double,int> poolDataSize ;
1136// multimap is not garanty to preserve stable sorting in c++98 but it seems it does for c++11
1137
1138       int j;
1139       double dataSize ;
1140       for (j = 0 ; j < nbPools ; ++j) poolDataSize.insert(std::pair<double,int>(0.,j)) ; 
1141             
1142       for (int i = dataSizeMap.size()-1; i >= 0; --i)
1143       {
1144         dataSize=(*poolDataSize.begin()).first ;
1145         j=(*poolDataSize.begin()).second ;
1146         dataSizeMap[i].second->setContextClient(clientPrimServer[j]);
1147         dataSize+=dataSizeMap[i].first;
1148         poolDataSize.erase(poolDataSize.begin()) ;
1149         poolDataSize.insert(std::pair<double,int>(dataSize,j)) ; 
1150       }
1151
1152       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 ;
1153 
1154       for (int i = 0; i < this->enabledReadModeFiles.size(); ++i)
1155       {
1156         enabledReadModeFiles[i]->setContextClient(client);         
1157       }
1158     }
1159     else
1160     {
1161       for (int i = 0; i < this->enabledFiles.size(); ++i)
1162         enabledFiles[i]->setContextClient(client);
1163     }
1164   }
1165   CATCH_DUMP_ATTR
1166
1167   void CContext::distributeFileOverMemoryBandwith(void)
1168   TRY
1169   {
1170     // If primary server
1171     if (hasServer && hasClient)
1172     {
1173       int nbPools = clientPrimServer.size();
1174       double ratio=0.5 ;
1175       ratio=CXios::getin<double>("server2_dist_file_memory_ratio", ratio);
1176
1177       int nFiles = this->enabledWriteModeFiles.size();
1178       vector<SDistFile> files(nFiles);
1179       vector<SDistGrid> grids;
1180       map<string,int> gridMap ;
1181       string gridId; 
1182       int gridIndex=0 ;
1183
1184       for (size_t i = 0; i < nFiles; ++i)
1185       {
1186         StdSize dataSize=0;
1187         CFile* file = this->enabledWriteModeFiles[i];
1188         std::vector<CField*> enabledFields = file->getEnabledFields();
1189         size_t numEnabledFields = enabledFields.size();
1190
1191         files[i].id_=file->getId() ;
1192         files[i].nbGrids_=numEnabledFields;
1193         files[i].assignedGrid_ = new int[files[i].nbGrids_] ;
1194         
1195         for (size_t j = 0; j < numEnabledFields; ++j)
1196         {
1197           gridId=enabledFields[j]->grid->getId() ;
1198           if (gridMap.find(gridId)==gridMap.end())
1199           {
1200              gridMap[gridId]=gridIndex  ;
1201              SDistGrid newGrid; 
1202              grids.push_back(newGrid) ;
1203              gridIndex++ ;
1204           }
1205           files[i].assignedGrid_[j]=gridMap[gridId] ;
1206           grids[files[i].assignedGrid_[j]].size_=enabledFields[j]->getGlobalWrittenSize() ;
1207           dataSize += enabledFields[j]->getGlobalWrittenSize() ; // usefull
1208         }
1209         double outFreqSec = (Time)(calendar->getCurrentDate()+file->output_freq)-(Time)(calendar->getCurrentDate()) ;
1210         files[i].bandwith_= dataSize/ outFreqSec ;
1211       }
1212
1213       double bandwith=0 ;
1214       double memory=0 ;
1215   
1216       for(int i=0; i<nFiles; i++)  bandwith+=files[i].bandwith_ ;
1217       for(int i=0; i<nFiles; i++)  files[i].bandwith_ = files[i].bandwith_/bandwith * ratio ;
1218
1219       for(int i=0; i<grids.size(); i++)  memory+=grids[i].size_ ;
1220       for(int i=0; i<grids.size(); i++)  grids[i].size_ = grids[i].size_ / memory * (1.0-ratio) ;
1221       
1222       distributeFileOverServer2(nbPools, grids.size(), &grids[0], nFiles, &files[0]) ;
1223
1224       vector<double> memorySize(nbPools,0.) ;
1225       vector< set<int> > serverGrids(nbPools) ;
1226       vector<double> bandwithSize(nbPools,0.) ;
1227       
1228       for (size_t i = 0; i < nFiles; ++i)
1229       {
1230         bandwithSize[files[i].assignedServer_] += files[i].bandwith_* bandwith /ratio ;
1231         for(int j=0 ; j<files[i].nbGrids_;j++)
1232         {
1233           if (serverGrids[files[i].assignedServer_].find(files[i].assignedGrid_[j]) == serverGrids[files[i].assignedServer_].end())
1234           {
1235             memorySize[files[i].assignedServer_]+= grids[files[i].assignedGrid_[j]].size_ * memory / (1.0-ratio);
1236             serverGrids[files[i].assignedServer_].insert(files[i].assignedGrid_[j]) ;
1237           }
1238         }
1239         enabledWriteModeFiles[i]->setContextClient(clientPrimServer[files[i].assignedServer_]) ;
1240         delete [] files[i].assignedGrid_ ;
1241       }
1242
1243       for (int i = 0; i < nbPools; ++i) info(100)<<"Pool server level2 "<<i<<"   assigned file bandwith "<<bandwithSize[i]*86400.*4./1024/1024.<<" Mb / days"<<endl ;
1244       for (int i = 0; i < nbPools; ++i) info(100)<<"Pool server level2 "<<i<<"   assigned grid memory "<<memorySize[i]*100/1024./1024.<<" Mb"<<endl ;
1245
1246
1247       for (int i = 0; i < this->enabledReadModeFiles.size(); ++i)
1248       {
1249         enabledReadModeFiles[i]->setContextClient(client);         
1250       }
1251
1252   }
1253   else
1254   {
1255     for (int i = 0; i < this->enabledFiles.size(); ++i)
1256        enabledFiles[i]->setContextClient(client);
1257   }
1258}
1259   CATCH_DUMP_ATTR
1260
1261   /*!
1262      Find all files in write mode
1263   */
1264   void CContext::findEnabledWriteModeFiles(void)
1265   TRY
1266   {
1267     int size = this->enabledFiles.size();
1268     for (int i = 0; i < size; ++i)
1269     {
1270       if (enabledFiles[i]->mode.isEmpty() || 
1271          (!enabledFiles[i]->mode.isEmpty() && enabledFiles[i]->mode.getValue() == CFile::mode_attr::write ))
1272        enabledWriteModeFiles.push_back(enabledFiles[i]);
1273     }
1274   }
1275   CATCH_DUMP_ATTR
1276
1277   /*!
1278      Find all files in read mode
1279   */
1280   void CContext::findEnabledReadModeFiles(void)
1281   TRY
1282   {
1283     int size = this->enabledFiles.size();
1284     for (int i = 0; i < size; ++i)
1285     {
1286       if (!enabledFiles[i]->mode.isEmpty() && enabledFiles[i]->mode.getValue() == CFile::mode_attr::read)
1287        enabledReadModeFiles.push_back(enabledFiles[i]);
1288     }
1289   }
1290   CATCH_DUMP_ATTR
1291
1292   void CContext::closeAllFile(void)
1293   TRY
1294   {
1295     std::vector<CFile*>::const_iterator
1296            it = this->enabledFiles.begin(), end = this->enabledFiles.end();
1297
1298     for (; it != end; it++)
1299     {
1300       info(30)<<"Closing File : "<<(*it)->getId()<<endl;
1301       (*it)->close();
1302     }
1303   }
1304   CATCH_DUMP_ATTR
1305
1306   /*!
1307   \brief Dispatch event received from client
1308      Whenever a message is received in buffer of server, it will be processed depending on
1309   its event type. A new event type should be added in the switch list to make sure
1310   it processed on server side.
1311   \param [in] event: Received message
1312   */
1313   bool CContext::dispatchEvent(CEventServer& event)
1314   TRY
1315   {
1316
1317      if (SuperClass::dispatchEvent(event)) return true;
1318      else
1319      {
1320        switch(event.type)
1321        {
1322           case EVENT_ID_CLOSE_DEFINITION :
1323             recvCloseDefinition(event);
1324             return true;
1325             break;
1326           case EVENT_ID_UPDATE_CALENDAR:
1327             recvUpdateCalendar(event);
1328             return true;
1329             break;
1330           case EVENT_ID_CREATE_FILE_HEADER :
1331             recvCreateFileHeader(event);
1332             return true;
1333             break;
1334           case EVENT_ID_POST_PROCESS:
1335             recvPostProcessing(event);
1336             return true;
1337            case EVENT_ID_SEND_REGISTRY:
1338             recvRegistry(event);
1339             return true;
1340             break;
1341            case EVENT_ID_POST_PROCESS_GLOBAL_ATTRIBUTES:
1342             recvPostProcessingGlobalAttributes(event);
1343             return true;
1344             break;
1345            case EVENT_ID_PROCESS_GRID_ENABLED_FIELDS:
1346             recvProcessingGridOfEnabledFields(event);
1347             return true;
1348             break;
1349           default :
1350             ERROR("bool CContext::dispatchEvent(CEventServer& event)",
1351                    <<"Unknown Event");
1352           return false;
1353         }
1354      }
1355   }
1356   CATCH
1357
1358   //! Client side: Send a message to server to make it close
1359   void CContext::sendCloseDefinition(void)
1360   TRY
1361   {
1362     // Use correct context client to send message
1363     int nbSrvPools = (this->hasServer) ? (this->hasClient ? this->clientPrimServer.size() : 0) : 1;
1364     for (int i = 0; i < nbSrvPools; ++i)
1365     {
1366       CContextClient* contextClientTmp = (hasServer) ? clientPrimServer[i] : client;
1367       CEventClient event(getType(),EVENT_ID_CLOSE_DEFINITION);
1368       if (contextClientTmp->isServerLeader())
1369       {
1370         CMessage msg;
1371         if (hasServer)
1372           msg<<this->getIdServer(i);
1373         else
1374           msg<<this->getIdServer();
1375         const std::list<int>& ranks = contextClientTmp->getRanksServerLeader();
1376         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
1377           event.push(*itRank,1,msg);
1378         contextClientTmp->sendEvent(event);
1379       }
1380       else contextClientTmp->sendEvent(event);
1381     }
1382   }
1383   CATCH_DUMP_ATTR
1384
1385   //! Server side: Receive a message of client announcing a context close
1386   void CContext::recvCloseDefinition(CEventServer& event)
1387   TRY
1388   {
1389      CBufferIn* buffer=event.subEvents.begin()->buffer;
1390      string id;
1391      *buffer>>id;
1392      get(id)->closeDefinition();
1393   }
1394   CATCH
1395
1396   //! Client side: Send a message to update calendar in each time step
1397   void CContext::sendUpdateCalendar(int step)
1398   TRY
1399   {
1400     // Use correct context client to send message
1401    int nbSrvPools = (this->hasServer) ? (this->hasClient ? this->clientPrimServer.size() : 0) : 1;
1402     for (int i = 0; i < nbSrvPools; ++i)
1403     {
1404       CContextClient* contextClientTmp = (hasServer) ? clientPrimServer[i] : client;
1405       CEventClient event(getType(),EVENT_ID_UPDATE_CALENDAR);
1406
1407         if (contextClientTmp->isServerLeader())
1408         {
1409           CMessage msg;
1410           if (hasServer)
1411             msg<<this->getIdServer(i)<<step;
1412           else
1413             msg<<this->getIdServer()<<step;
1414           const std::list<int>& ranks = contextClientTmp->getRanksServerLeader();
1415           for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
1416             event.push(*itRank,1,msg);
1417           contextClientTmp->sendEvent(event);
1418         }
1419         else contextClientTmp->sendEvent(event);
1420     }
1421   }
1422   CATCH_DUMP_ATTR
1423
1424   //! Server side: Receive a message of client annoucing calendar update
1425   void CContext::recvUpdateCalendar(CEventServer& event)
1426   TRY
1427   {
1428      CBufferIn* buffer=event.subEvents.begin()->buffer;
1429      string id;
1430      *buffer>>id;
1431      get(id)->recvUpdateCalendar(*buffer);
1432   }
1433   CATCH
1434
1435   //! Server side: Receive a message of client annoucing calendar update
1436   void CContext::recvUpdateCalendar(CBufferIn& buffer)
1437   TRY
1438   {
1439      int step;
1440      buffer>>step;
1441      updateCalendar(step);
1442      if (hasClient && hasServer)
1443      {       
1444        sendUpdateCalendar(step);
1445      }
1446   }
1447   CATCH_DUMP_ATTR
1448
1449   //! Client side: Send a message to create header part of netcdf file
1450   void CContext::sendCreateFileHeader(void)
1451   TRY
1452   {
1453     // Use correct context client to send message
1454     // int nbSrvPools = (hasServer) ? clientPrimServer.size() : 1;
1455     int nbSrvPools = (this->hasServer) ? (this->hasClient ? this->clientPrimServer.size() : 0) : 1;
1456     for (int i = 0; i < nbSrvPools; ++i)
1457     {
1458       CContextClient* contextClientTmp = (hasServer) ? clientPrimServer[i] : client;
1459       CEventClient event(getType(),EVENT_ID_CREATE_FILE_HEADER);
1460
1461       if (contextClientTmp->isServerLeader())
1462       {
1463         CMessage msg;
1464         if (hasServer)
1465           msg<<this->getIdServer(i);
1466         else
1467           msg<<this->getIdServer();
1468         const std::list<int>& ranks = contextClientTmp->getRanksServerLeader();
1469         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
1470           event.push(*itRank,1,msg) ;
1471         contextClientTmp->sendEvent(event);
1472       }
1473       else contextClientTmp->sendEvent(event);
1474     }
1475   }
1476   CATCH_DUMP_ATTR
1477
1478   //! Server side: Receive a message of client annoucing the creation of header part of netcdf file
1479   void CContext::recvCreateFileHeader(CEventServer& event)
1480   TRY
1481   {
1482      CBufferIn* buffer=event.subEvents.begin()->buffer;
1483      string id;
1484      *buffer>>id;
1485      get(id)->recvCreateFileHeader(*buffer);
1486   }
1487   CATCH
1488
1489   //! Server side: Receive a message of client annoucing the creation of header part of netcdf file
1490   void CContext::recvCreateFileHeader(CBufferIn& buffer)
1491   TRY
1492   {
1493      if (!hasClient && hasServer) 
1494        createFileHeader();
1495   }
1496   CATCH_DUMP_ATTR
1497
1498   //! Client side: Send a message to do some post processing on server
1499   void CContext::sendProcessingGridOfEnabledFields()
1500   TRY
1501   {
1502      // Use correct context client to send message
1503     int nbSrvPools = (this->hasServer) ? (this->hasClient ? this->clientPrimServer.size() : 0) : 1;
1504     for (int i = 0; i < nbSrvPools; ++i)
1505     {
1506       CContextClient* contextClientTmp = (0 != clientPrimServer.size()) ? clientPrimServer[i] : client;
1507       CEventClient event(getType(),EVENT_ID_PROCESS_GRID_ENABLED_FIELDS);
1508
1509       if (contextClientTmp->isServerLeader())
1510       {
1511         CMessage msg;
1512         if (hasServer)
1513           msg<<this->getIdServer(i);
1514         else
1515           msg<<this->getIdServer();
1516         const std::list<int>& ranks = contextClientTmp->getRanksServerLeader();
1517         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
1518           event.push(*itRank,1,msg);
1519         contextClientTmp->sendEvent(event);
1520       }
1521       else contextClientTmp->sendEvent(event);
1522     }
1523   }
1524   CATCH_DUMP_ATTR
1525
1526   //! Server side: Receive a message to do some post processing
1527   void CContext::recvProcessingGridOfEnabledFields(CEventServer& event)
1528   TRY
1529   {
1530      CBufferIn* buffer=event.subEvents.begin()->buffer;
1531      string id;
1532      *buffer>>id;     
1533   }
1534   CATCH
1535
1536   //! Client side: Send a message to do some post processing on server
1537   void CContext::sendPostProcessing()
1538   TRY
1539   {
1540      // Use correct context client to send message
1541     // int nbSrvPools = (hasServer) ? clientPrimServer.size() : 1;
1542     int nbSrvPools = (this->hasServer) ? (this->hasClient ? this->clientPrimServer.size() : 0) : 1;
1543     for (int i = 0; i < nbSrvPools; ++i)
1544     {
1545       CContextClient* contextClientTmp = (hasServer) ? clientPrimServer[i] : client;
1546       CEventClient event(getType(),EVENT_ID_POST_PROCESS);
1547       if (contextClientTmp->isServerLeader())
1548       {
1549         CMessage msg;
1550         if (hasServer)
1551           msg<<this->getIdServer(i);
1552         else
1553           msg<<this->getIdServer();
1554         const std::list<int>& ranks = contextClientTmp->getRanksServerLeader();
1555         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
1556         event.push(*itRank,1,msg);
1557         contextClientTmp->sendEvent(event);
1558       }
1559       else contextClientTmp->sendEvent(event);
1560     }
1561   }
1562   CATCH_DUMP_ATTR
1563
1564   //! Server side: Receive a message to do some post processing
1565   void CContext::recvPostProcessing(CEventServer& event)
1566   TRY
1567   {
1568      CBufferIn* buffer=event.subEvents.begin()->buffer;
1569      string id;
1570      *buffer>>id;
1571      get(id)->recvPostProcessing(*buffer);
1572   }
1573   CATCH
1574
1575   //! Server side: Receive a message to do some post processing
1576   void CContext::recvPostProcessing(CBufferIn& buffer)
1577   TRY
1578   {
1579      CCalendarWrapper::get(CCalendarWrapper::GetDefName())->createCalendar();
1580      postProcessing();
1581   }
1582   CATCH_DUMP_ATTR
1583
1584   void CContext::setIdServer(const StdString& idServer)
1585   TRY
1586   {
1587      idServer_=idServer ;
1588   }
1589   CATCH_DUMP_ATTR
1590
1591   
1592   const StdString& CContext::getIdServer()
1593   TRY
1594   {
1595      return idServer_;
1596   }
1597   CATCH_DUMP_ATTR
1598
1599   const StdString& CContext::getIdServer(const int i)
1600   TRY
1601   {
1602//     return idServer_ + std::to_string(static_cast<unsigned long long>(i));
1603      return primServerId_[i] ;
1604   }
1605   CATCH_DUMP_ATTR
1606
1607/*
1608   const StdString& CContext::getIdServer()
1609   TRY
1610   {
1611      if (hasClient)
1612      {
1613        idServer_ = this->getId();
1614        idServer_ += "_server";
1615        return idServer_;
1616      }
1617      if (hasServer) return (this->getId());
1618   }
1619   CATCH_DUMP_ATTR
1620
1621   const StdString& CContext::getIdServer(const int i)
1622   TRY
1623   {
1624     idServer_ = this->getId();
1625     idServer_ += "_server_";
1626     idServer_ += std::to_string(static_cast<unsigned long long>(i));
1627     return idServer_;
1628   }
1629   CATCH_DUMP_ATTR
1630*/
1631
1632
1633   /*!
1634   \brief Do some simple post processings after parsing xml file
1635      After the xml file (iodef.xml) is parsed, it is necessary to build all relations among
1636   created object, e.g: inhertance among fields, domain, axis. After that, all fiels as well as their parents (reference fields),
1637   which will be written out into netcdf files, are processed
1638   */
1639   void CContext::postProcessing()
1640   TRY
1641   {
1642     if (isPostProcessed) return;
1643
1644      // Make sure the calendar was correctly created
1645      if (!calendar)
1646        ERROR("CContext::postProcessing()", << "A calendar must be defined for the context \"" << getId() << "!\"")
1647      else if (calendar->getTimeStep() == NoneDu)
1648        ERROR("CContext::postProcessing()", << "A timestep must be defined for the context \"" << getId() << "!\"")
1649      // Calendar first update to set the current date equals to the start date
1650      calendar->update(0);
1651
1652      // Find all inheritance in xml structure
1653      this->solveAllInheritance();
1654
1655//      ShowTree(info(10));
1656
1657      // Check if some axis, domains or grids are eligible to for compressed indexed output.
1658      // Warning: This must be done after solving the inheritance and before the rest of post-processing
1659      checkAxisDomainsGridsEligibilityForCompressedOutput();     
1660
1661      // Check if some automatic time series should be generated
1662      // Warning: This must be done after solving the inheritance and before the rest of post-processing     
1663
1664      // The timeseries should only be prepared in client
1665      if (hasClient && !hasServer) prepareTimeseries();
1666
1667      //Initialisation du vecteur 'enabledFiles' contenant la liste des fichiers à sortir.
1668      findEnabledFiles();
1669      findEnabledWriteModeFiles();
1670      findEnabledReadModeFiles();
1671
1672      // For now, only read files with client and only one level server
1673      // if (hasClient && !hasServer) findEnabledReadModeFiles();     
1674
1675      // Find all enabled fields of each file     
1676      findAllEnabledFieldsInFiles(this->enabledWriteModeFiles);
1677      findAllEnabledFieldsInFiles(this->enabledReadModeFiles);
1678
1679      // For now, only read files with client and only one level server
1680      // if (hasClient && !hasServer)
1681      //   findAllEnabledFieldsInFiles(this->enabledReadModeFiles);     
1682
1683      if (hasClient && !hasServer)
1684      {
1685        initReadFiles();
1686        // Try to read attributes of fields in file then fill in corresponding grid (or domain, axis)
1687        this->readAttributesOfEnabledFieldsInReadModeFiles();
1688      }
1689
1690      // Only search and rebuild all reference objects of enable fields, don't transform
1691      this->solveOnlyRefOfEnabledFields(false);
1692
1693      // Search and rebuild all reference object of enabled fields, and transform
1694      this->solveAllRefOfEnabledFieldsAndTransform(false);
1695
1696      // Find all fields with read access from the public API
1697      if (hasClient && !hasServer) findFieldsWithReadAccess();
1698      // and solve the all reference for them
1699      if (hasClient && !hasServer) solveAllRefOfFieldsWithReadAccess();
1700
1701      isPostProcessed = true;
1702   }
1703   CATCH_DUMP_ATTR
1704
1705   /*!
1706    * Compute the required buffer size to send the attributes (mostly those grid related).
1707    * \param maxEventSize [in/out] the size of the bigger event for each connected server
1708    * \param [in] contextClient
1709    * \param [in] bufferForWriting True if buffers are used for sending data for writing
1710      This flag is only true for client and server-1 for communication with server-2
1711    */
1712   std::map<int, StdSize> CContext::getAttributesBufferSize(std::map<int, StdSize>& maxEventSize,
1713                                                           CContextClient* contextClient, bool bufferForWriting /*= "false"*/)
1714   TRY
1715   {
1716         // As calendar attributes are sent even if there are no active files or fields, maps are initialized according the size of calendar attributes
1717     std::map<int, StdSize> attributesSize = CCalendarWrapper::get(CCalendarWrapper::GetDefName())->getMinimumBufferSizeForAttributes(contextClient);
1718     maxEventSize = CCalendarWrapper::get(CCalendarWrapper::GetDefName())->getMinimumBufferSizeForAttributes(contextClient);
1719
1720     std::vector<CFile*>& fileList = this->enabledFiles;
1721     size_t numEnabledFiles = fileList.size();
1722     for (size_t i = 0; i < numEnabledFiles; ++i)
1723     {
1724//         CFile* file = this->enabledWriteModeFiles[i];
1725        CFile* file = fileList[i];
1726        std::vector<CField*> enabledFields = file->getEnabledFields();
1727        size_t numEnabledFields = enabledFields.size();
1728        for (size_t j = 0; j < numEnabledFields; ++j)
1729        {
1730          const std::map<int, StdSize> mapSize = enabledFields[j]->getGridAttributesBufferSize(contextClient, bufferForWriting);
1731          std::map<int, StdSize>::const_iterator it = mapSize.begin(), itE = mapSize.end();
1732          for (; it != itE; ++it)
1733          {
1734                     // If attributesSize[it->first] does not exist, it will be zero-initialized
1735                     // so we can use it safely without checking for its existence
1736             if (attributesSize[it->first] < it->second)
1737                           attributesSize[it->first] = it->second;
1738
1739                     if (maxEventSize[it->first] < it->second)
1740                           maxEventSize[it->first] = it->second;
1741          }
1742        }
1743     }
1744     return attributesSize;
1745   }
1746   CATCH_DUMP_ATTR
1747
1748   /*!
1749    * Compute the required buffer size to send the fields data.
1750    * \param maxEventSize [in/out] the size of the bigger event for each connected server
1751    * \param [in] contextClient
1752    * \param [in] bufferForWriting True if buffers are used for sending data for writing
1753      This flag is only true for client and server-1 for communication with server-2
1754    */
1755   std::map<int, StdSize> CContext::getDataBufferSize(std::map<int, StdSize>& maxEventSize,
1756                                                      CContextClient* contextClient, bool bufferForWriting /*= "false"*/)
1757   TRY
1758   {
1759     std::map<int, StdSize> dataSize;
1760
1761     // Find all reference domain and axis of all active fields
1762     std::vector<CFile*>& fileList = bufferForWriting ? this->enabledWriteModeFiles : this->enabledReadModeFiles;
1763     size_t numEnabledFiles = fileList.size();
1764     for (size_t i = 0; i < numEnabledFiles; ++i)
1765     {
1766       CFile* file = fileList[i];
1767       if (file->getContextClient() == contextClient)
1768       {
1769         std::vector<CField*> enabledFields = file->getEnabledFields();
1770         size_t numEnabledFields = enabledFields.size();
1771         for (size_t j = 0; j < numEnabledFields; ++j)
1772         {
1773           // const std::vector<std::map<int, StdSize> > mapSize = enabledFields[j]->getGridDataBufferSize(contextClient);
1774           const std::map<int, StdSize> mapSize = enabledFields[j]->getGridDataBufferSize(contextClient,bufferForWriting);
1775           std::map<int, StdSize>::const_iterator it = mapSize.begin(), itE = mapSize.end();
1776           for (; it != itE; ++it)
1777           {
1778             // If dataSize[it->first] does not exist, it will be zero-initialized
1779             // so we can use it safely without checking for its existance
1780                 if (CXios::isOptPerformance)
1781               dataSize[it->first] += it->second;
1782             else if (dataSize[it->first] < it->second)
1783               dataSize[it->first] = it->second;
1784
1785                 if (maxEventSize[it->first] < it->second)
1786               maxEventSize[it->first] = it->second;
1787           }
1788         }
1789       }
1790     }
1791     return dataSize;
1792   }
1793   CATCH_DUMP_ATTR
1794
1795   //! Client side: Send infomation of active files (files are enabled to write out)
1796   void CContext::sendEnabledFiles(const std::vector<CFile*>& activeFiles)
1797   TRY
1798   {
1799     int size = activeFiles.size();
1800
1801     // In a context, each type has a root definition, e.g: axis, domain, field.
1802     // Every object must be a child of one of these root definition. In this case
1803     // all new file objects created on server must be children of the root "file_definition"
1804     StdString fileDefRoot("file_definition");
1805     CFileGroup* cfgrpPtr = CFileGroup::get(fileDefRoot);
1806
1807     for (int i = 0; i < size; ++i)
1808     {
1809       CFile* f = activeFiles[i];
1810       cfgrpPtr->sendCreateChild(f->getId(),f->getContextClient());
1811       f->sendAllAttributesToServer(f->getContextClient());
1812       f->sendAddAllVariables(f->getContextClient());
1813     }
1814   }
1815   CATCH_DUMP_ATTR
1816
1817   //! Client side: Send information of active fields (ones are written onto files)
1818   void CContext::sendEnabledFieldsInFiles(const std::vector<CFile*>& activeFiles)
1819   TRY
1820   {
1821     int size = activeFiles.size();
1822     for (int i = 0; i < size; ++i)
1823     {
1824       activeFiles[i]->sendEnabledFields(activeFiles[i]->getContextClient());
1825     }
1826   }
1827   CATCH_DUMP_ATTR
1828
1829   //! Client side: Check if the defined axis, domains and grids are eligible for compressed indexed output
1830   void CContext::checkAxisDomainsGridsEligibilityForCompressedOutput()
1831   TRY
1832   {
1833     if (!hasClient) return;
1834
1835     const vector<CAxis*> allAxis = CAxis::getAll();
1836     for (vector<CAxis*>::const_iterator it = allAxis.begin(); it != allAxis.end(); it++)
1837       (*it)->checkEligibilityForCompressedOutput();
1838
1839     const vector<CDomain*> allDomains = CDomain::getAll();
1840     for (vector<CDomain*>::const_iterator it = allDomains.begin(); it != allDomains.end(); it++)
1841       (*it)->checkEligibilityForCompressedOutput();
1842
1843     const vector<CGrid*> allGrids = CGrid::getAll();
1844     for (vector<CGrid*>::const_iterator it = allGrids.begin(); it != allGrids.end(); it++)
1845       (*it)->checkEligibilityForCompressedOutput();
1846   }
1847   CATCH_DUMP_ATTR
1848
1849   //! Client side: Prepare the timeseries by adding the necessary files
1850   void CContext::prepareTimeseries()
1851   TRY
1852   {
1853     if (!hasClient) return;
1854
1855     const std::vector<CFile*> allFiles = CFile::getAll();
1856     for (size_t i = 0; i < allFiles.size(); i++)
1857     {
1858       CFile* file = allFiles[i];
1859
1860       std::vector<CVariable*> fileVars, fieldVars, vars = file->getAllVariables();
1861       for (size_t k = 0; k < vars.size(); k++)
1862       {
1863         CVariable* var = vars[k];
1864
1865         if (var->ts_target.isEmpty()
1866              || var->ts_target == CVariable::ts_target_attr::file || var->ts_target == CVariable::ts_target_attr::both)
1867           fileVars.push_back(var);
1868
1869         if (!var->ts_target.isEmpty()
1870              && (var->ts_target == CVariable::ts_target_attr::field || var->ts_target == CVariable::ts_target_attr::both))
1871           fieldVars.push_back(var);
1872       }
1873
1874       if (!file->timeseries.isEmpty() && file->timeseries != CFile::timeseries_attr::none)
1875       {
1876         StdString fileNameStr("%file_name%") ;
1877         StdString tsPrefix = !file->ts_prefix.isEmpty() ? file->ts_prefix : fileNameStr ;
1878         
1879         StdString fileName=file->getFileOutputName();
1880         size_t pos=tsPrefix.find(fileNameStr) ;
1881         while (pos!=std::string::npos)
1882         {
1883           tsPrefix=tsPrefix.replace(pos,fileNameStr.size(),fileName) ;
1884           pos=tsPrefix.find(fileNameStr) ;
1885         }
1886       
1887         const std::vector<CField*> allFields = file->getAllFields();
1888         for (size_t j = 0; j < allFields.size(); j++)
1889         {
1890           CField* field = allFields[j];
1891
1892           if (!field->ts_enabled.isEmpty() && field->ts_enabled)
1893           {
1894             CFile* tsFile = CFile::create();
1895             tsFile->duplicateAttributes(file);
1896
1897             // Add variables originating from file and targeted to timeserie file
1898             for (size_t k = 0; k < fileVars.size(); k++)
1899               tsFile->getVirtualVariableGroup()->addChild(fileVars[k]);
1900
1901           
1902             tsFile->name = tsPrefix + "_";
1903             if (!field->name.isEmpty())
1904               tsFile->name.get() += field->name;
1905             else if (field->hasDirectFieldReference()) // We cannot use getBaseFieldReference() just yet
1906               tsFile->name.get() += field->field_ref;
1907             else
1908               tsFile->name.get() += field->getId();
1909
1910             if (!field->ts_split_freq.isEmpty())
1911               tsFile->split_freq = field->ts_split_freq;
1912
1913             CField* tsField = tsFile->addField();
1914             tsField->field_ref = field->getId();
1915
1916             // Add variables originating from file and targeted to timeserie field
1917             for (size_t k = 0; k < fieldVars.size(); k++)
1918               tsField->getVirtualVariableGroup()->addChild(fieldVars[k]);
1919
1920             vars = field->getAllVariables();
1921             for (size_t k = 0; k < vars.size(); k++)
1922             {
1923               CVariable* var = vars[k];
1924
1925               // Add variables originating from field and targeted to timeserie field
1926               if (var->ts_target.isEmpty()
1927                    || var->ts_target == CVariable::ts_target_attr::field || var->ts_target == CVariable::ts_target_attr::both)
1928                 tsField->getVirtualVariableGroup()->addChild(var);
1929
1930               // Add variables originating from field and targeted to timeserie file
1931               if (!var->ts_target.isEmpty()
1932                    && (var->ts_target == CVariable::ts_target_attr::file || var->ts_target == CVariable::ts_target_attr::both))
1933                 tsFile->getVirtualVariableGroup()->addChild(var);
1934             }
1935
1936             tsFile->solveFieldRefInheritance(true);
1937
1938             if (file->timeseries == CFile::timeseries_attr::exclusive)
1939               field->enabled = false;
1940           }
1941         }
1942
1943         // Finally disable the original file is need be
1944         if (file->timeseries == CFile::timeseries_attr::only)
1945          file->enabled = false;
1946       }
1947     }
1948   }
1949   CATCH_DUMP_ATTR
1950
1951   //! Client side: Send information of reference grid of active fields
1952   void CContext::sendRefGrid(const std::vector<CFile*>& activeFiles)
1953   TRY
1954   {
1955     std::set<StdString> gridIds;
1956     int sizeFile = activeFiles.size();
1957     CFile* filePtr(NULL);
1958
1959     // Firstly, find all reference grids of all active fields
1960     for (int i = 0; i < sizeFile; ++i)
1961     {
1962       filePtr = activeFiles[i];
1963       std::vector<CField*> enabledFields = filePtr->getEnabledFields();
1964       int sizeField = enabledFields.size();
1965       for (int numField = 0; numField < sizeField; ++numField)
1966       {
1967         if (0 != enabledFields[numField]->getRelGrid())
1968           gridIds.insert(CGrid::get(enabledFields[numField]->getRelGrid())->getId());
1969       }
1970     }
1971
1972     // Create all reference grids on server side
1973     StdString gridDefRoot("grid_definition");
1974     CGridGroup* gridPtr = CGridGroup::get(gridDefRoot);
1975     std::set<StdString>::const_iterator it, itE = gridIds.end();
1976     for (it = gridIds.begin(); it != itE; ++it)
1977     {
1978       gridPtr->sendCreateChild(*it);
1979       CGrid::get(*it)->sendAllAttributesToServer();
1980       CGrid::get(*it)->sendAllDomains();
1981       CGrid::get(*it)->sendAllAxis();
1982       CGrid::get(*it)->sendAllScalars();
1983     }
1984   }
1985   CATCH_DUMP_ATTR
1986
1987   //! Client side: Send information of reference domain, axis and scalar of active fields
1988   void CContext::sendRefDomainsAxisScalars(const std::vector<CFile*>& activeFiles)
1989   TRY
1990   {
1991     std::set<StdString> domainIds, axisIds, scalarIds;
1992
1993     // Find all reference domain and axis of all active fields
1994     int numEnabledFiles = activeFiles.size();
1995     for (int i = 0; i < numEnabledFiles; ++i)
1996     {
1997       std::vector<CField*> enabledFields = activeFiles[i]->getEnabledFields();
1998       int numEnabledFields = enabledFields.size();
1999       for (int j = 0; j < numEnabledFields; ++j)
2000       {
2001         const std::vector<StdString>& prDomAxisScalarId = enabledFields[j]->getRefDomainAxisIds();
2002         if ("" != prDomAxisScalarId[0]) domainIds.insert(prDomAxisScalarId[0]);
2003         if ("" != prDomAxisScalarId[1]) axisIds.insert(prDomAxisScalarId[1]);
2004         if ("" != prDomAxisScalarId[2]) scalarIds.insert(prDomAxisScalarId[2]);
2005       }
2006     }
2007
2008     // Create all reference axis on server side
2009     std::set<StdString>::iterator itDom, itAxis, itScalar;
2010     std::set<StdString>::const_iterator itE;
2011
2012     StdString scalarDefRoot("scalar_definition");
2013     CScalarGroup* scalarPtr = CScalarGroup::get(scalarDefRoot);
2014     itE = scalarIds.end();
2015     for (itScalar = scalarIds.begin(); itScalar != itE; ++itScalar)
2016     {
2017       if (!itScalar->empty())
2018       {
2019         scalarPtr->sendCreateChild(*itScalar);
2020         CScalar::get(*itScalar)->sendAllAttributesToServer();
2021       }
2022     }
2023
2024     StdString axiDefRoot("axis_definition");
2025     CAxisGroup* axisPtr = CAxisGroup::get(axiDefRoot);
2026     itE = axisIds.end();
2027     for (itAxis = axisIds.begin(); itAxis != itE; ++itAxis)
2028     {
2029       if (!itAxis->empty())
2030       {
2031         axisPtr->sendCreateChild(*itAxis);
2032         CAxis::get(*itAxis)->sendAllAttributesToServer();
2033       }
2034     }
2035
2036     // Create all reference domains on server side
2037     StdString domDefRoot("domain_definition");
2038     CDomainGroup* domPtr = CDomainGroup::get(domDefRoot);
2039     itE = domainIds.end();
2040     for (itDom = domainIds.begin(); itDom != itE; ++itDom)
2041     {
2042       if (!itDom->empty()) {
2043          domPtr->sendCreateChild(*itDom);
2044          CDomain::get(*itDom)->sendAllAttributesToServer();
2045       }
2046     }
2047   }
2048   CATCH_DUMP_ATTR
2049
2050   //! Update calendar in each time step
2051   void CContext::updateCalendar(int step)
2052   TRY
2053   {
2054      int prevStep = calendar->getStep();
2055
2056      if (prevStep < step)
2057      {
2058        if (hasClient && !hasServer) // For now we only use server level 1 to read data
2059        {
2060          doPreTimestepOperationsForEnabledReadModeFiles();
2061        }
2062
2063        info(50) << "updateCalendar : before : " << calendar->getCurrentDate() << endl;
2064        calendar->update(step);
2065        info(50) << "updateCalendar : after : " << calendar->getCurrentDate() << endl;
2066  #ifdef XIOS_MEMTRACK_LIGHT
2067        info(50) << " Current memory used by XIOS : "<<  MemTrack::getCurrentMemorySize()*1.0/(1024*1024)<<" Mbyte, at timestep "<<step<<" of context "<<this->getId()<<endl ;
2068  #endif
2069
2070        if (hasClient && !hasServer) // For now we only use server level 1 to read data
2071        {
2072          doPostTimestepOperationsForEnabledReadModeFiles();
2073          garbageCollector.invalidate(calendar->getCurrentDate());
2074        }
2075      }
2076      else if (prevStep == step)
2077        info(50) << "updateCalendar: already at step " << step << ", no operation done." << endl;
2078      else // if (prevStep > step)
2079        ERROR("void CContext::updateCalendar(int step)",
2080              << "Illegal calendar update: previous step was " << prevStep << ", new step " << step << "is in the past!")
2081   }
2082   CATCH_DUMP_ATTR
2083
2084   void CContext::initReadFiles(void)
2085   TRY
2086   {
2087      vector<CFile*>::const_iterator it;
2088
2089      for (it=enabledReadModeFiles.begin(); it != enabledReadModeFiles.end(); it++)
2090      {
2091         (*it)->initRead();
2092      }
2093   }
2094   CATCH_DUMP_ATTR
2095
2096   //! Server side: Create header of netcdf file
2097   void CContext::createFileHeader(void)
2098   TRY
2099   {
2100      vector<CFile*>::const_iterator it;
2101
2102      for (it=enabledFiles.begin(); it != enabledFiles.end(); it++)
2103      // for (it=enabledWriteModeFiles.begin(); it != enabledWriteModeFiles.end(); it++)
2104      {
2105         (*it)->initWrite();
2106      }
2107   }
2108   CATCH_DUMP_ATTR
2109
2110   //! Get current context
2111   CContext* CContext::getCurrent(void)
2112   TRY
2113   {
2114     return CObjectFactory::GetObject<CContext>(CObjectFactory::GetCurrentContextId()).get();
2115   }
2116   CATCH
2117
2118   /*!
2119   \brief Set context with an id be the current context
2120   \param [in] id identity of context to be set to current
2121   */
2122   void CContext::setCurrent(const string& id)
2123   TRY
2124   {
2125     CObjectFactory::SetCurrentContextId(id);
2126     CGroupFactory::SetCurrentContextId(id);
2127   }
2128   CATCH
2129
2130  /*!
2131  \brief Create a context with specific id
2132  \param [in] id identity of new context
2133  \return pointer to the new context or already-existed one with identity id
2134  */
2135  CContext* CContext::create(const StdString& id)
2136  TRY
2137  {
2138    CContext::setCurrent(id);
2139
2140    bool hasctxt = CContext::has(id);
2141    CContext* context = CObjectFactory::CreateObject<CContext>(id).get();
2142    getRoot();
2143    if (!hasctxt) CGroupFactory::AddChild(root, context->getShared());
2144
2145#define DECLARE_NODE(Name_, name_) \
2146    C##Name_##Definition::create(C##Name_##Definition::GetDefName());
2147#define DECLARE_NODE_PAR(Name_, name_)
2148#include "node_type.conf"
2149
2150    return (context);
2151  }
2152  CATCH
2153
2154     //! Server side: Receive a message to do some post processing
2155  void CContext::recvRegistry(CEventServer& event)
2156  TRY
2157  {
2158    CBufferIn* buffer=event.subEvents.begin()->buffer;
2159    string id;
2160    *buffer>>id;
2161    get(id)->recvRegistry(*buffer);
2162  }
2163  CATCH
2164
2165  void CContext::recvRegistry(CBufferIn& buffer)
2166  TRY
2167  {
2168    if (server->intraCommRank==0)
2169    {
2170      CRegistry registry(server->intraComm) ;
2171      registry.fromBuffer(buffer) ;
2172      registryOut->mergeRegistry(registry) ;
2173    }
2174  }
2175  CATCH_DUMP_ATTR
2176
2177  void CContext::sendRegistry(void)
2178  TRY
2179  {
2180    registryOut->hierarchicalGatherRegistry() ;
2181
2182    // Use correct context client to send message
2183    int nbSrvPools = (this->hasServer) ? (this->hasClient ? this->clientPrimServer.size() : 0) : 1;
2184    for (int i = 0; i < nbSrvPools; ++i)
2185    {
2186      CContextClient* contextClientTmp = (hasServer) ? clientPrimServer[i] : client;
2187      CEventClient event(CContext::GetType(), CContext::EVENT_ID_SEND_REGISTRY);
2188        if (contextClientTmp->isServerLeader())
2189        {
2190           CMessage msg ;
2191           if (hasServer)
2192             msg<<this->getIdServer(i);
2193           else
2194             msg<<this->getIdServer();
2195           if (contextClientTmp->clientRank==0) msg<<*registryOut ;
2196           const std::list<int>& ranks = contextClientTmp->getRanksServerLeader();
2197           for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
2198             event.push(*itRank,1,msg);
2199           contextClientTmp->sendEvent(event);
2200         }
2201         else contextClientTmp->sendEvent(event);
2202    }
2203  }
2204  CATCH_DUMP_ATTR
2205
2206 
2207  void CContext::sendFinalizeClient(CContextClient* contextClient, const string& contextClientId)
2208  TRY
2209  {
2210    CEventClient event(getType(),EVENT_ID_CONTEXT_FINALIZE_CLIENT);
2211    if (contextClient->isServerLeader())
2212    {
2213      CMessage msg;
2214      msg<<contextClientId ;
2215      const std::list<int>& ranks = contextClient->getRanksServerLeader();
2216      for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
2217           event.push(*itRank,1,msg);
2218      contextClient->sendEvent(event);
2219    }
2220    else contextClient->sendEvent(event);
2221  }
2222  CATCH_DUMP_ATTR
2223
2224 
2225  void CContext::recvFinalizeClient(CEventServer& event)
2226  TRY
2227  {
2228    CBufferIn* buffer=event.subEvents.begin()->buffer;
2229    string id;
2230    *buffer>>id;
2231    get(id)->recvFinalizeClient(*buffer);
2232  }
2233  CATCH
2234
2235  void CContext::recvFinalizeClient(CBufferIn& buffer)
2236  TRY
2237  {
2238    countChildContextFinalized_++ ;
2239  }
2240  CATCH_DUMP_ATTR
2241
2242
2243
2244
2245  /*!
2246  * \fn bool CContext::isFinalized(void)
2247  * Context is finalized if it received context post finalize event.
2248  */
2249  bool CContext::isFinalized(void)
2250  TRY
2251  {
2252    return finalized;
2253  }
2254  CATCH_DUMP_ATTR
2255  ///--------------------------------------------------------------
2256  StdString CContext::dumpClassAttributes(void)
2257  {
2258    StdString str;
2259    str.append("enabled files=\"");
2260    int size = this->enabledFiles.size();
2261    for (int i = 0; i < size; ++i)
2262    {
2263      str.append(enabledFiles[i]->getId());
2264      str.append(" ");
2265    }
2266    str.append("\"");
2267    return str;
2268  }
2269
2270} // namespace xios
Note: See TracBrowser for help on using the repository browser.