Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for directional relative permeabilities #714

Merged
merged 15 commits into from
Sep 26, 2022

Conversation

hakonhagland
Copy link
Contributor

@hakonhagland hakonhagland commented Sep 1, 2022

@hakonhagland
Copy link
Contributor Author

jenkins build this opm-material=532 opm-common=3113 please

Copy link
Member

@atgeirr atgeirr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What I looked at seems good, I just have a few questions and minor requests.

@@ -588,6 +646,39 @@ private:
friend BlackOilBrineIntensiveQuantities<TypeTag>;
friend BlackOilMICPIntensiveQuantities<TypeTag>;

void updateRelperms(const Problem& problem, const MaterialLawParams& materialParams, unsigned globalSpaceIdx)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When it is spread across two functions, it is not easy to see that mobility_ and dirMob_ gets updated here. What about making this a static function and passing mobility_ and dirMob_ to it, that way it is obvious at the call site that those variables get updated?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea! See update.

/*!
* \brief Returns the direction of the face
*/
FaceDir::DirEnum dirId() const
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For my current work on boundary conditions, it would be very useful if dirId() returned the underlying int instead, as I need to distinguish between the XMin and XPlus cases. Could we make that change, and add a free function faceDirFromDirId() with the implementation below?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, see update.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, I have added the code identically to my own branch too, so it should be easy to rebase one once the other is merged.

@@ -597,6 +688,7 @@ private:
Evaluation porosity_;
Evaluation rockCompTransMultiplier_;
std::array<Evaluation,numPhases> mobility_;
std::shared_ptr<DirectionalMobility> dirMob_;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume this is a shared_ptr and not a unique_ptr to keep the class copyable. But I think that changes the semantics of the class in a nontrivial way, as we will then not get a fully independent copy anymore. I am not set against it, but have you looked at the places where IQs are copied and checked that this is ok?

If we want to preserve deep copy semantics with a smart pointer it is possible, the Thor library has (or at least used to have) a CopiedPtr template that implemented it: https://bromeon.ch/libraries/thor/tutorials/v1.1/smartptr.html

Not sure that is necessary though.

Copy link
Contributor Author

@hakonhagland hakonhagland Sep 16, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes! That was to make the IQs copyable. I am not sure if there is an easy way to find all the places where the copy constructor and assignment operator for the IQ are used. I checked some files and looked at the compiler error messages and found one place in fvbaseelmentcontext.hh where they are copied: see updateIntensitiveQuantities_() at line 562 and one place where the IQs are reassigned, see updateStencil() at line 140. There are probably other places?

In the updated PR, I changed the shared_ptr to unique_ptr and added a copy constructor and an assignment operator to the BlackOilIntensiveQuantities class.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it is not a good solution to add explicitly coded copy constructors and assignment operators. It adds to the maintenance overhead significantly. I am also not sure it is actually correct as implemented here in the copy constructor, it fails to copy most members, this just demonstrates the point that it is hard to maintain.

I think using a copyable smart pointer is the best solution, keeping the copy construction and assigment defaulted. I may have come across as skeptical of the shared_ptr, but I think it can be an acceptable solution, as long as we have considered the consequences. A smart pointer with copy semantics is also a fine solution I think, but requires us to create or adopt such a template class.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It adds to the maintenance overhead significantly

@atgeirr Yes, I agree.

A smart pointer with copy semantics is also a fine solution I think, but requires us to create or adopt such a template class.

I'll give the "copyable pointer" a try first. In the added commit I try to implement a minimal functionality for a copyable pointer.

To make each copy of the IQ unique, we change dirMob_ to be a shared_ptr
instead of a unique_ptr.
To aid readability, we make updateRelperms() a static function.
Use a copyable unique pointer instead of writing custom copy constructor
and assignment operator.
return ptr_ ? true : false;
}
// get a reference to the stored value
T& get() const {return *ptr_;}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To be consistent with the unique_ptr interface, it should return the raw pointer instead (return ptr_.get()).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea

CopyablePtr() : ptr_(nullptr) {}
CopyablePtr(const CopyablePtr& other) {
if (other) { // other does not contain a nullptr
ptr_ = std::make_unique<T>(other.get());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With get() returning a pointer (see below), this should change to take *this.

if (other) { // other does not contain a nullptr
ptr_ = std::make_unique<T>(other.get());
}
// else {ptr_ = nullptr;} // this is the default construction value
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The else branch must be implemented to kill the current pointer. Copying from an empty smart pointer should leave the current object as a similarly empty one, just as in the assignment operator.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought since we are constructing a new object there will be no current object? Then, the default constructor will apply to the unique_ptr which will initialize it with a nullptr. Anyway, for clarity I have updated the code to use the else branch.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are correct in that there is no current object, my mistake! Maybe I thought it was a move constructor or something, not sure. But the default constructor is not invoked automatically, so you should always ensure all members are initialized.

// of the unique_ptr each time we copy construct or assign to it from another BlackOilIntensiveQuantites.
// (On the other hand, if a copy could share the ptr with the original, a shared_ptr could be used instead and the
// wrapper would not be needed)
template <class T>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would add one more warning to this class template comment: You should never use it polymorphically. (That would require a virtual clone() method etc.) It will only ever copy the static class type of the pointed to class.

Also, it should be put in a separate file, and have some unit tests.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea, I have moved the class to opm-common, see OPM/opm-common#3113 and added some tests..

This is more in line with how std::unique_ptr works.
For clarity, explicitly default construct the unique_ptr in the copy
constructor
Moved the CopyablePtr template class to opm-common, see file
opm/utility/CopyablePtr.hpp in opm-common
Try to fix jenkins build error: no type named EclMaterialLawManager
Define a method materialLawManagerPtr() that returns a nullpointer
to EclMaterialLawManager, but that can be overridden in derived classes
e.g. EclProblem
@bska
Copy link
Member

bska commented Sep 26, 2022

This PR appears to break the post-commit build. Please fix or revert.

@totto82
Copy link
Member

totto82 commented Sep 26, 2022

Strange, it was green. Let me first double-check locally. Could there be an issue with the ordering and timing of when this and the PR in opm-material was merged?

@hakonhagland
Copy link
Contributor Author

hakonhagland commented Sep 26, 2022

This PR appears to break the post-commit build

I see in the jenkins log:

[5/119] Building CXX object CMakeFiles/reservoir_blackoil_vcfv.dir/tests/reservoir_blackoil_vcfv.cc.o
FAILED: CMakeFiles/reservoir_blackoil_vcfv.dir/tests/reservoir_blackoil_vcfv.cc.o

But locally on my machine the test reservoir_blackoil_vcfv in opm-models seems not to be built. Any ideas how I can build and test this locally?

@bska
Copy link
Member

bska commented Sep 26, 2022

locally on my machine the test reservoir_blackoil_vcfv in opm-models seems not to be built. Any ideas how I can build and test this locally?

Configure all your module builds with the

-DBUILD_TESTING:BOOL=True

cmake option.

@bska
Copy link
Member

bska commented Sep 26, 2022

Could there be an issue with the ordering and timing of when this and the PR in opm-material was merged?

I suppose, but I get the same result locally when I include BUILD_TESTING in my configuration options.

@hakonhagland
Copy link
Contributor Author

Configure all your module builds with the

-DBUILD_TESTING:BOOL=True

@bska Thanks for the information!

This PR appears to break the post-commit build. Please fix or revert.

This has been addressed in #727. Thanks to @totto82 for ideas on how to solve this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants