Merge pull request #888 from joakim-hove/group-names

Add method Schedule::groupNames()
This commit is contained in:
Joakim Hove 2019-07-15 07:42:22 +02:00 committed by GitHub
commit ffba2b114b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 213 additions and 180 deletions

View File

@ -121,6 +121,11 @@ namespace Opm
std::vector<std::string> wellNames(size_t timeStep) const;
std::vector<std::string> wellNames() const;
std::vector<std::string> groupNames(const std::string& pattern, size_t timeStep) const;
std::vector<std::string> groupNames(size_t timeStep) const;
std::vector<std::string> groupNames(const std::string& pattern) const;
std::vector<std::string> groupNames() const;
void updateWell(std::shared_ptr<Well2> well, size_t reportStep);
const Well2& getWell2(const std::string& wellName, size_t timeStep) const;
const Well2& getWell2atEnd(const std::string& well_name) const;
@ -142,8 +147,7 @@ namespace Opm
size_t numGroups(size_t timeStep) const;
bool hasGroup(const std::string& groupName) const;
const Group& getGroup(const std::string& groupName) const;
std::vector< const Group* > getGroups() const;
std::vector< const Group* > getGroups(size_t timeStep) const;
Group& getGroup(const std::string& groupName);
const Tuning& getTuning() const;
const MessageLimits& getMessageLimits() const;
void invalidNamePattern (const std::string& namePattern, const ParseContext& parseContext, ErrorGuard& errors, const DeckKeyword& keyword) const;

View File

@ -73,8 +73,9 @@ namespace {
std::vector<Group> get_groups( const Schedule& sch ) {
std::vector< Group > groups;
for( const auto& g : sch.getGroups() )
groups.push_back( *g );
for( const auto& group_name : sch.groupNames())
groups.push_back( sch.getGroup(group_name) );
return groups;
}
@ -82,6 +83,11 @@ namespace {
return sch.hasWell( wellName );
}
const Group& get_group(const Schedule& sch, const std::string group_name) {
return sch.getGroup(group_name);
}
}
void sunbeam::export_Schedule(py::module& module) {
@ -94,7 +100,7 @@ void sunbeam::export_Schedule(py::module& module) {
.def( "_get_wells", &Schedule::getWells2)
.def("_getwell", &get_well)
.def( "__contains__", &has_well )
.def( "_group", &Schedule::getGroup, ref_internal)
.def( "_group", &get_group, ref_internal)
.def( "_group_tree", &get_grouptree, ref_internal);
}

View File

@ -91,58 +91,58 @@ namespace {
std::map <size_t, const Opm::Group*> currentGroupMapIndexGroup(const Opm::Schedule& sched, const size_t simStep, const std::vector<int>& inteHead)
{
const auto& groups = sched.getGroups(simStep);
// make group index for current report step
std::map <size_t, const Opm::Group*> indexGroupMap;
for (const auto* group : groups) {
int ind = (group->name() == "FIELD")
? ngmaxz(inteHead)-1 : group->seqIndex()-1;
const std::pair<size_t, const Opm::Group*> groupPair = std::make_pair(static_cast<size_t>(ind), group);
indexGroupMap.insert(groupPair);
}
return indexGroupMap;
// make group index for current report step
std::map <size_t, const Opm::Group*> indexGroupMap;
for (const auto& group_name : sched.groupNames(simStep)) {
const auto& group = sched.getGroup(group_name);
int ind = (group.name() == "FIELD")
? ngmaxz(inteHead)-1 : group.seqIndex()-1;
const std::pair<size_t, const Opm::Group*> groupPair = std::make_pair(static_cast<size_t>(ind), std::addressof(group));
indexGroupMap.insert(groupPair);
}
return indexGroupMap;
}
std::map <const std::string, size_t> currentGroupMapNameIndex(const Opm::Schedule& sched, const size_t simStep, const std::vector<int>& inteHead)
{
const auto& groups = sched.getGroups(simStep);
// make group name to index map for the current time step
std::map <const std::string, size_t> groupIndexMap;
for (const auto* group : groups) {
int ind = (group->name() == "FIELD")
? ngmaxz(inteHead)-1 : group->seqIndex()-1;
std::pair<const std::string, size_t> groupPair = std::make_pair(group->name(), ind);
groupIndexMap.insert(groupPair);
}
return groupIndexMap;
// make group name to index map for the current time step
std::map <const std::string, size_t> groupIndexMap;
for (const auto& group_name : sched.groupNames(simStep)) {
const auto& group = sched.getGroup(group_name);
int ind = (group.name() == "FIELD")
? ngmaxz(inteHead)-1 : group.seqIndex()-1;
std::pair<const std::string, size_t> groupPair = std::make_pair(group.name(), ind);
groupIndexMap.insert(groupPair);
}
return groupIndexMap;
}
int currentGroupLevel(const Opm::Schedule& sched, const Opm::Group& group, const size_t simStep)
{
int level = 0;
const std::vector< const Opm::Group* > groups = sched.getGroups(simStep);
const std::string& groupName = group.name();
if (!sched.hasGroup(groupName))
int level = 0;
const std::string& groupName = group.name();
if (!sched.hasGroup(groupName))
throw std::invalid_argument("No such group: " + groupName);
{
if (group.hasBeenDefined( simStep )) {
const auto& groupTree = sched.getGroupTree( simStep );
//find group level - field level is 0
std::string tstGrpName = groupName;
while (((tstGrpName.size())>0) && (!(tstGrpName=="FIELD"))) {
std::string curParent = groupTree.parent(tstGrpName);
level+=1;
tstGrpName = curParent;
}
return level;
}
else {
std::stringstream str;
str << "actual group has not been defined at report time: " << simStep;
throw std::invalid_argument(str.str());
}
}
return level;
//find group level - field level is 0
std::string tstGrpName = groupName;
while (((tstGrpName.size())>0) && (!(tstGrpName=="FIELD"))) {
std::string curParent = groupTree.parent(tstGrpName);
level+=1;
tstGrpName = curParent;
}
return level;
}
else {
std::stringstream str;
str << "actual group has not been defined at report time: " << simStep;
throw std::invalid_argument(str.str());
}
}
return level;
}

