2013-12-10 22:44:40 +01:00
/////////////////////////////////////////////////////////////////////////////////
//
2014-09-24 07:14:52 +02:00
// Copyright (C) Statoil ASA
// Copyright (C) Ceetron Solutions AS
2013-12-10 22:44:40 +01:00
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RigNNCData.h"
#include "RigMainGrid.h"
2013-12-11 14:55:14 +01:00
#include "cvfGeometryTools.h"
2013-12-10 22:44:40 +01:00
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RigNNCData :: RigNNCData ()
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RigNNCData :: processConnections ( const RigMainGrid & mainGrid )
{
2013-12-19 10:50:08 +01:00
//cvf::Trace::show("NNC: Total number: " + cvf::String((int)m_connections.size()));
2013-12-11 14:55:14 +01:00
for ( size_t cnIdx = 0 ; cnIdx < m_connections . size (); ++ cnIdx )
2013-12-10 22:44:40 +01:00
{
2015-11-24 14:21:02 +01:00
const RigCell & c1 = mainGrid . globalCellArray ()[ m_connections [ cnIdx ]. m_c1GlobIdx ];
const RigCell & c2 = mainGrid . globalCellArray ()[ m_connections [ cnIdx ]. m_c2GlobIdx ];
2013-12-10 22:44:40 +01:00
2017-11-02 09:31:09 +01:00
bool foundAnyOverlap = false ;
std :: vector < size_t > connectionPolygon ;
std :: vector < cvf :: Vec3d > connectionIntersections ;
cvf :: StructGridInterface :: FaceType connectionFace = cvf :: StructGridInterface :: NO_FACE ;
connectionFace = calculateCellFaceOverlap ( c1 , c2 , mainGrid , & connectionPolygon , & connectionIntersections );
2013-12-11 14:55:14 +01:00
2017-11-02 09:31:09 +01:00
if ( connectionFace != cvf :: StructGridInterface :: NO_FACE )
{
foundAnyOverlap = true ;
// Found an overlap polygon. Store data about connection
m_connections [ cnIdx ]. m_c1Face = connectionFace ;
for ( size_t pIdx = 0 ; pIdx < connectionPolygon . size (); ++ pIdx )
{
if ( connectionPolygon [ pIdx ] < mainGrid . nodes (). size ())
m_connections [ cnIdx ]. m_polygon . push_back ( mainGrid . nodes ()[ connectionPolygon [ pIdx ]]);
else
m_connections [ cnIdx ]. m_polygon . push_back ( connectionIntersections [ connectionPolygon [ pIdx ] - mainGrid . nodes (). size ()]);
}
2013-12-10 22:44:40 +01:00
2017-11-02 09:31:09 +01:00
// Add to search map, possibly not needed
//m_cellIdxToFaceToConnectionIdxMap[m_connections[cnIdx].m_c1GlobIdx][connectionFace].push_back(cnIdx);
//m_cellIdxToFaceToConnectionIdxMap[m_connections[cnIdx].m_c2GlobIdx][cvf::StructGridInterface::oppositeFace(connectionFace].push_back(cnIdx);
}
else
2013-12-10 22:44:40 +01:00
{
2017-11-02 09:31:09 +01:00
//cvf::Trace::show("NNC: No overlap found for : C1: " + cvf::String((int)m_connections[cnIdx].m_c1GlobIdx) + "C2: " + cvf::String((int)m_connections[cnIdx].m_c2GlobIdx));
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
cvf :: StructGridInterface :: FaceType RigNNCData :: calculateCellFaceOverlap ( const RigCell & c1 ,
const RigCell & c2 ,
const RigMainGrid & mainGrid ,
std :: vector < size_t >* connectionPolygon ,
std :: vector < cvf :: Vec3d >* connectionIntersections )
{
// Try to find the shared face
bool isPossibleNeighborInDirection [ 6 ] = { true , true , true , true , true , true };
if ( c1 . hostGrid () == c2 . hostGrid () )
{
char hasNeighbourInAnyDirection = 0 ;
size_t i1 , j1 , k1 ;
c1 . hostGrid () -> ijkFromCellIndex ( c1 . gridLocalCellIndex (), & i1 , & j1 , & k1 );
size_t i2 , j2 , k2 ;
c2 . hostGrid () -> ijkFromCellIndex ( c2 . gridLocalCellIndex (), & i2 , & j2 , & k2 );
isPossibleNeighborInDirection [ cvf :: StructGridInterface :: POS_I ] = (( i1 + 1 ) == i2 );
isPossibleNeighborInDirection [ cvf :: StructGridInterface :: NEG_I ] = (( i2 + 1 ) == i1 );
isPossibleNeighborInDirection [ cvf :: StructGridInterface :: POS_J ] = (( j1 + 1 ) == j2 );
isPossibleNeighborInDirection [ cvf :: StructGridInterface :: NEG_J ] = (( j2 + 1 ) == j1 );
isPossibleNeighborInDirection [ cvf :: StructGridInterface :: POS_K ] = (( k1 + 1 ) == k2 );
isPossibleNeighborInDirection [ cvf :: StructGridInterface :: NEG_K ] = (( k2 + 1 ) == k1 );
hasNeighbourInAnyDirection =
isPossibleNeighborInDirection [ cvf :: StructGridInterface :: POS_I ]
2013-12-10 22:44:40 +01:00
+ isPossibleNeighborInDirection [ cvf :: StructGridInterface :: NEG_I ]
+ isPossibleNeighborInDirection [ cvf :: StructGridInterface :: POS_J ]
+ isPossibleNeighborInDirection [ cvf :: StructGridInterface :: NEG_J ]
+ isPossibleNeighborInDirection [ cvf :: StructGridInterface :: POS_K ]
+ isPossibleNeighborInDirection [ cvf :: StructGridInterface :: NEG_K ];
2017-11-02 09:31:09 +01:00
// If cell 2 is not adjancent with respect to any of the six ijk directions,
// assume that we have no overlapping area.
2013-12-10 22:44:40 +01:00
2017-11-02 09:31:09 +01:00
if ( ! hasNeighbourInAnyDirection )
{
// Add to search map
//m_cellIdxToFaceToConnectionIdxMap[m_connections[cnIdx].m_c1GlobIdx][cvf::StructGridInterface::NO_FACE].push_back(cnIdx);
//m_cellIdxToFaceToConnectionIdxMap[m_connections[cnIdx].m_c2GlobIdx][cvf::StructGridInterface::NO_FACE].push_back(cnIdx);
2013-12-11 14:55:14 +01:00
2017-11-02 09:31:09 +01:00
//cvf::Trace::show("NNC: No direct neighbors : C1: " + cvf::String((int)m_connections[cnIdx].m_c1GlobIdx) + " C2: " + cvf::String((int)m_connections[cnIdx].m_c2GlobIdx));
return cvf :: StructGridInterface :: NO_FACE ;
2013-12-11 14:55:14 +01:00
}
2017-11-02 09:31:09 +01:00
}
2013-12-11 14:55:14 +01:00
2017-11-02 09:31:09 +01:00
#if 0
// Possibly do some testing to avoid unneccesary overlap calculations
cvf::Vec3d normal;
for ( char fIdx = 0; fIdx < 6; ++fIdx )
{
if ( isPossibleNeighborInDirection[fIdx] )
2013-12-11 14:55:14 +01:00
{
2017-11-02 09:31:09 +01:00
cvf::Vec3d fc1 = c1.faceCenter((cvf::StructGridInterface::FaceType)(fIdx));
cvf::Vec3d fc2 = c2.faceCenter(cvf::StructGridInterface::oppositeFace((cvf::StructGridInterface::FaceType)(fIdx)));
cvf::Vec3d fc1ToFc2 = fc2 - fc1;
normal = c1.faceNormalWithAreaLenght((cvf::StructGridInterface::FaceType)(fIdx));
normal.normalize();
// Check that face centers are approx in the face plane
if ( normal.dot(fc1ToFc2) < 0.01*fc1ToFc2.length() )
2013-12-10 22:44:40 +01:00
{
2017-11-02 09:31:09 +01:00
2013-12-11 14:55:14 +01:00
}
}
2017-11-02 09:31:09 +01:00
}
#endif
2013-12-10 22:44:40 +01:00
2013-12-16 14:25:27 +01:00
2018-02-23 22:38:46 +01:00
for ( unsigned char fIdx = 0 ; fIdx < 6 ; ++ fIdx )
2017-11-02 09:31:09 +01:00
{
if ( ! isPossibleNeighborInDirection [ fIdx ] )
2013-12-11 14:55:14 +01:00
{
2017-11-02 09:31:09 +01:00
continue ;
2013-12-10 22:44:40 +01:00
}
2013-12-16 14:25:27 +01:00
2017-11-02 09:31:09 +01:00
// Calculate connection polygon
std :: vector < size_t > polygon ;
std :: vector < cvf :: Vec3d > intersections ;
2018-08-07 10:37:52 +02:00
std :: array < size_t , 4 > face1 ;
std :: array < size_t , 4 > face2 ;
2017-11-02 09:31:09 +01:00
c1 . faceIndices (( cvf :: StructGridInterface :: FaceType )( fIdx ), & face1 );
c2 . faceIndices ( cvf :: StructGridInterface :: oppositeFace (( cvf :: StructGridInterface :: FaceType )( fIdx )), & face2 );
bool foundOverlap = cvf :: GeometryTools :: calculateOverlapPolygonOfTwoQuads (
& polygon ,
& intersections ,
2018-02-18 18:56:43 +01:00
( cvf :: EdgeIntersectStorage < size_t >* ) nullptr ,
2017-11-02 09:31:09 +01:00
cvf :: wrapArrayConst ( & mainGrid . nodes ()),
face1 . data (),
face2 . data (),
1e-6 );
if ( foundOverlap )
2013-12-16 14:25:27 +01:00
{
2017-11-02 09:31:09 +01:00
if ( connectionPolygon )( * connectionPolygon ) = polygon ;
if ( connectionIntersections ) ( * connectionIntersections ) = intersections ;
return ( cvf :: StructGridInterface :: FaceType )( fIdx );
2013-12-16 14:25:27 +01:00
}
2013-12-11 14:55:14 +01:00
}
2017-11-02 09:31:09 +01:00
return cvf :: StructGridInterface :: NO_FACE ;
2013-12-11 14:55:14 +01:00
}
2014-09-04 09:28:39 +02:00
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
2017-06-29 11:19:07 +02:00
std :: vector < double >& RigNNCData :: makeStaticConnectionScalarResult ( QString nncDataType )
2014-09-04 09:28:39 +02:00
{
2017-06-26 10:25:08 +02:00
std :: vector < std :: vector < double > >& results = m_connectionResults [ nncDataType ];
results . resize ( 1 );
results [ 0 ]. resize ( m_connections . size (), HUGE_VAL );
return results [ 0 ];
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
const std :: vector < double >* RigNNCData :: staticConnectionScalarResult ( size_t scalarResultIndex ) const
{
2017-06-29 11:19:07 +02:00
QString nncDataType = getNNCDataTypeFromScalarResultIndex ( scalarResultIndex );
if ( nncDataType . isNull ()) return nullptr ;
2017-06-26 10:25:08 +02:00
2017-06-29 11:19:07 +02:00
std :: map < QString , std :: vector < std :: vector < double > > >:: const_iterator it = m_connectionResults . find ( nncDataType );
if ( it != m_connectionResults . end ())
{
CVF_ASSERT ( it -> second . size () == 1 );
return & ( it -> second [ 0 ]);
}
else
{
return nullptr ;
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
const std :: vector < double >* RigNNCData :: staticConnectionScalarResultByName ( const QString & nncDataType ) const
{
std :: map < QString , std :: vector < std :: vector < double > > >:: const_iterator it = m_connectionResults . find ( nncDataType );
2017-06-26 10:25:08 +02:00
if ( it != m_connectionResults . end ())
{
2017-06-29 11:19:07 +02:00
CVF_ASSERT ( it -> second . size () == 1 );
2017-06-26 10:25:08 +02:00
return & ( it -> second [ 0 ]);
}
else
{
return nullptr ;
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
2017-06-29 11:19:07 +02:00
std :: vector < std :: vector < double > >& RigNNCData :: makeDynamicConnectionScalarResult ( QString nncDataType , size_t timeStepCount )
2017-06-26 10:25:08 +02:00
{
auto & results = m_connectionResults [ nncDataType ];
results . resize ( timeStepCount );
2014-09-04 09:28:39 +02:00
return results ;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
2017-06-26 10:25:08 +02:00
const std :: vector < std :: vector < double > >* RigNNCData :: dynamicConnectionScalarResult ( size_t scalarResultIndex ) const
2014-09-04 09:28:39 +02:00
{
2017-06-29 11:19:07 +02:00
QString nncDataType = getNNCDataTypeFromScalarResultIndex ( scalarResultIndex );
if ( nncDataType . isNull ()) return nullptr ;
2017-06-26 10:25:08 +02:00
2017-06-29 11:19:07 +02:00
auto it = m_connectionResults . find ( nncDataType );
2017-06-26 10:25:08 +02:00
2014-09-04 09:28:39 +02:00
if ( it != m_connectionResults . end ())
2017-06-26 10:25:08 +02:00
{
2014-09-04 09:28:39 +02:00
return & ( it -> second );
2017-06-26 10:25:08 +02:00
}
2014-09-04 09:28:39 +02:00
else
2017-06-26 10:25:08 +02:00
{
return nullptr ;
}
2014-09-04 09:28:39 +02:00
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
2017-06-26 10:25:08 +02:00
const std :: vector < double >* RigNNCData :: dynamicConnectionScalarResult ( size_t scalarResultIndex , size_t timeStep ) const
2014-09-04 09:28:39 +02:00
{
2017-06-29 11:19:07 +02:00
QString nncDataType = getNNCDataTypeFromScalarResultIndex ( scalarResultIndex );
if ( nncDataType . isNull ()) return nullptr ;
2017-06-26 10:25:08 +02:00
2017-06-29 11:19:07 +02:00
auto it = m_connectionResults . find ( nncDataType );
2017-06-26 10:25:08 +02:00
2014-09-24 13:28:08 +02:00
if ( it != m_connectionResults . end ())
{
2017-06-26 10:25:08 +02:00
if ( it -> second . size () > timeStep )
{
return & ( it -> second [ timeStep ]);
}
2014-09-24 13:28:08 +02:00
}
2017-06-26 10:25:08 +02:00
return nullptr ;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
2017-06-29 11:19:07 +02:00
const std :: vector < std :: vector < double >>* RigNNCData :: dynamicConnectionScalarResultByName ( const QString & nncDataType ) const
{
auto it = m_connectionResults . find ( nncDataType );
if ( it != m_connectionResults . end ())
{
return & ( it -> second );
}
return nullptr ;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
const std :: vector < double >* RigNNCData :: dynamicConnectionScalarResultByName ( const QString & nncDataType , size_t timeStep ) const
{
auto it = m_connectionResults . find ( nncDataType );
if ( it != m_connectionResults . end ())
{
if ( it -> second . size () > timeStep )
{
return & ( it -> second [ timeStep ]);
}
}
return nullptr ;
}
2017-08-08 13:12:43 +02:00
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std :: vector < std :: vector < double > >& RigNNCData :: makeGeneratedConnectionScalarResult ( QString nncDataType , size_t timeStepCount )
{
auto & results = m_connectionResults [ nncDataType ];
results . resize ( timeStepCount );
return results ;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
const std :: vector < std :: vector < double > >* RigNNCData :: generatedConnectionScalarResult ( size_t scalarResultIndex ) const
{
QString nncDataType = getNNCDataTypeFromScalarResultIndex ( scalarResultIndex );
if ( nncDataType . isNull ()) return nullptr ;
auto it = m_connectionResults . find ( nncDataType );
if ( it != m_connectionResults . end ())
{
return & ( it -> second );
}
else
{
return nullptr ;
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
const std :: vector < double >* RigNNCData :: generatedConnectionScalarResult ( size_t scalarResultIndex , size_t timeStep ) const
{
QString nncDataType = getNNCDataTypeFromScalarResultIndex ( scalarResultIndex );
if ( nncDataType . isNull ()) return nullptr ;
auto it = m_connectionResults . find ( nncDataType );
if ( it != m_connectionResults . end ())
{
if ( it -> second . size () > timeStep )
{
return & ( it -> second [ timeStep ]);
}
}
return nullptr ;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std :: vector < std :: vector < double > >* RigNNCData :: generatedConnectionScalarResult ( size_t scalarResultIndex )
{
QString nncDataType = getNNCDataTypeFromScalarResultIndex ( scalarResultIndex );
if ( nncDataType . isNull ()) return nullptr ;
auto it = m_connectionResults . find ( nncDataType );
if ( it != m_connectionResults . end ())
{
return & ( it -> second );
}
else
{
return nullptr ;
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std :: vector < double >* RigNNCData :: generatedConnectionScalarResult ( size_t scalarResultIndex , size_t timeStep )
{
QString nncDataType = getNNCDataTypeFromScalarResultIndex ( scalarResultIndex );
if ( nncDataType . isNull ()) return nullptr ;
auto it = m_connectionResults . find ( nncDataType );
if ( it != m_connectionResults . end ())
{
if ( it -> second . size () > timeStep )
{
return & ( it -> second [ timeStep ]);
}
}
return nullptr ;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
const std :: vector < std :: vector < double >>* RigNNCData :: generatedConnectionScalarResultByName ( const QString & nncDataType ) const
{
auto it = m_connectionResults . find ( nncDataType );
if ( it != m_connectionResults . end ())
{
return & ( it -> second );
}
return nullptr ;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
const std :: vector < double >* RigNNCData :: generatedConnectionScalarResultByName ( const QString & nncDataType , size_t timeStep ) const
{
auto it = m_connectionResults . find ( nncDataType );
if ( it != m_connectionResults . end ())
{
if ( it -> second . size () > timeStep )
{
return & ( it -> second [ timeStep ]);
}
}
return nullptr ;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std :: vector < std :: vector < double >>* RigNNCData :: generatedConnectionScalarResultByName ( const QString & nncDataType )
{
auto it = m_connectionResults . find ( nncDataType );
if ( it != m_connectionResults . end ())
{
return & ( it -> second );
}
return nullptr ;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std :: vector < double >* RigNNCData :: generatedConnectionScalarResultByName ( const QString & nncDataType , size_t timeStep )
{
auto it = m_connectionResults . find ( nncDataType );
if ( it != m_connectionResults . end ())
{
if ( it -> second . size () > timeStep )
{
return & ( it -> second [ timeStep ]);
}
}
return nullptr ;
}
2017-08-07 15:28:27 +02:00
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std :: vector < QString > RigNNCData :: availableProperties ( NNCResultType resultType ) const
{
std :: vector < QString > properties ;
for ( auto it : m_connectionResults )
{
2017-08-08 13:12:43 +02:00
if ( resultType == NNC_STATIC && it . second . size () == 1 && it . second [ 0 ]. size () > 0 && isNative ( it . first ))
2017-08-07 15:28:27 +02:00
{
properties . push_back ( it . first );
}
2017-08-08 13:12:43 +02:00
else if ( resultType == NNC_DYNAMIC && it . second . size () > 1 && it . second [ 0 ]. size () > 0 && isNative ( it . first ))
{
properties . push_back ( it . first );
}
else if ( resultType == NNC_GENERATED && ! isNative ( it . first ))
2017-08-07 15:28:27 +02:00
{
properties . push_back ( it . first );
}
}
return properties ;
}
2017-06-29 11:19:07 +02:00
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RigNNCData :: setScalarResultIndex ( const QString & nncDataType , size_t scalarResultIndex )
2017-06-26 10:25:08 +02:00
{
m_resultIndexToNNCDataType [ scalarResultIndex ] = nncDataType ;
2014-09-04 09:28:39 +02:00
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RigNNCData :: hasScalarValues ( size_t scalarResultIndex )
{
2017-06-29 11:19:07 +02:00
QString nncDataType = getNNCDataTypeFromScalarResultIndex ( scalarResultIndex );
if ( nncDataType . isNull ()) return false ;
2017-06-26 10:25:08 +02:00
2017-06-29 11:19:07 +02:00
auto it = m_connectionResults . find ( nncDataType );
2014-09-04 09:28:39 +02:00
return ( it != m_connectionResults . end ());
}
2017-06-26 10:25:08 +02:00
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
2017-06-29 11:19:07 +02:00
const QString RigNNCData :: getNNCDataTypeFromScalarResultIndex ( size_t scalarResultIndex ) const
2017-06-26 10:25:08 +02:00
{
auto it = m_resultIndexToNNCDataType . find ( scalarResultIndex );
if ( it != m_resultIndexToNNCDataType . end ())
{
2017-06-29 11:19:07 +02:00
return it -> second ;
2017-06-26 10:25:08 +02:00
}
2017-06-29 11:19:07 +02:00
return QString ();
2017-06-26 10:25:08 +02:00
}
2013-12-11 14:55:14 +01:00
//--------------------------------------------------------------------------------------------------
2017-08-08 13:12:43 +02:00
///
2013-12-11 14:55:14 +01:00
//--------------------------------------------------------------------------------------------------
2017-08-08 13:12:43 +02:00
bool RigNNCData :: isNative ( QString nncDataType ) const
2013-12-11 14:55:14 +01:00
{
2017-08-08 13:12:43 +02:00
if ( nncDataType == RigNNCData :: propertyNameCombTrans () ||
nncDataType == RigNNCData :: propertyNameFluxGas () ||
nncDataType == RigNNCData :: propertyNameFluxOil () ||
nncDataType == RigNNCData :: propertyNameFluxWat () ||
nncDataType == RigNNCData :: propertyNameRiCombMult () ||
nncDataType == RigNNCData :: propertyNameRiCombTrans () ||
nncDataType == RigNNCData :: propertyNameRiCombTransByArea ())
2013-12-11 14:55:14 +01:00
{
2017-08-08 13:12:43 +02:00
return true ;
2013-12-11 14:55:14 +01:00
}
2017-08-08 13:12:43 +02:00
return false ;
2013-12-10 22:44:40 +01:00
}