Since writeTimeStep() now gets called also before the first timestep is done,
the EclipseWellTotal::update() method was in error, always calling
SimulatorTimer::stepLengthTaken(). That method cannot be called if the
timer's currentStepNum() is 0, so that is checked for and intercepted.
The total rate in that case is of course zero.
This commit implements some additional scaling keywords. This includes
the ISWL-family that provide hysteresis behaviour via alternative
scaling of the tables. The old parser has been somewhat extended for
testing purposes. The commit also includes a slight refactoring of the
SatFunc-family where a new base class has been introduced.
If we want to index into two arrays that has been concatenated (for
instance oil phase pressure continuously, then water phase pressure
continuously), then this variant (courtesy of @bska) will cover both
variants (intermixed striding (where offset < stride) and sequentially
striding (where offset > stride)).
We are interested in how many records there are, since we extract one
item per record. The offset is just used to index into each record, and
doesn't affect the total number of records.
If the output routines are called at the right place in the simulator,
then the numbering scheme coincide with that of Eclipse, and no
adjustments are necessary.
We already copy the data once from the OPM state into the ERT-managed
memory, so we may as well fudge a conversion routine in there (at the
expense of having to do this everywhere).
The writeTimeStep method is called *after* each timestep and does
not include the initial state of the reservoir. If the writer wants
to dump the initial state of the reservoir, this must be done in
writeInit, which is called before the simulator is run, but after
the initial state has been set up.
The Eclipse timestep index can not always be retrieved from the
SimulatorTimer object; the initial state is 0 in Eclipse (and does not
have an index in OPM), and the timestep in OPM is not increased until
*after* the timestep is completed (i.e. it is not initialized to -1).
We would like to build up and write the header only once (with
ecl_sum_fwrite_smspec) and then the data for each timestep (with
ecl_sum_fwrite_step), but since the data attach to the summary
object and so does the header, how do we keep the header in memory
without also accumulating all the data?
Instead of calling the destroy functions for the timestep and well
report objects, the ERT memory allocated for these are contained in
the summary handle and freed together with that.
The timestep and well report objects thus becomes only views into this
memory; it is no longer allowed for these to outlive the summary section
(not that this was ever sensible in the first place).
Although this will lead to parsing the same input data over and over
again (setting up the smspecs for the wells), the summary files contain
this redundant information because in Eclipse, wells can appear and
disappear during the run.
Although GCC 4.6.3 implements div by including stdlib.h (where
everything is put in the global namespace), and then importing these
into std, not every compiler does this (one could for instance think
that in #include <stdlib.h> inside the namespace).
The original rationale for commit c39d367 was to pass a pointer since
this was all we got from one of the APIs. However, just after the code
was changed to copy the data anyway since it would have to be converted
from double to float.
Reverting actually serves a purpose; as @bska pointed out, taking
&data[0] of an empty vector is undefined, whereas it now checks the
size and assert here (and not in the standard library) on that condition.
The EclipseSummary field is just forward declared in the header, and
the compiler cannot create a proper destructor based on just that. If
we define it in the compilation unit, it will get instantiated there
once and for all and the compiler won't try to create it (and leave it
to the linker to sort out duplicates) everywhere the header is used
(which may be in another module, even).
This is similar to commit 18b9f2b for SimulatorOutput.
Since all construction should go through the wrapper method, and the
class otherwise just handed everything down to the base class, we might
as well inline everything in there to avoid someone starting to make
their own objects of this type.
Instead of having each timestep available just locally in the
writeTimeStep method, which will free the memory and create a
corruption error, keep all timesteps on a free list in the summary,
and do all the writing in the destructor there (the memory of the
individual timesteps will have to linger on anyway).
ERT requires the type of the keywords that are passed to the grid
allocation routine to be float (and it is checked - causes abort if
there is a mismatch!)
The writer will need to know which cells are the active cells after
post-processing (because these are the cells there is stored results
for in the pressure and saturation arrays), and thus not only the
raw input grid (to get the COORD and ZCORN arrays which is not easily
detainable from the UnstructuredGrid), *and* the UnstructuredGrid
needs to be available.
The template function share_obj let you pass regular references
as shared pointers, which makes it easy (perhaps too easy) to quick-
fix old code which pass references and have stern warnings about the
lifetime rules of the objects in the documentation section instead.
If an interface requires a shared_ptr, but we have an object that is
known to outlive the client anyway, we can use a custom deleter to
suppress the delete part and pass this object around anyway.
The code is now allowed to use C++11, where shared_ptr is available
in the standard. To specify that the parser object must be present
for the output writer in its entire lifetime, we require to be passed
a shared_ptr. (This can be faked for local storage anyway).
Due to a glitch the order of the names was put incorrectly in the file,
even though the comment stressed that it was important it was right!
Hat tip: @bska
The return type of the path methods has changed in newer version of
Boost; by wrapping them with a new path object we can get a string
in a way that is compatible for both version 2 and 3.
Hat tip: @bska
Using an interface allows us to code the simulator to just pass the
necessary state variables to something which implements this, and
then the user can select the actual output format with configuration
values. This allows us to set new formats without having to change
the code being compiled (for instance, we can have a special debug
"format" which prints out things of interest in each timestep)
By getting a pointer directly into the data store, the copy can be
performed faster than calling a function for every item. Also, the
storage type of the array should now match the C++ one exactly (i.e.
no conversion to float).
C++11 will write a default move constructor that invoke the same in
the base class. However, GCC 4.4 doesn't support this, so we have to
explicitly give the implementation that would be generated on later
compilers.
If we put them in the anonymous namespace, then we cannot have a
reference to the types in the header (because that would mean different
things in each compilation unit).
The only thing it was needed for was the number of cells in the grid,
and the Cartesian dimensions, and those are already available from other
structures.
ecl_grid_alloc_GRDECL_kw takes zcorn first, then coord (slightly
unintuitive if you ask me), and this is also the order that is used
in EclipseGrid::make; thus, the order should be consistent through
the constructor also.
If we restart from a later time, then the SimulatorTimer should be
restarted in that state as well, so it is already always a reflection
of how far we've progressed in the input file's schedule.
The EclipseKeyword class takes care of cleaning up the handle after we
are done using it, and provides several convenience constructors that
make the code read easier.
The code to condense the output using repeat counts was disabled
long ago (commit fc992da). If we ever need this feature, we can
bring it back from history or reimplemented in a refined fashion.
There is no need to use a nested loop to output a constant number of
items per line. We only need to output a '\n' rather than a ' '
after every "nl" item output.
Currently, it still writes out whatever conservation quantity which is
used by the solver (which is probably the mass of the oil/gas
mixture). TODO: convert these solver rates to "pure oil volume without
gas at the surface" and to "gas volume at the surface" rates.
thanks again to Joakim Hove for the pointers where to start kicking!
most code was shamelessly ripped from opm-core's EclipseGridParser,
but there are some additions (e.g. grids specified using the D[XYZ]V
Eclipse keywords can be used).
The code is located inside the new class "BlackoilEclipseOutputWriter"
(should probably renamed) and hooked up in
SimulatorFullyImplicitBlackoil and sim_fibo_ad.cc.
Also be aware that, to make this code work properly, the newest master
version of ERT is required (i.e. one which includes commit
5e4e9661720). In this context, I would like to thank Joakim Hove for
his support!
for some of these files this is needed to make to keep it compiling
after the next patch because the new ErrorMacros.hpp file will no
longer implicitly includes <iostream>. for the remaining files it is
just good style.
While at it, the includes for most of these files have been ordered in
order of decreasing abstraction level.
our policy is that we only use boost if necessary, i.e., if the oldest
supported compiler does not support a given feature but boost
does. since we recently switched to GCC 4.4 or newer, std::shared_ptr
is available unconditionally.
The functions of linInt.hpp are now used everywhere, but:
- linInt.hpp -> linearInterpolation.hpp (better name)
- linearInterpolationExtrap() -> linearInterpolation() (extrapolate by default)