View File

@ -104,32 +104,32 @@ namespace {
};
}
std::map <const std::string, size_t> currentGroupMapNameIndex(const Opm::Schedule& sched, const size_t simStep, const std::vector<int>& inteHead)
{
const auto& groups = sched.getGroups(simStep);
// make group name to index map for the current time step
std::map <const std::string, size_t> groupIndexMap;
for (const auto* group : groups) {
int ind = (group->name() == "FIELD")
? inteHead[VI::intehead::NGMAXZ]-1 : group->seqIndex()-1;
std::pair<const std::string, size_t> groupPair = std::make_pair(group->name(), ind);
groupIndexMap.insert(groupPair);
}
return groupIndexMap;
std::map <const std::string, size_t> currentGroupMapNameIndex(const Opm::Schedule& sched, const size_t simStep, const std::vector<int>& inteHead)
{
// make group name to index map for the current time step
std::map <const std::string, size_t> groupIndexMap;
for (const auto& group_name : sched.groupNames(simStep)) {
const auto& group = sched.getGroup(group_name);
int ind = (group.name() == "FIELD")
? inteHead[VI::intehead::NGMAXZ]-1 : group.seqIndex()-1;
std::pair<const std::string, size_t> groupPair = std::make_pair(group.name(), ind);
groupIndexMap.insert(groupPair);
}
return groupIndexMap;
}
int groupIndex(const std::string& grpName,
const std::map <const std::string, size_t>& currentGroupMapNameIndex)
{
int ind = 0;
auto searchGTName = currentGroupMapNameIndex.find(grpName);
if (searchGTName != currentGroupMapNameIndex.end()) {
ind = searchGTName->second + 1;
}
else {
std::cout << "group Name: " << grpName << std::endl;
throw std::invalid_argument( "Invalid group name" );
}
int ind = 0;
auto searchGTName = currentGroupMapNameIndex.find(grpName);
if (searchGTName != currentGroupMapNameIndex.end()) {
ind = searchGTName->second + 1;
}
else {
std::cout << "group Name: " << grpName << std::endl;
throw std::invalid_argument( "Invalid group name" );
}
return ind;
}

View File

@ -1181,9 +1181,8 @@ namespace {
intehead, std::move(rst_view)
};
for (const auto* group : schedule.getGroups(sim_step)) {
const auto& gname = group->name();
for (const auto& gname : schedule.groupNames(sim_step)) {
const auto& group = schedule.getGroup(gname);
// Note: Order of group values in {I,X}GRP arrays mostly
// matches group's order of occurrence in .DATA file.
// Values pertaining to FIELD are stored at zero-based order
@ -1196,7 +1195,7 @@ namespace {
// proofing and robustness in case that ever changes.
const auto groupOrderIx = (gname == "FIELD")
? groupData.maxGroups() // NGMAXZ -- Item 3 of WELLDIMS
: std::max(group->seqIndex(), std::size_t{1}) - 1;
: std::max(group.seqIndex(), std::size_t{1}) - 1;
assign_group_cumulatives(gname, groupOrderIx, groupData, smry);
}

View File

@ -94,12 +94,9 @@ namespace {
entities.emplace_back("WWVIR", well_name);
}
for (const auto* grp : sched.getGroups()) {
const auto& grp_name = grp->name();
if (grp_name != "FIELD") {
for (const auto& grp_name : sched.groupNames()) {
if (grp_name != "FIELD")
makeEntities('G', grp_name);
}
}
makeEntities('F', "FIELD");

View File

@ -68,6 +68,15 @@
namespace Opm {
namespace {
bool name_match(const std::string& pattern, const std::string& name) {
int flags = 0;
return (fnmatch(pattern.c_str(), name.c_str(), flags) == 0);
}
}
Schedule::Schedule( const Deck& deck,
const EclipseGrid& grid,
const Eclipse3DProperties& eclipseProperties,
@ -1403,19 +1412,20 @@ namespace Opm {
void Schedule::handleGCONINJE( const SCHEDULESection& section, const DeckKeyword& keyword, size_t currentStep, const ParseContext& parseContext, ErrorGuard& errors) {
for( const auto& record : keyword ) {
const std::string& groupNamePattern = record.getItem("GROUP").getTrimmedString(0);
auto groups = getGroups ( groupNamePattern );
const auto group_names = this->groupNames(groupNamePattern);
if (groups.empty())
if (group_names.empty())
invalidNamePattern(groupNamePattern, parseContext, errors, keyword);
for (auto* group : groups){
for (const auto& group_name : group_names){
auto& group = this->getGroup(group_name);
{
Phase phase = get_phase( record.getItem("PHASE").getTrimmedString(0) );
group->setInjectionPhase( currentStep , phase );
group.setInjectionPhase( currentStep , phase );
}
{
GroupInjection::ControlEnum controlMode = GroupInjection::ControlEnumFromString( record.getItem("CONTROL_MODE").getTrimmedString(0) );
group->setInjectionControlMode( currentStep , controlMode );
group.setInjectionControlMode( currentStep , controlMode );
}
Phase wellPhase = get_phase( record.getItem("PHASE").getTrimmedString(0));
@ -1424,12 +1434,12 @@ namespace Opm {
surfaceInjectionRate = injection::rateToSI(surfaceInjectionRate, wellPhase, section.unitSystem());
double reservoirInjectionRate = record.getItem("RESV_TARGET").get<UDAValue>(0).get<double>();
group->setSurfaceMaxRate( currentStep , surfaceInjectionRate);
group->setReservoirMaxRate( currentStep , reservoirInjectionRate);
group->setTargetReinjectFraction( currentStep , record.getItem("REINJ_TARGET").get<UDAValue>(0).get<double>());
group->setTargetVoidReplacementFraction( currentStep , record.getItem("VOIDAGE_TARGET").get<UDAValue>(0).get<double>());
group.setSurfaceMaxRate( currentStep , surfaceInjectionRate);
group.setReservoirMaxRate( currentStep , reservoirInjectionRate);
group.setTargetReinjectFraction( currentStep , record.getItem("REINJ_TARGET").get<UDAValue>(0).get<double>());
group.setTargetVoidReplacementFraction( currentStep , record.getItem("VOIDAGE_TARGET").get<UDAValue>(0).get<double>());
group->setInjectionGroup(currentStep, true);
group.setInjectionGroup(currentStep, true);
}
}
}
@ -1437,27 +1447,28 @@ namespace Opm {
void Schedule::handleGCONPROD( const DeckKeyword& keyword, size_t currentStep, const ParseContext& parseContext, ErrorGuard& errors) {
for( const auto& record : keyword ) {
const std::string& groupNamePattern = record.getItem("GROUP").getTrimmedString(0);
auto groups = getGroups ( groupNamePattern );
const auto group_names = this->groupNames(groupNamePattern);
if (groups.empty())
if (group_names.empty())
invalidNamePattern(groupNamePattern, parseContext, errors, keyword);
for (auto* group : groups){
for (const auto& group_name : group_names){
auto& group = this->getGroup(group_name);
{
GroupProduction::ControlEnum controlMode = GroupProduction::ControlEnumFromString( record.getItem("CONTROL_MODE").getTrimmedString(0) );
group->setProductionControlMode( currentStep , controlMode );
group.setProductionControlMode( currentStep , controlMode );
}
group->setOilTargetRate( currentStep , record.getItem("OIL_TARGET").get<UDAValue>(0).get<double>());
group->setGasTargetRate( currentStep , record.getItem("GAS_TARGET").get<UDAValue>(0).get<double>());
group->setWaterTargetRate( currentStep , record.getItem("WATER_TARGET").get<UDAValue>(0).get<double>());
group->setLiquidTargetRate( currentStep , record.getItem("LIQUID_TARGET").get<UDAValue>(0).get<double>());
group->setReservoirVolumeTargetRate( currentStep , record.getItem("RESERVOIR_FLUID_TARGET").getSIDouble(0));
group.setOilTargetRate( currentStep , record.getItem("OIL_TARGET").get<UDAValue>(0).get<double>());
group.setGasTargetRate( currentStep , record.getItem("GAS_TARGET").get<UDAValue>(0).get<double>());
group.setWaterTargetRate( currentStep , record.getItem("WATER_TARGET").get<UDAValue>(0).get<double>());
group.setLiquidTargetRate( currentStep , record.getItem("LIQUID_TARGET").get<UDAValue>(0).get<double>());
group.setReservoirVolumeTargetRate( currentStep , record.getItem("RESERVOIR_FLUID_TARGET").getSIDouble(0));
{
GroupProductionExceedLimit::ActionEnum exceedAction = GroupProductionExceedLimit::ActionEnumFromString(record.getItem("EXCEED_PROC").getTrimmedString(0) );
group->setProductionExceedLimitAction( currentStep , exceedAction );
group.setProductionExceedLimitAction( currentStep , exceedAction );
}
group->setProductionGroup(currentStep, true);
group.setProductionGroup(currentStep, true);
}
}
}
@ -1466,17 +1477,18 @@ namespace Opm {
void Schedule::handleGEFAC( const DeckKeyword& keyword, size_t currentStep, const ParseContext& parseContext, ErrorGuard& errors) {
for( const auto& record : keyword ) {
const std::string& groupNamePattern = record.getItem("GROUP").getTrimmedString(0);
auto groups = getGroups ( groupNamePattern );
const auto group_names = this->groupNames(groupNamePattern);
if (groups.empty())
if (group_names.empty())
invalidNamePattern(groupNamePattern, parseContext, errors, keyword);
for (auto* group : groups){
group->setGroupEfficiencyFactor(currentStep, record.getItem("EFFICIENCY_FACTOR").get< double >(0));
for (const auto& group_name : group_names){
auto& group = this->getGroup(group_name);
const std::string& transfer_str = record.getItem("TRANSFER_EXT_NET").getTrimmedString(0);
bool transfer = (transfer_str == "YES") ? true : false;
group->setTransferGroupEfficiencyFactor(currentStep, transfer);
group.setGroupEfficiencyFactor(currentStep, record.getItem("EFFICIENCY_FACTOR").get< double >(0));
group.setTransferGroupEfficiencyFactor(currentStep, transfer);
}
}
}
@ -2028,10 +2040,9 @@ namespace Opm {
// Normal pattern matching
auto star_pos = pattern.find('*');
if (star_pos != std::string::npos) {
int flags = 0;
std::vector<std::string> names;
for (const auto& well_pair : this->wells_static) {
if (fnmatch(pattern.c_str(), well_pair.first.c_str(), flags) == 0) {
if (name_match(pattern, well_pair.first)) {
const auto& dynamic_state = well_pair.second;
if (dynamic_state.get(timeStep))
names.push_back(well_pair.first);
@ -2077,6 +2088,74 @@ namespace Opm {
return names;
}
std::vector<std::string> Schedule::groupNames(const std::string& pattern, size_t timeStep) const {
if (pattern.size() == 0)
return {};
// Normal pattern matching
auto star_pos = pattern.find('*');
if (star_pos != std::string::npos) {
std::vector<std::string> names;
for (const auto& group_pair : this->m_groups) {
if (name_match(pattern, group_pair.first)) {
const auto& group = group_pair.second;
if (group.hasBeenDefined(timeStep))
names.push_back(group_pair.first);
}
}
return names;
}
// Normal group name without any special characters
if (this->hasGroup(pattern)) {
const auto& group = this->m_groups.at(pattern);
if (group.hasBeenDefined(timeStep))
return { pattern };
}
return {};
}
std::vector<std::string> Schedule::groupNames(size_t timeStep) const {
std::vector<std::string> names;
for (const auto& group_pair : this->m_groups) {
const auto& group = group_pair.second;
if (group.hasBeenDefined(timeStep))
names.push_back( group.name() );
}
return names;
}
std::vector<std::string> Schedule::groupNames(const std::string& pattern) const {
if (pattern.size() == 0)
return {};
// Normal pattern matching
auto star_pos = pattern.find('*');
if (star_pos != std::string::npos) {
int flags = 0;
std::vector<std::string> names;
for (const auto& group_pair : this->m_groups) {
if (fnmatch(pattern.c_str(), group_pair.first.c_str(), flags) == 0)
names.push_back(group_pair.first);
}
return names;
}
// Normal group name without any special characters
if (this->hasGroup(pattern))
return { pattern };
return {};
}
std::vector<std::string> Schedule::groupNames() const {
std::vector<std::string> names;
for (const auto& group_pair : this->m_groups)
names.push_back(group_pair.first);
return names;
}
void Schedule::addGroup(const std::string& groupName, size_t timeStep) {
const size_t gseqIndex = m_groups.size();
@ -2087,15 +2166,16 @@ namespace Opm {
size_t Schedule::numGroups() const {
return m_groups.size();
}
size_t Schedule::numGroups(size_t timeStep) const {
return this->getGroups( timeStep ).size();
const auto group_names = this->groupNames(timeStep);
return group_names.size();
}
bool Schedule::hasGroup(const std::string& groupName) const {
return m_groups.count(groupName) > 0;
}
const Group& Schedule::getGroup(const std::string& groupName) const {
if (hasGroup(groupName)) {
return m_groups.at(groupName);
@ -2103,53 +2183,13 @@ namespace Opm {
throw std::invalid_argument("Group: " + groupName + " does not exist");
}
std::vector< const Group* > Schedule::getGroups() const {
std::vector< const Group* > groups;
for( const auto& group : m_groups )
groups.push_back( std::addressof(group.second) );
return groups;
Group& Schedule::getGroup(const std::string& groupName) {
if (hasGroup(groupName)) {
return m_groups.at(groupName);
} else
throw std::invalid_argument("Group: " + groupName + " does not exist");
}
std::vector< Group* > Schedule::getGroups(const std::string& groupNamePattern) {
size_t wildcard_pos = groupNamePattern.find("*");
if( wildcard_pos != groupNamePattern.length()-1 ) {
if( m_groups.count( groupNamePattern ) == 0) return {};
return { std::addressof( m_groups.get( groupNamePattern ) ) };
}
std::vector< Group* > groups;
for( auto& group_pair : this->m_groups ) {
auto& group = group_pair.second;
if( Group::groupNameInGroupNamePattern( group.name(), groupNamePattern ) ) {
groups.push_back( std::addressof( group ) );
}
}
return groups;
}
std::vector< const Group* > Schedule::getGroups(size_t timeStep) const {
if (timeStep >= m_timeMap.size()) {
throw std::invalid_argument("Timestep to large");
}
auto defined = [=]( const Group& g ) {
return g.hasBeenDefined( timeStep );
};
std::vector< const Group* > groups;
for( const auto& group_pair : m_groups ) {
const auto& group = group_pair.second;
if( !defined( group) ) continue;
groups.push_back( &group );
}
return groups;
}
void Schedule::addWellToGroup( Group& newGroup, const std::string& wellName , size_t timeStep) {
auto& dynamic_state = this->wells_static.at(wellName);

View File

@ -198,9 +198,9 @@ inline void keywordG( SummaryConfig::keyword_list& list,
if( keyword.size() == 0 ||
!keyword.getDataRecord().getDataItem().hasValue( 0 ) ) {
for( const auto& group : schedule.getGroups() ) {
if( group->name() == "FIELD" ) continue;
list.push_back( SummaryConfig::keyword_type(keyword.name(), group->name() ));
for( const auto& group : schedule.groupNames() ) {
if( group == "FIELD" ) continue;
list.push_back( SummaryConfig::keyword_type(keyword.name(), group ));
}
return;
}

View File

@ -279,6 +279,10 @@ BOOST_AUTO_TEST_CASE(createDeckWithGEFAC) {
Runspec runspec (deck );
Opm::Schedule schedule(deck, grid, eclipseProperties, runspec);
auto group_names = schedule.groupNames("PRODUC");
BOOST_CHECK_EQUAL(group_names.size(), 1);
BOOST_CHECK_EQUAL(group_names[0], "PRODUC");
const auto& group1 = schedule.getGroup("PRODUC");
BOOST_CHECK_EQUAL(group1.getGroupEfficiencyFactor(0), 0.85);
BOOST_CHECK(group1.getTransferGroupEfficiencyFactor(0));

View File

@ -377,11 +377,11 @@ BOOST_AUTO_TEST_CASE(CreateScheduleDeckWellsOrdered) {
BOOST_CHECK_EQUAL( "BW_2" , well_names[1]);
BOOST_CHECK_EQUAL( "AW_3" , well_names[2]);
auto groups = schedule.getGroups();
// groups[0] is 'FIELD'
BOOST_CHECK_EQUAL( "CG", groups[1]->name());
BOOST_CHECK_EQUAL( "BG", groups[2]->name());
BOOST_CHECK_EQUAL( "AG", groups[3]->name());
auto group_names = schedule.groupNames();
BOOST_CHECK_EQUAL( "FIELD", group_names[0]);
BOOST_CHECK_EQUAL( "CG", group_names[1]);
BOOST_CHECK_EQUAL( "BG", group_names[2]);
BOOST_CHECK_EQUAL( "AG", group_names[3]);
}
@ -437,6 +437,10 @@ BOOST_AUTO_TEST_CASE(CreateScheduleDeckWellsOrderedGRUPTREE) {
BOOST_CHECK( has_well( parent_wells2, "BW_2" ));
BOOST_CHECK( has_well( parent_wells2, "AW_3" ));
}
auto group_names = schedule.groupNames("P*", 0);
BOOST_CHECK( std::find(group_names.begin(), group_names.end(), "PG1") != group_names.end() );
BOOST_CHECK( std::find(group_names.begin(), group_names.end(), "PG2") != group_names.end() );
BOOST_CHECK( std::find(group_names.begin(), group_names.end(), "PLATFORM") != group_names.end() );
}
@ -514,27 +518,6 @@ BOOST_AUTO_TEST_CASE(CreateSchedule_DeckWithGRUPTREE_HasRootGroupTreeNodeForTime
BOOST_CHECK_EQUAL( "FAREN", schedule.getGroupTree( 0 ).parent( "BARNET" ) );
}
BOOST_AUTO_TEST_CASE(GetGroups) {
auto deck = deckWithGRUPTREE();
EclipseGrid grid(10,10,10);
TableManager table ( deck );
Eclipse3DProperties eclipseProperties ( deck , table, grid);
Runspec runspec (deck);
Schedule schedule(deck , grid , eclipseProperties, runspec);
auto groups = schedule.getGroups();
BOOST_CHECK_EQUAL( 3, groups.size() );
std::vector< std::string > names;
for( const auto group : groups ) names.push_back( group->name() );
std::sort( names.begin(), names.end() );
BOOST_CHECK_EQUAL( "BARNET", names[ 0 ] );
BOOST_CHECK_EQUAL( "FAREN", names[ 1 ] );
BOOST_CHECK_EQUAL( "FIELD", names[ 2 ] );
}
BOOST_AUTO_TEST_CASE(EmptyScheduleHasFIELDGroup) {
EclipseGrid grid(10,10,10);
auto deck = createDeck();