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 PyVista mesh support to Field #59

Merged
merged 5 commits into from
Dec 10, 2020
Merged

Add PyVista mesh support to Field #59

merged 5 commits into from
Dec 10, 2020

Conversation

banesullivan
Copy link
Collaborator

@banesullivan banesullivan commented Jan 12, 2020

Resolve #32 (see #32 (comment)) by giving the Field class a way to handle PyVista meshes. After this, I see no advantage for implementing a custom PyVista plotting routine but to just let users do PyVista plotting on their own.

Originally, this function would do everything implicitly without importing the mesh packages... IMO, this isn't a very stable/clean way to implement that as it was checking for attributes on the objects which could be shared across types or the name could be present on an unsupported type that isn't what is expected. I implemented PyVista by bare try/except import and then checking if the passed mesh is a PyVista dataset.

I would HIGHLY recommend implementing type checking for the other meshes and add an alert the user if they are passing an unsupported object.


Example usage with PyVista from the code in #36 (comment)

...
grid = pv.UniformGrid()
grid.origin = (329700, 4252600, -2700)
grid.spacing = (250, 250, 50)
grid.dimensions = (60, 75, 100)

# Create the kriging model
krig = krige.Ordinary(fit_model,
                      cond_pos=project["temperature"].points.T, 
                      cond_val=project["temperature"]["temperature (C)"])

krig.mesh(grid, name="temperature (C)", )

...

Another concern. This method does not leverage structured grids... does having a structured grid even help? Because if so, there are a number of PyVista mesh types that can be recast to structured grids which would improve performance

Comment on lines 125 to 136
if isinstance(out, np.ndarray):
mesh[name] = out
else:
# if multiple values are returned, take the first one
mesh[name] = out[0]
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This is really messy... we should leverage #60 to handle adding all returned arrays to the PyVista and meshio meshes

Copy link
Member

Choose a reason for hiding this comment

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

This can now be discussed in #65

Copy link
Collaborator Author

@banesullivan banesullivan Jan 16, 2020

Choose a reason for hiding this comment

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

This is probably the best as is and we can use #65 to change this

Copy link
Member

Choose a reason for hiding this comment

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

@banesullivan I added a workaround for this problem.

@MuellerSeb
Copy link
Member

Please make this PR in the develop branch.

@banesullivan banesullivan changed the base branch from master to develop January 13, 2020 16:14
@banesullivan
Copy link
Collaborator Author

the base has been changed to develop

@banesullivan
Copy link
Collaborator Author

If you "squash and merge" on GitHub, this should be good

@banesullivan banesullivan marked this pull request as ready for review January 13, 2020 17:15
@banesullivan
Copy link
Collaborator Author

I should probably add some tests to make sure all PyVista meshes work

@LSchueler LSchueler self-requested a review February 7, 2020 10:55
@LSchueler
Copy link
Member

Yeah, I think if you add some tests, we can merge this as is and then, when I finally get along with PR #65, I will automatically be reminded to change this.

@banesullivan
Copy link
Collaborator Author

@LSchueler, will do! And I'll get looking at #65 ASAP too

@banesullivan
Copy link
Collaborator Author

Apologies for doing a rebase and force push... this got outdated quickly.

I'm trying to add tests but having trouble running the tests locally...

@banesullivan
Copy link
Collaborator Author

This same error is happening for like all of the tests:

____________________________________________ TestCondition.test_ordinary ____________________________________________

self = <test_condition.TestCondition testMethod=test_ordinary>

    def test_ordinary(self):
        for Model in self.cov_models:
            model = Model(
>               dim=1, var=0.5, len_scale=2, anis=[0.1, 1], angles=[0.5, 0, 0]
            )

tests/test_condition.py:74:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
gstools/covmodel/base.py:175: in __init__
    self.dim = dim
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <[AttributeError("'Gaussian' object has no attribute '_var'") raised in repr()] Gaussian object at 0x7f9820f3be10>
dim = 1

    @dim.setter
    def dim(self, dim):
        # check if a fixed dimension should be used
        if self.fix_dim() is not None:
            print(self.name + ": using fixed dimension " + str(self.fix_dim()))
            dim = self.fix_dim()
        # set the dimension
        if dim < 1 or dim > 3:
            raise ValueError("Only dimensions of 1 <= d <= 3 are supported.")
        self._dim = int(dim)
        # create fourier transform just once (recreate for dim change)
>       self._sft = SFT(ndim=self.dim, **self.hankel_kw)
E       TypeError: __init__() got an unexpected keyword argument 'alt'

gstools/covmodel/base.py:988: TypeError

any suggestions?

@banesullivan
Copy link
Collaborator Author

banesullivan commented Apr 10, 2020

Well, I took alt out of the HANKEL_DEFAULT locally in covmodel/base.py and now the tests are running

@banesullivan
Copy link
Collaborator Author

I added a basic test in test_srf.py that uses PyVista PolyData. It is important to note that this method will work for all PyVista mesh types as PyVista's general API is used which is shared across mesh types.

I also noticed the the .mesh() method isn't called anywhere else in the testing suite. This might need to be fully implemented to also test how meshio and ogs5py meshes are handled

@MuellerSeb
Copy link
Member

@banesullivan welcome back!! have a look at the new mesh class from #65 .. we plan to include the meshIO stuff there and you are warmly welcome to provide input and wishes there (since we mostly had the vtk format in mind creating this)!

the hankel problem comes in your case from an outdated hankel package (update to 1.0 and it should work!)

maybe we could close this PR in favor of #65 and start over with the new mesh class.

What do you think?

@LSchueler
Copy link
Member

@banesullivan Are you fine with closing this PR?

@banesullivan
Copy link
Collaborator Author

All good by me to close this PR! The code will remain here for reference if needed and #59 should take precedence

@MuellerSeb MuellerSeb reopened this Nov 25, 2020
@MuellerSeb
Copy link
Member

@banesullivan I reopened this PR, since we decided, that the mesh class will be a separate class in GSTools, that can be passed to the Field.mesh class like this PR does with pyvista meshes.

I think, the way you proposed here is the best one for now. Sorry for this!

@MuellerSeb MuellerSeb self-assigned this Nov 25, 2020
@MuellerSeb MuellerSeb added the enhancement New feature or request label Nov 25, 2020
@MuellerSeb MuellerSeb added this to the 1.3 milestone Nov 25, 2020
@MuellerSeb
Copy link
Member

To solve the problem with multiple returns: We could think about allowing a list of names for the name parameter. We could also care about wrong numbers of names (to also use the standard value of a sole name "field"):

def _names(name, cnt):
    name = [name] if isinstance(name, str) else list(name)[:cnt]
    if len(name) < cnt:
        name += [name[-1] + str(i + 1) for i in range(cnt - len(name))]
    return name

Then we could do something like the following after the field was generated:

fields = [out] if isinstance(out, np.ndarray) else out
for f_name, field in zip(_names(name, len(fields)), fields):
    mesh[f_name] = field

This would result in the names "field" and "field1" when called from a Krige subclass, storing the field and the kriging variance.

@banesullivan
Copy link
Collaborator Author

@MuellerSeb, looks good to me! I like your fix for handling the field names

@MuellerSeb MuellerSeb removed the request for review from LSchueler December 10, 2020 06:41
Copy link
Member

@MuellerSeb MuellerSeb left a comment

Choose a reason for hiding this comment

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

@banesullivan thanks for supporting this! 👍

@MuellerSeb MuellerSeb merged commit bcbb8db into GeoStat-Framework:develop Dec 10, 2020
@MuellerSeb MuellerSeb linked an issue Apr 7, 2021 that may be closed by this pull request
3 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

PyVista next steps
3 participants