mirror of
https://github.com/OPM/opm-simulators.git
synced 2025-02-25 18:55:30 -06:00
move time iterations to Simulator class and pass deck to create polymer inflows.
This should solve the issues: write the final state to eclipse binaries.
This commit is contained in:
parent
5535dd99cc
commit
5242d6bbf7
@ -198,9 +198,6 @@ try
|
|||||||
|
|
||||||
// initialize variables
|
// initialize variables
|
||||||
simtimer.init(timeMap);
|
simtimer.init(timeMap);
|
||||||
//Check for WPOLYMER presence in last report step to decide
|
|
||||||
//polymer injection control type.
|
|
||||||
std::cout << polymer << " " << use_wpolymer << std::endl;
|
|
||||||
if (polymer){
|
if (polymer){
|
||||||
if (!use_wpolymer) {
|
if (!use_wpolymer) {
|
||||||
OPM_MESSAGE("Warning: simulate polymer injection without WPOLYMER.");
|
OPM_MESSAGE("Warning: simulate polymer injection without WPOLYMER.");
|
||||||
@ -218,61 +215,27 @@ try
|
|||||||
std::cout << "\n\n================ Starting main simulation loop ===============\n"
|
std::cout << "\n\n================ Starting main simulation loop ===============\n"
|
||||||
<< std::flush;
|
<< std::flush;
|
||||||
SimulatorReport fullReport;
|
SimulatorReport fullReport;
|
||||||
WellStateFullyImplicitBlackoil prev_well_state;
|
Opm::DerivedGeology geology(*grid->c_grid(), *new_props, eclipseState, grav);
|
||||||
for (size_t reportStepIdx = 0; reportStepIdx < timeMap->numTimesteps(); ++reportStepIdx) {
|
|
||||||
simtimer.setCurrentStepNum(reportStepIdx);
|
|
||||||
Opm::DerivedGeology geology(*grid->c_grid(), *new_props, eclipseState, grav);
|
|
||||||
|
|
||||||
std::vector<double> threshold_pressures = thresholdPressures(deck, eclipseState, *grid->c_grid());
|
std::vector<double> threshold_pressures = thresholdPressures(deck, eclipseState, *grid->c_grid());
|
||||||
//Create new wells, polymer inflow controls.
|
SimulatorFullyImplicitBlackoilPolymer<UnstructuredGrid> simulator(param,
|
||||||
WellsManager wells_manager(eclipseState,
|
*grid->c_grid(),
|
||||||
simtimer.currentStepNum(),
|
geology,
|
||||||
Opm::UgGridHelpers::numCells(*grid->c_grid()),
|
*new_props,
|
||||||
Opm::UgGridHelpers::globalCell(*grid->c_grid()),
|
polymer_props_ad,
|
||||||
Opm::UgGridHelpers::cartDims(*grid->c_grid()),
|
rock_comp->isActive() ? rock_comp.get() : 0,
|
||||||
Opm::UgGridHelpers::dimensions(*grid->c_grid()),
|
*fis_solver,
|
||||||
Opm::UgGridHelpers::beginCellCentroids(*grid->c_grid()),
|
grav,
|
||||||
Opm::UgGridHelpers::cell2Faces(*grid->c_grid()),
|
deck->hasKeyword("DISGAS"),
|
||||||
Opm::UgGridHelpers::beginFaceCentroids(*grid->c_grid()),
|
deck->hasKeyword("VAPOIL"),
|
||||||
props->permeability());
|
polymer,
|
||||||
WellStateFullyImplicitBlackoil well_state;
|
eclipseState,
|
||||||
well_state.init(wells_manager.c_wells(), state.blackoilState());
|
outputWriter,
|
||||||
if (reportStepIdx != 0) {
|
deck,
|
||||||
// Transfer previous well state to current.
|
threshold_pressures);
|
||||||
well_state.partialCopy(prev_well_state, *wells_manager.c_wells(), prev_well_state.numWells());
|
|
||||||
}
|
|
||||||
std::unique_ptr<PolymerInflowInterface> polymer_inflow;
|
|
||||||
if (use_wpolymer) {
|
|
||||||
if (wells_manager.c_wells() == 0) {
|
|
||||||
OPM_THROW(std::runtime_error, "Cannot control polymer injection via WPOLYMER without wells.");
|
|
||||||
}
|
|
||||||
polymer_inflow.reset(new PolymerInflowFromDeck(deck, *wells_manager.c_wells(), props->numCells()));
|
|
||||||
} else {
|
|
||||||
polymer_inflow.reset(new PolymerInflowBasic(0.0*Opm::unit::day,
|
|
||||||
1.0*Opm::unit::day,
|
|
||||||
0.0));
|
|
||||||
}
|
|
||||||
SimulatorFullyImplicitBlackoilPolymer<UnstructuredGrid> simulator(param,
|
|
||||||
*grid->c_grid(),
|
|
||||||
geology,
|
|
||||||
*new_props,
|
|
||||||
polymer_props_ad,
|
|
||||||
rock_comp->isActive() ? rock_comp.get() : 0,
|
|
||||||
*fis_solver,
|
|
||||||
*polymer_inflow,
|
|
||||||
wells_manager,
|
|
||||||
grav,
|
|
||||||
deck->hasKeyword("DISGAS"),
|
|
||||||
deck->hasKeyword("VAPOIL"),
|
|
||||||
polymer,
|
|
||||||
eclipseState,
|
|
||||||
outputWriter,
|
|
||||||
threshold_pressures);
|
|
||||||
|
|
||||||
|
|
||||||
fullReport = simulator.run(simtimer, state, well_state);
|
fullReport = simulator.run(simtimer, state);
|
||||||
prev_well_state = well_state;
|
|
||||||
}
|
|
||||||
std::cout << "\n\n================ End of simulation ===============\n\n";
|
std::cout << "\n\n================ End of simulation ===============\n\n";
|
||||||
fullReport.report(std::cout);
|
fullReport.report(std::cout);
|
||||||
|
|
||||||
|
@ -86,14 +86,13 @@ namespace Opm
|
|||||||
const PolymerPropsAd& polymer_props,
|
const PolymerPropsAd& polymer_props,
|
||||||
const RockCompressibility* rock_comp_props,
|
const RockCompressibility* rock_comp_props,
|
||||||
NewtonIterationBlackoilInterface& linsolver,
|
NewtonIterationBlackoilInterface& linsolver,
|
||||||
const PolymerInflowInterface& polymer_inflow,
|
|
||||||
WellsManager& well_manager,
|
|
||||||
const double* gravity,
|
const double* gravity,
|
||||||
const bool disgas,
|
const bool disgas,
|
||||||
const bool vapoil,
|
const bool vapoil,
|
||||||
const bool polymer,
|
const bool polymer,
|
||||||
std::shared_ptr<EclipseState> eclipse_state,
|
std::shared_ptr<EclipseState> eclipse_state,
|
||||||
EclipseWriter& output_writer,
|
EclipseWriter& output_writer,
|
||||||
|
Opm::DeckConstPtr& deck,
|
||||||
const std::vector<double>& threshold_pressures_by_face);
|
const std::vector<double>& threshold_pressures_by_face);
|
||||||
|
|
||||||
/// Run the simulation.
|
/// Run the simulation.
|
||||||
@ -104,8 +103,7 @@ namespace Opm
|
|||||||
/// \param[in,out] well_state state of wells: bhp, perforation rates
|
/// \param[in,out] well_state state of wells: bhp, perforation rates
|
||||||
/// \return simulation report, with timing data
|
/// \return simulation report, with timing data
|
||||||
SimulatorReport run(SimulatorTimer& timer,
|
SimulatorReport run(SimulatorTimer& timer,
|
||||||
PolymerBlackoilState& state,
|
PolymerBlackoilState& state);
|
||||||
WellStateFullyImplicitBlackoil& well_state);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
class Impl;
|
class Impl;
|
||||||
|
@ -52,6 +52,7 @@
|
|||||||
#include <opm/parser/eclipse/EclipseState/Schedule/ScheduleEnums.hpp>
|
#include <opm/parser/eclipse/EclipseState/Schedule/ScheduleEnums.hpp>
|
||||||
#include <opm/parser/eclipse/EclipseState/Schedule/Well.hpp>
|
#include <opm/parser/eclipse/EclipseState/Schedule/Well.hpp>
|
||||||
#include <opm/parser/eclipse/EclipseState/Schedule/WellProductionProperties.hpp>
|
#include <opm/parser/eclipse/EclipseState/Schedule/WellProductionProperties.hpp>
|
||||||
|
#include <opm/parser/eclipse/Deck/Deck.hpp>
|
||||||
|
|
||||||
#include <boost/filesystem.hpp>
|
#include <boost/filesystem.hpp>
|
||||||
#include <boost/lexical_cast.hpp>
|
#include <boost/lexical_cast.hpp>
|
||||||
@ -82,19 +83,17 @@ namespace Opm
|
|||||||
const PolymerPropsAd& polymer_props,
|
const PolymerPropsAd& polymer_props,
|
||||||
const RockCompressibility* rock_comp_props,
|
const RockCompressibility* rock_comp_props,
|
||||||
NewtonIterationBlackoilInterface& linsolver,
|
NewtonIterationBlackoilInterface& linsolver,
|
||||||
const PolymerInflowInterface& polymer_inflow,
|
|
||||||
WellsManager& wells_manager,
|
|
||||||
const double* gravity,
|
const double* gravity,
|
||||||
bool has_disgas,
|
bool has_disgas,
|
||||||
bool has_vapoil,
|
bool has_vapoil,
|
||||||
bool has_polymer,
|
bool has_polymer,
|
||||||
std::shared_ptr<EclipseState> eclipse_state,
|
std::shared_ptr<EclipseState> eclipse_state,
|
||||||
EclipseWriter& output_writer,
|
EclipseWriter& output_writer,
|
||||||
|
Opm::DeckConstPtr& deck,
|
||||||
const std::vector<double>& threshold_pressures_by_face);
|
const std::vector<double>& threshold_pressures_by_face);
|
||||||
|
|
||||||
SimulatorReport run(SimulatorTimer& timer,
|
SimulatorReport run(SimulatorTimer& timer,
|
||||||
PolymerBlackoilState& state,
|
PolymerBlackoilState& state);
|
||||||
WellStateFullyImplicitBlackoil& well_state);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Data.
|
// Data.
|
||||||
@ -118,8 +117,6 @@ namespace Opm
|
|||||||
// Solvers
|
// Solvers
|
||||||
const DerivedGeology& geo_;
|
const DerivedGeology& geo_;
|
||||||
NewtonIterationBlackoilInterface& solver_;
|
NewtonIterationBlackoilInterface& solver_;
|
||||||
const PolymerInflowInterface& polymer_inflow_;
|
|
||||||
WellsManager& wells_manager_;
|
|
||||||
// Misc. data
|
// Misc. data
|
||||||
std::vector<int> allcells_;
|
std::vector<int> allcells_;
|
||||||
const bool has_disgas_;
|
const bool has_disgas_;
|
||||||
@ -129,6 +126,7 @@ namespace Opm
|
|||||||
std::shared_ptr<EclipseState> eclipse_state_;
|
std::shared_ptr<EclipseState> eclipse_state_;
|
||||||
// output_writer
|
// output_writer
|
||||||
EclipseWriter& output_writer_;
|
EclipseWriter& output_writer_;
|
||||||
|
Opm::DeckConstPtr& deck_;
|
||||||
RateConverterType rateConverter_;
|
RateConverterType rateConverter_;
|
||||||
// Threshold pressures.
|
// Threshold pressures.
|
||||||
std::vector<double> threshold_pressures_by_face_;
|
std::vector<double> threshold_pressures_by_face_;
|
||||||
@ -151,19 +149,18 @@ namespace Opm
|
|||||||
const PolymerPropsAd& polymer_props,
|
const PolymerPropsAd& polymer_props,
|
||||||
const RockCompressibility* rock_comp_props,
|
const RockCompressibility* rock_comp_props,
|
||||||
NewtonIterationBlackoilInterface& linsolver,
|
NewtonIterationBlackoilInterface& linsolver,
|
||||||
const PolymerInflowInterface& polymer_inflow,
|
|
||||||
WellsManager& wells_manager,
|
|
||||||
const double* gravity,
|
const double* gravity,
|
||||||
const bool has_disgas,
|
const bool has_disgas,
|
||||||
const bool has_vapoil,
|
const bool has_vapoil,
|
||||||
const bool has_polymer,
|
const bool has_polymer,
|
||||||
std::shared_ptr<EclipseState> eclipse_state,
|
std::shared_ptr<EclipseState> eclipse_state,
|
||||||
EclipseWriter& output_writer,
|
EclipseWriter& output_writer,
|
||||||
|
Opm::DeckConstPtr& deck,
|
||||||
const std::vector<double>& threshold_pressures_by_face)
|
const std::vector<double>& threshold_pressures_by_face)
|
||||||
|
|
||||||
{
|
{
|
||||||
pimpl_.reset(new Impl(param, grid, geo, props, polymer_props, rock_comp_props, linsolver, polymer_inflow, wells_manager, gravity, has_disgas,
|
pimpl_.reset(new Impl(param, grid, geo, props, polymer_props, rock_comp_props, linsolver, gravity, has_disgas,
|
||||||
has_vapoil, has_polymer, eclipse_state, output_writer, threshold_pressures_by_face));
|
has_vapoil, has_polymer, eclipse_state, output_writer, deck, threshold_pressures_by_face));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -172,10 +169,9 @@ namespace Opm
|
|||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
SimulatorReport SimulatorFullyImplicitBlackoilPolymer<T>::run(SimulatorTimer& timer,
|
SimulatorReport SimulatorFullyImplicitBlackoilPolymer<T>::run(SimulatorTimer& timer,
|
||||||
PolymerBlackoilState& state,
|
PolymerBlackoilState& state)
|
||||||
WellStateFullyImplicitBlackoil& well_state)
|
|
||||||
{
|
{
|
||||||
return pimpl_->run(timer, state, well_state);
|
return pimpl_->run(timer, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -246,14 +242,13 @@ namespace Opm
|
|||||||
const PolymerPropsAd& polymer_props,
|
const PolymerPropsAd& polymer_props,
|
||||||
const RockCompressibility* rock_comp_props,
|
const RockCompressibility* rock_comp_props,
|
||||||
NewtonIterationBlackoilInterface& linsolver,
|
NewtonIterationBlackoilInterface& linsolver,
|
||||||
const PolymerInflowInterface& polymer_inflow,
|
|
||||||
WellsManager& wells_manager,
|
|
||||||
const double* gravity,
|
const double* gravity,
|
||||||
const bool has_disgas,
|
const bool has_disgas,
|
||||||
const bool has_vapoil,
|
const bool has_vapoil,
|
||||||
const bool has_polymer,
|
const bool has_polymer,
|
||||||
std::shared_ptr<EclipseState> eclipse_state,
|
std::shared_ptr<EclipseState> eclipse_state,
|
||||||
EclipseWriter& output_writer,
|
EclipseWriter& output_writer,
|
||||||
|
Opm::DeckConstPtr& deck,
|
||||||
const std::vector<double>& threshold_pressures_by_face)
|
const std::vector<double>& threshold_pressures_by_face)
|
||||||
: param_(param),
|
: param_(param),
|
||||||
grid_(grid),
|
grid_(grid),
|
||||||
@ -263,13 +258,12 @@ namespace Opm
|
|||||||
gravity_(gravity),
|
gravity_(gravity),
|
||||||
geo_(geo),
|
geo_(geo),
|
||||||
solver_(linsolver),
|
solver_(linsolver),
|
||||||
polymer_inflow_(polymer_inflow),
|
|
||||||
wells_manager_(wells_manager),
|
|
||||||
has_disgas_(has_disgas),
|
has_disgas_(has_disgas),
|
||||||
has_vapoil_(has_vapoil),
|
has_vapoil_(has_vapoil),
|
||||||
has_polymer_(has_polymer),
|
has_polymer_(has_polymer),
|
||||||
eclipse_state_(eclipse_state),
|
eclipse_state_(eclipse_state),
|
||||||
output_writer_(output_writer),
|
output_writer_(output_writer),
|
||||||
|
deck_(deck),
|
||||||
rateConverter_(props_, std::vector<int>(AutoDiffGrid::numCells(grid_), 0)),
|
rateConverter_(props_, std::vector<int>(AutoDiffGrid::numCells(grid_), 0)),
|
||||||
threshold_pressures_by_face_(threshold_pressures_by_face)
|
threshold_pressures_by_face_(threshold_pressures_by_face)
|
||||||
{
|
{
|
||||||
@ -302,8 +296,7 @@ namespace Opm
|
|||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
SimulatorReport SimulatorFullyImplicitBlackoilPolymer<T>::Impl::run(SimulatorTimer& timer,
|
SimulatorReport SimulatorFullyImplicitBlackoilPolymer<T>::Impl::run(SimulatorTimer& timer,
|
||||||
PolymerBlackoilState& state,
|
PolymerBlackoilState& state)
|
||||||
WellStateFullyImplicitBlackoil& well_state)
|
|
||||||
{
|
{
|
||||||
WellStateFullyImplicitBlackoil prev_well_state;
|
WellStateFullyImplicitBlackoil prev_well_state;
|
||||||
|
|
||||||
@ -317,30 +310,47 @@ namespace Opm
|
|||||||
std::ofstream tstep_os(tstep_filename.c_str());
|
std::ofstream tstep_os(tstep_filename.c_str());
|
||||||
|
|
||||||
// Main simulation loop.
|
// Main simulation loop.
|
||||||
// while (!timer.done()) {
|
while (!timer.done()) {
|
||||||
// Report timestep.
|
// Report timestep.
|
||||||
step_timer.start();
|
step_timer.start();
|
||||||
timer.report(std::cout);
|
timer.report(std::cout);
|
||||||
|
|
||||||
// Create wells and well state.
|
// Create wells and well state.
|
||||||
// WellsManager wells_manager(eclipse_state_,
|
WellsManager wells_manager(eclipse_state_,
|
||||||
// timer.currentStepNum(),
|
timer.currentStepNum(),
|
||||||
// Opm::UgGridHelpers::numCells(grid_),
|
Opm::UgGridHelpers::numCells(grid_),
|
||||||
// Opm::UgGridHelpers::globalCell(grid_),
|
Opm::UgGridHelpers::globalCell(grid_),
|
||||||
// Opm::UgGridHelpers::cartDims(grid_),
|
Opm::UgGridHelpers::cartDims(grid_),
|
||||||
// Opm::UgGridHelpers::dimensions(grid_),
|
Opm::UgGridHelpers::dimensions(grid_),
|
||||||
// Opm::UgGridHelpers::beginCellCentroids(grid_),
|
Opm::UgGridHelpers::beginCellCentroids(grid_),
|
||||||
// Opm::UgGridHelpers::cell2Faces(grid_),
|
Opm::UgGridHelpers::cell2Faces(grid_),
|
||||||
// Opm::UgGridHelpers::beginFaceCentroids(grid_),
|
Opm::UgGridHelpers::beginFaceCentroids(grid_),
|
||||||
// props_.permeability());
|
props_.permeability());
|
||||||
const Wells* wells = wells_manager_.c_wells();
|
const Wells* wells = wells_manager.c_wells();
|
||||||
// WellStateFullyImplicitBlackoil well_state;
|
WellStateFullyImplicitBlackoil well_state;
|
||||||
// well_state.init(wells, state.blackoilState());
|
well_state.init(wells, state.blackoilState());
|
||||||
// if (timer.currentStepNum() != 0) {
|
if (timer.currentStepNum() != 0) {
|
||||||
// // Transfer previous well state to current.
|
// Transfer previous well state to current.
|
||||||
// well_state.partialCopy(prev_well_state, *wells, prev_well_state.numWells());
|
well_state.partialCopy(prev_well_state, *wells, prev_well_state.numWells());
|
||||||
// }
|
}
|
||||||
|
|
||||||
|
// compute polymer inflow
|
||||||
|
std::unique_ptr<PolymerInflowInterface> polymer_inflow_ptr;
|
||||||
|
if (deck_->hasKeyword("WPOLYMER")) {
|
||||||
|
if (wells_manager.c_wells() == 0) {
|
||||||
|
OPM_THROW(std::runtime_error, "Cannot control polymer injection via WPOLYMER without wells.");
|
||||||
|
}
|
||||||
|
polymer_inflow_ptr.reset(new PolymerInflowFromDeck(deck_, *wells, Opm::UgGridHelpers::numCells(grid_)));
|
||||||
|
} else {
|
||||||
|
polymer_inflow_ptr.reset(new PolymerInflowBasic(0.0*Opm::unit::day,
|
||||||
|
1.0*Opm::unit::day,
|
||||||
|
0.0));
|
||||||
|
}
|
||||||
|
std::vector<double> polymer_inflow_c(Opm::UgGridHelpers::numCells(grid_));
|
||||||
|
const PolymerInflowInterface& polymer_inflow = *polymer_inflow_ptr;
|
||||||
|
polymer_inflow.getInflowValues(timer.simulationTimeElapsed(),
|
||||||
|
timer.simulationTimeElapsed() + timer.currentStepLength(),
|
||||||
|
polymer_inflow_c);
|
||||||
// Output state at start of time step.
|
// Output state at start of time step.
|
||||||
if (output_ && (timer.currentStepNum() % output_interval_ == 0)) {
|
if (output_ && (timer.currentStepNum() % output_interval_ == 0)) {
|
||||||
if (output_vtk_) {
|
if (output_vtk_) {
|
||||||
@ -363,13 +373,6 @@ namespace Opm
|
|||||||
// Compute reservoir volumes for RESV controls.
|
// Compute reservoir volumes for RESV controls.
|
||||||
computeRESV(timer.currentStepNum(), wells, state, well_state);
|
computeRESV(timer.currentStepNum(), wells, state, well_state);
|
||||||
|
|
||||||
// compute polymer inflow
|
|
||||||
std::vector<double> polymer_inflow_c(Opm::UgGridHelpers::numCells(grid_));
|
|
||||||
if (has_polymer_) {
|
|
||||||
polymer_inflow_.getInflowValues(timer.simulationTimeElapsed(),
|
|
||||||
timer.simulationTimeElapsed() + timer.currentStepLength(),
|
|
||||||
polymer_inflow_c);
|
|
||||||
}
|
|
||||||
// Run a single step of the solver.
|
// Run a single step of the solver.
|
||||||
solver_timer.start();
|
solver_timer.start();
|
||||||
FullyImplicitBlackoilPolymerSolver<T> solver(param_, grid_, props_, geo_, rock_comp_props_, polymer_props_, *wells, solver_, has_disgas_, has_vapoil_, has_polymer_);
|
FullyImplicitBlackoilPolymerSolver<T> solver(param_, grid_, props_, geo_, rock_comp_props_, polymer_props_, *wells, solver_, has_disgas_, has_vapoil_, has_polymer_);
|
||||||
@ -391,19 +394,19 @@ namespace Opm
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Increment timer, remember well state.
|
// Increment timer, remember well state.
|
||||||
// ++timer;
|
++timer;
|
||||||
// prev_well_state = well_state;
|
prev_well_state = well_state;
|
||||||
// }
|
}
|
||||||
|
|
||||||
// Write final simulation state.
|
// Write final simulation state.
|
||||||
// if (output_) {
|
if (output_) {
|
||||||
// if (output_vtk_) {
|
if (output_vtk_) {
|
||||||
// outputStateVtk(grid_, state, timer.currentStepNum(), output_dir_);
|
outputStateVtk(grid_, state, timer.currentStepNum(), output_dir_);
|
||||||
// }
|
}
|
||||||
// outputStateMatlab(grid_, state, timer.currentStepNum(), output_dir_);
|
outputStateMatlab(grid_, state, timer.currentStepNum(), output_dir_);
|
||||||
// outputWellStateMatlab(prev_well_state, timer.currentStepNum(), output_dir_);
|
outputWellStateMatlab(prev_well_state, timer.currentStepNum(), output_dir_);
|
||||||
// output_writer_.writeTimeStep(timer, state.blackoilState(), prev_well_state.basicWellState());
|
output_writer_.writeTimeStep(timer, state.blackoilState(), prev_well_state.basicWellState());
|
||||||
// }
|
}
|
||||||
|
|
||||||
// Stop timer and create timing report
|
// Stop timer and create timing report
|
||||||
total_timer.stop();
|
total_timer.stop();
|
||||||
|
Loading…
Reference in New Issue
Block a user