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

Start PetscObject #1

Closed
wants to merge 107 commits into from
Closed

Start PetscObject #1

wants to merge 107 commits into from

Conversation

ZoeLeibowitz
Copy link
Owner

Playing around with PR UI.

@ZoeLeibowitz ZoeLeibowitz added the testing Playing around. Don't review. label Jun 20, 2023
@ZoeLeibowitz ZoeLeibowitz changed the title Test. Start PetscObject Jun 23, 2023
@ZoeLeibowitz ZoeLeibowitz added enhancement New feature or request and removed testing Playing around. Don't review. labels Jun 23, 2023
@ZoeLeibowitz
Copy link
Owner Author

Start of PetscObject ... please review if you have time, thanks!

@mloubout
Copy link
Collaborator

mloubout commented Jun 23, 2023

@edsml-zl5621 @FabioLuporini I think can make use of the standard devito objects and interface rather than resulting in all these new classe. Below is an example of something that would work as a nice extension without needing to go all the way down to object but might need some tweaks

from ctypes import POINTER

import numpy as np

from devito import *

from devito.ir.iet import Definition, DummyExpr
from devito.types.dense import DiscreteFunction
from devito.types.basic import Basic, AbstractSymbol
from devito.types.object import AbstractObject
from devito.tools import dtype_to_cstr, dtype_to_ctype


class PetscObject(AbstractSymbol):
    is_PetscObject = True
    """
    PetscObjects encode their dtype as a class attribute.
    """

    @property
    def is_const(self):
        return self._is_const
    
    @property
    def dtype(self):
        return self._dtype

    @property
    def _C_name(self):
        return self.name

    @property
    def _C_ctype(self):
        name = dtype_to_cstr(self._dtype).capitalize()
        return type('Petsc%s' % name, (dtype_to_ctype(self._dtype),), {})


class PetscFunction(Function):

    @property
    def _C_ctype(self):
        ctypename = 'Petsc%s' % dtype_to_cstr(self.dtype).capitalize()
        ctype = dtype_to_ctype(self.dtype)
        r = POINTER(type(ctypename, (ctype,), {}))
        for n in range(len(self.dimensions)-1):
            r = POINTER(r)
        return r


grid = Grid((2, 2))
x, y = grid.dimensions
# pointer and const functionality
ptr1 = PetscFunction(name='ptr1', dtype=np.int32, grid=grid, dimensions=(x,), shape=(2,), is_const=True)
ptr2 = PetscFunction(name='ptr2', dtype=np.int32, grid=grid, dimensions=(x,), shape=(2,))
pptr = PetscFunction(name='pptr', dtype=np.int32, grid=grid)

defn1 = Definition(ptr1)
defn2 = Definition(ptr2)
defn3 = Definition(pptr)

# algebraic expressions
x = PetscObject(name='x', dtype=np.int32)
y = PetscObject(name='y', dtype=np.int32)

expr1 = DummyExpr(x, 15, init=True)
expr2 = DummyExpr(x, y-1)

print(str(defn1))
print(str(defn2))
print(str(defn3))
print(str(expr1))
print(str(expr2))

assert str(defn1) == "const PetscInt * ptr1;"
assert str(defn2) == "PetscInt * ptr2;"
assert str(defn3) == "PetscInt ** pptr;"
assert str(expr1) == "PetscInt x = 15;"
assert str(expr2) == "x = -1 + y;"

# taken exactly from Function class but removed the "shape_global"
# # and also added the option for all dimensions, shape and grid to be None
@classmethod
def __shape_setup__(cls, **kwargs):
Copy link
Collaborator

Choose a reason for hiding this comment

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

both shape_setup and indices_setup should belong to AbstractObjectWithShape

Copy link
Owner Author

Choose a reason for hiding this comment

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

Does this mean I should remove the 'empty' shape_setup and indices_setup that are currently inside AbstractObjectWithShape and replace them with these ones?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Why not?

Say I create a new subtype, let's call it class MyNewObject(AbstractObjectWithShape)

I want this new type to share all the key PetscObject mechanisms , don't I?

if len(shape) != len(dimensions):
raise ValueError("`shape` and `dimensions` must have the "
"same number of entries")
loc_shape = []
Copy link
Collaborator

Choose a reason for hiding this comment

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

no distinction between global and local shape (MPI irrelevant for Objects), so we don't need this part

PetscObject
"""

AbstractObjectWithShape = True
Copy link
Collaborator

Choose a reason for hiding this comment

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

don't add unless proven useful. Too early


AbstractObjectWithShape
|
PetscObject
Copy link
Collaborator

Choose a reason for hiding this comment

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

a PetscObject is way too special to live inside the types/object directory. Only the more general class belong here.

The PetscObject type should instead be defined wherever you will implement the petsc machinery (passes/iet/petsc/ ?) . Just like we do for some MPI Objects under /mpi/distributed or /mpi/routines

@@ -1,14 +1,17 @@
from ctypes import byref
from ctypes import POINTER
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why not from ctypes import byref, POINTER?

self._is_const = kwargs.get('is_const', False)

# taken exactly from Function class but removed the "shape_global"
# # and also added the option for all dimensions, shape and grid to be None
Copy link
Collaborator

Choose a reason for hiding this comment

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

Extra # in the second comment here

@classmethod
def __indices_setup__(cls, **kwargs):
grid = kwargs.get('grid')
# shape = kwargs.get('shape', None)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Leftover comment


@property
def _C_ctype(self):
"""
Copy link
Collaborator

Choose a reason for hiding this comment

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

Is the empty docstring intentional?

@ZoeLeibowitz
Copy link
Owner Author

Hi, I added a FunctionPtr class and a test for the symbolic representation of C's function pointers. I'm not sure if this is the right way to do it so if someone could have a look that would be great! Thank you

Symbolic representation of C's function pointers.
"""

_return_typ = ''
Copy link
Collaborator

Choose a reason for hiding this comment

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

why aren't these instance attributes?

also, you can add an 'e' at the end of 'type' ;)

Copy link
Owner Author

Choose a reason for hiding this comment

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

I took inspo from the Cast class https://github.com/devitocodes/devito/blob/0abe3952a792ed9ba5bf9ef904fa2fec04789a79/devito/symbolics/extended_sympy.py#L370C1-L400C33 and _base_typ is not an instance attribute. Is there a particular reason for this?

Copy link
Collaborator

Choose a reason for hiding this comment

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

I think it's a leftover from code that has been refactorer multiple times. You may probably tweak that too !

func = Pickable._rebuild

@property
def _op(self):
Copy link
Collaborator

Choose a reason for hiding this comment

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

shouldn't this just be __str__ (== __repr__)

@FabioLuporini
Copy link
Collaborator

Also, how about a first tiny tiny PR that only ships FunctionPointer and related tests -- see:

  • test_symbolics.py
  • test_pickling.py

THe first merge into devito master is big milestone :-)

@ZoeLeibowitz ZoeLeibowitz reopened this Aug 4, 2023
# need to check this?
# __rkwargs__ = ('name', 'dtype', 'is_const', 'grid', 'shape', 'dimensions')

def __new__(cls, *args, **kwargs):
Copy link
Collaborator

Choose a reason for hiding this comment

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

This still looks like there is a quite large amount of overlap with AbstractFunction so I'm not sure why this is needed.

Copy link
Owner Author

Choose a reason for hiding this comment

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

Hi, I forgot to ask about this in the meeting. @FabioLuporini do you have any comments on this, because I am unsure?

Copy link
Collaborator

Choose a reason for hiding this comment

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

@mloubout AbstractObject doesn't inherit from AbstractFunction, so unless we lift some of the construction logic to the closest common ancestor (as in, Basic), this needs to stay here, I think

Copy link
Collaborator

Choose a reason for hiding this comment

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

But this doesn't need to inheriting from AbstractObject if there is already an existing type that does all of it. This just redefines AbstractFunction with a new calss name and _const it should be a 2 liners inheriting from AbstractFunction

# __rkwargs__ = (AbstractObjectWithShape.__rkwargs__ +
# ('petsc_type',))

def __init__(self, name, petsc_type, **kwargs):
Copy link
Collaborator

Choose a reason for hiding this comment

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

Should implement _init_finalize_ not __init__ to follow AbstractObjectWithShape construction

return obj

def __str__(self):
return "(%s (%s)(%s))%s" % (self.return_type, '*',
Copy link
Collaborator

Choose a reason for hiding this comment

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

Could this be simplified to return "(%s (*)(%s))%s" % (self.return_type, self.parameter_type, self.func_name)?


# this probably shouldn't be in this file
def petsc_type_to_ctype(petsc_type):
"Map Petsc types to ctypes type"
Copy link
Collaborator

Choose a reason for hiding this comment

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

Triple quotes on the docstring

@@ -400,6 +401,37 @@ def _op(self):
return '(%s)' % self.typ


class FunctionPointer(sympy.Expr, Pickable):

Copy link
Collaborator

Choose a reason for hiding this comment

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

Remove this whitespace?

@ZoeLeibowitz ZoeLeibowitz added testing Playing around. Don't review. and removed enhancement New feature or request labels Dec 19, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
testing Playing around. Don't review.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants