Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion opm/models/io/vtkmultiwriter.hh
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ class VtkMultiWriter : public BaseOutputWriter
// current time step
// The file names in the pvd file are relative, the path should therefore be stripped.
const std::filesystem::path fullPath{fileName};
const std::string localFileName = fullPath.filename();
const std::string localFileName = fullPath.filename().string();
multiWriter_.multiFile_.precision(16);
multiWriter_.multiFile_ << " <DataSet timestep=\"" << multiWriter_.curTime_ << "\" file=\""
<< localFileName << "\"/>\n";
Expand Down
14 changes: 13 additions & 1 deletion opm/models/pvs/pvsprimaryvariables.hh
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
#include <opm/models/discretization/common/fvbaseprimaryvariables.hh>
#include <opm/models/pvs/pvsproperties.hh>

#include <bit>
#include <cassert>
#include <cmath>
#include <ostream>
Expand Down Expand Up @@ -216,7 +217,18 @@ public:
* \brief Returns the phase with the lowest index that is present.
*/
unsigned lowestPresentPhaseIdx() const
{ return static_cast<unsigned>(ffs(phasePresence_) - 1); }
{
// No phase present: fail fast instead of returning a bogus phase index.
// The previous ffs()-based code returned ffs(0)-1, a huge index whose
// out-of-bounds access surfaced the corrupt state immediately.
if (phasePresence_ == 0) [[unlikely]] {
throw NumericalProblem("Phase presence is 0, i.e., no fluid is present");
}

// std::countr_zero requires an unsigned argument; its count of trailing
// zeros is the index of the lowest set bit, i.e. the lowest phase present.
return static_cast<unsigned>(std::countr_zero(static_cast<unsigned short>(phasePresence_)));
}

/*!
* \brief Assignment operator from an other primary variables object
Expand Down
3 changes: 2 additions & 1 deletion opm/models/tpsa/tpsamodel.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,8 @@ class TpsaModel
#ifdef _OPENMP
#pragma omp parallel for
#endif
for (const auto& chunk : element_chunks_) {
for (std::size_t ci = 0; ci < element_chunks_.size(); ++ci) {
const auto& chunk = element_chunks_[ci];
for (const auto& elem : chunk) {
const unsigned globalIdx = elementMapper.index(elem);
auto& currSol = solution(/*timeIdx=*/0)[globalIdx];
Expand Down
14 changes: 14 additions & 0 deletions opm/models/utils/alignedallocator.hh
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@
#include <type_traits>
#include <utility>

#if defined(_MSC_VER)
#include <malloc.h> // _aligned_malloc / _aligned_free
#endif

namespace Opm {

namespace detail {
Expand Down Expand Up @@ -80,16 +84,26 @@ inline void* aligned_alloc(std::size_t alignment,
alignment = sizeof(void*);
}
void* p;
#if defined(_MSC_VER)
// MSVC has no posix_memalign; _aligned_malloc takes (size, alignment).
p = _aligned_malloc(size, alignment);
#else
if (::posix_memalign(&p, alignment, size) != 0) {
p = 0;
}
#endif
return p;
}

inline void aligned_free(void* ptr)
noexcept
{
#if defined(_MSC_VER)
// Memory from _aligned_malloc must be released with _aligned_free.
_aligned_free(ptr);
#else
::free(ptr);
#endif
}

template<class T, std::size_t Alignment>
Expand Down
11 changes: 10 additions & 1 deletion opm/models/utils/parametersystem.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,16 @@ auto getParamName()
return Parameter::name;
} else {
std::string paramName = Dune::className<Parameter>();
paramName.replace(0, std::strlen("Opm::Parameters::"), "");
// Strip the enclosing namespace. Do NOT assume the string starts with
// "Opm::Parameters::": MSVC's Dune::className prefixes the type with
// "struct "/"class " (e.g. "struct Opm::Parameters::EclDeckFileName"),
// so find the qualifier instead of erasing a fixed number of leading
// characters (which previously produced names like "-eters::...").
constexpr std::string_view nsQualifier = "Opm::Parameters::";
const auto nsPos = paramName.find(nsQualifier);
if (nsPos != std::string::npos) {
paramName.erase(0, nsPos + nsQualifier.size());
}
const auto pos = paramName.find_first_of('<');
if (pos != std::string::npos) {
paramName.erase(pos);
Expand Down
17 changes: 16 additions & 1 deletion opm/models/utils/simulatorutils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,19 @@
#include <iomanip>
#include <sstream>
#include <sys/stat.h>
#include <unistd.h>
#include <vector>

#if defined(_WIN32)
#include <io.h> // _access
#else
#include <unistd.h>
#endif

// MSVC's <sys/stat.h> defines _S_IFMT/_S_IFDIR but not the POSIX S_ISDIR macro.
#if defined(_MSC_VER) && !defined(S_ISDIR)
# define S_ISDIR(mode) (((mode) & _S_IFMT) == _S_IFDIR)
#endif

#if HAVE_QUAD
#include <opm/material/common/quad.hpp>
#endif
Expand Down Expand Up @@ -134,7 +144,12 @@ std::string simulatorOutputDir()
"' exists but is not a directory");
}

#if defined(_WIN32)
// _access mode 2 checks for write permission, like access(..., W_OK).
if (_access(outputDir.c_str(), 2) != 0) {
#else
if (access(outputDir.c_str(), W_OK) != 0) {
#endif
throw std::runtime_error("Output directory '" + outputDir +
"' exists but is not writeable");
}
Expand Down
39 changes: 32 additions & 7 deletions opm/models/utils/terminal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,22 +28,41 @@
#include <mpi.h>
#endif

#include <chrono>
#include <csignal>
#include <cstdio>
#include <iostream>
#include <thread>
#include <unordered_map>

#if defined(_WIN32)
#include <io.h> // _isatty, _fileno
#else
#include <sys/ioctl.h>
#include <unistd.h>
#endif

namespace {

bool isTty(std::FILE* stream)
{
#if defined(_WIN32)
return _isatty(_fileno(stream)) != 0;
#else
return isatty(fileno(stream)) != 0;
#endif
}

const char* getSignalAbbrev(int sig)
{
const auto sig_map = std::unordered_map<int, const char*>{
{SIGINT, "INT"},
{SIGILL, "ILL"},
{SIGABRT, "ABRT"},
{SIGFPE, "FPE"},
{SIGKILL, "KILL"},
#ifdef SIGKILL
{SIGKILL, "KILL"}, // not defined by MSVC's <signal.h>
#endif
{SIGSEGV, "SEGV"},
{SIGTERM, "TERM"},
};
Expand Down Expand Up @@ -110,7 +129,7 @@ std::string breakLines(const std::string& msg,
int getTtyWidth()
{
int ttyWidth = 10*1000; // effectively do not break lines at all.
if (isatty(STDOUT_FILENO) != 0) {
if (isTty(stdout)) {
#if defined TIOCGWINSZ
// This is a bit too linux specific, IMO. let's do it anyway
struct winsize ttySize;
Expand All @@ -129,13 +148,17 @@ void assignResetTerminalSignalHandlers()
{
// set the signal handlers to reset the TTY to a well defined state on unexpected
// program aborts
if (isatty(STDIN_FILENO) != 0) {
if (isTty(stdin)) {
signal(SIGINT, resetTerminal);
signal(SIGHUP, resetTerminal);
#ifdef SIGHUP
signal(SIGHUP, resetTerminal); // not on Windows
#endif
signal(SIGABRT, resetTerminal);
signal(SIGFPE, resetTerminal);
signal(SIGSEGV, resetTerminal);
signal(SIGPIPE, resetTerminal);
#ifdef SIGPIPE
signal(SIGPIPE, resetTerminal); // not on Windows
#endif
signal(SIGTERM, resetTerminal);
}
}
Expand All @@ -151,15 +174,17 @@ void resetTerminal()

// it seems like some terminals sometimes takes their time to react, so let's
// accommodate them.
usleep(/*usec=*/500*1000);
std::this_thread::sleep_for(std::chrono::milliseconds(500));

#if !defined(_WIN32)
// this requires the 'stty' command to be available in the command search path. on
// most linux systems, is the case. (but even if the system() function fails, the
// worst thing which can happen is that the TTY stays potentially choked up...)
if (system("stty sane") != 0) {
std::cout << "Executing the 'stty' command failed."
<< " Terminal might be left in an undefined state!\n";
}
#endif
}

void resetTerminal(int signum)
Expand All @@ -178,7 +203,7 @@ void resetTerminal(int signum)
}
#endif

if (isatty(fileno(stdout)) != 0 && isatty(fileno(stdin)) != 0) {
if (isTty(stdout) && isTty(stdin)) {
std::cout << "\n\nReceived signal " << signum
<< " (\"" << getSignalAbbrev(signum) << "\")."
<< " Trying to reset the terminal.\n";
Expand Down
68 changes: 60 additions & 8 deletions opm/simulators/flow/Banners.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,18 +32,66 @@
#include <ctime>
#include <iomanip>
#include <iostream>
#include <optional>
#include <sstream>
#include <sys/utsname.h>
#include <string>
#include <thread>

#if defined(_WIN32)
#define WIN32_LEAN_AND_MEAN
#define NOMINMAX
#include <windows.h>
#include <cstdlib> // getenv
#else
#include <sys/utsname.h>
#include <unistd.h>
#endif

namespace {

unsigned long long getTotalSystemMemory()
{
#if defined(_WIN32)
// Windows has no sysconf(_SC_PHYS_PAGES); query the total physical memory.
MEMORYSTATUSEX status;
status.dwLength = sizeof(status);
if (GlobalMemoryStatusEx(&status)) {
return static_cast<unsigned long long>(status.ullTotalPhys);
}
return 0;
#else
long pages = sysconf(_SC_PHYS_PAGES);
long page_size = sysconf(_SC_PAGE_SIZE);
return pages * page_size;
#endif
}

struct SystemDescription
{
std::string nodename;
std::string os; // empty when no operating-system description is available
};

std::optional<SystemDescription> getSystemDescription()
{
#if defined(_WIN32)
// Windows has no uname()/utsname; query the machine name via the Win32 API.
char computer_name[MAX_COMPUTERNAME_LENGTH + 1] = {};
DWORD computer_name_len = sizeof(computer_name);
return SystemDescription {
GetComputerNameA(computer_name, &computer_name_len) ? computer_name : "unknown",
""
};
#else
struct utsname arch;
if (uname(&arch) != 0) {
return std::nullopt;
}
std::ostringstream os;
os << arch.sysname << " " << arch.machine << " (Kernel: " << arch.release
<< ", " << arch.version << " )";
return SystemDescription { arch.nodename, os.str() };
#endif
}

}
Expand All @@ -57,8 +105,11 @@ void printPRTHeader(const int nprocs, const int nthreads,
{
const double megabyte = 1024 * 1024;
unsigned num_cpu = std::thread::hardware_concurrency();
struct utsname arch;
#if defined(_WIN32)
const char* user = getenv("USERNAME"); // no getlogin() on Windows
#else
const char* user = getlogin();
#endif
std::time_t now = std::time(0);
struct std::tm tstruct;
char tmstr[80];
Comment on lines 111 to 115
Expand All @@ -75,12 +126,13 @@ void printPRTHeader(const int nprocs, const int nthreads,
ss << "Flow is a simulator for fully implicit three-phase black-oil flow,";
ss << " and is part of OPM.\nFor more information visit: https://opm-project.org \n\n";
ss << "Flow Version = " << moduleVersion << "\n";
if (uname(&arch) == 0) {
ss << "Machine name = " << arch.nodename << " (Number of logical cores: " << num_cpu;
ss << ", Memory size: " << std::fixed << std::setprecision (2) << mem_size << " MB) \n";
ss << "Operating system = " << arch.sysname << " " << arch.machine << " (Kernel: " << arch.release;
ss << ", " << arch.version << " )\n";
ss << "Build time = " << compileTimestamp << "\n";
if (const auto sys = getSystemDescription()) {
ss << "Machine name = " << sys->nodename << " (Number of logical cores: " << num_cpu;
ss << ", Memory size: " << std::fixed << std::setprecision(2) << mem_size << " MB) \n";
if (!sys->os.empty()) {
ss << "Operating system = " << sys->os << "\n";
}
ss << "Build time = " << compileTimestamp << "\n";
}
if (user) {
ss << "User = " << user << std::endl;
Expand Down
18 changes: 12 additions & 6 deletions opm/simulators/flow/ConvergenceOutputConfiguration.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,18 @@ namespace {
std::vector<std::string> tokenizeOptionValues(std::string_view options)
{
const auto split = std::regex { R"(\s*,\s*)" };
return {
std::cregex_token_iterator {
options.begin(), options.end(), split, -1
},
std::cregex_token_iterator {}
};
// Construct from the iterator range explicitly: a braced {first, last}
// is interpreted by MSVC as an initializer_list<cregex_token_iterator>
// rather than the (first, last) range constructor.
// Use data()/data()+size() raw pointers: std::cregex_token_iterator needs
// const char* iterators, but MSVC's std::string_view::begin() is a checked
// iterator class (not const char*), which does not convert.
return std::vector<std::string>(
std::cregex_token_iterator(
options.data(), options.data() + options.size(), split, -1
),
std::cregex_token_iterator()
);
}

void reportUnsupportedOptionValuesAndThrow(std::vector<std::string> unsupp,
Expand Down
6 changes: 4 additions & 2 deletions opm/simulators/flow/FIBlackoilModel.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,8 @@ class FIBlackOilModel : public BlackOilModel<TypeTag>
#ifdef _OPENMP
#pragma omp parallel for
#endif
for (const auto& chunk : element_chunks_) {
for (std::size_t ci = 0; ci < element_chunks_.size(); ++ci) {
const auto& chunk = element_chunks_[ci];
ElementContext elemCtx(this->simulator_);
for (const auto& elem : chunk) {
elemCtx.updatePrimaryStencil(elem);
Expand Down Expand Up @@ -257,7 +258,8 @@ class FIBlackOilModel : public BlackOilModel<TypeTag>
#ifdef _OPENMP
#pragma omp parallel for
#endif
for (const auto& chunk : element_chunks_) {
for (std::size_t ci = 0; ci < element_chunks_.size(); ++ci) {
const auto& chunk = element_chunks_[ci];
for (const auto& elem : chunk) {
this->template updateSingleCachedIntQuantUnchecked<Args...>(elementMapper.index(elem), timeIdx);
}
Expand Down
6 changes: 4 additions & 2 deletions opm/simulators/flow/FacePropertiesTPSA_impl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -150,11 +150,13 @@ update()
ThreadSafeMapBuilder distanceBoundaryMap(distanceBoundary_, num_threads, MapBuilderInsertionMode::Insert_Or_Assign);
ThreadSafeMapBuilder faceNormalBoundaryMap(faceNormalBoundary_, num_threads, MapBuilderInsertionMode::Insert_Or_Assign);

// Loop over grid element an compute face properties
const auto element_chunks = ElementChunks(gridView_, Dune::Partitions::all, num_threads);
#ifdef _OPENMP
#pragma omp parallel for
#endif
// Loop over grid element an compute face properties
for (const auto& chunk : ElementChunks(gridView_, Dune::Partitions::all, num_threads)) {
for (std::size_t ci = 0; ci < element_chunks.size(); ++ci) {
const auto& chunk = element_chunks[ci];
for (const auto& elem : chunk) {
// Init. face info for inside/outside cells
FaceInfo inside;
Expand Down
Loading