-
Notifications
You must be signed in to change notification settings - Fork 33
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
Tentative solution to replace FrozenClass #244
Conversation
I like the changes. I am fine with the register params thing. I guess you are right that there are many things that could use a cleanup... |
pySDC/implementations/problem_classes/AdvectionEquation_ND_FD.py
Outdated
Show resolved
Hide resolved
pySDC/implementations/problem_classes/AdvectionEquation_ND_FD.py
Outdated
Show resolved
Hide resolved
pySDC/implementations/problem_classes/AdvectionEquation_ND_FD.py
Outdated
Show resolved
Hide resolved
@brownbaerchen tell me if the implementation changes suit you. Then I'll start to work on the class documentation |
pySDC/implementations/problem_classes/AdvectionEquation_ND_FD.py
Outdated
Show resolved
Hide resolved
To (finally) answer your question concerning the |
Thanks ! I may have some small improvement to propose for that. On the same topic, why do we need different data-types for u and f ? |
I like improvements, bring it on! Concerning data types: the IMEX sweeper expects a different type of Then think of particles, where the |
Ok, I think I finshed the implementation aspect of this PR. The main change is how parameters are given and stored in the base Problem class, with an example of inheritance using the Also, the problem class has now two properties that can be used to instantiate data types for u and f. It simplifies a little bit the implementation in inherited Problem classes, but the main advantage is to tell explicitly in the code how the 🔔 Note on testing : in a near future, each inherited problem class could be tested like this ... def testProblemImplementation(probClass):
prob = probClass()
params = prob.params # check if all registered parameters where set as attributes
u_init = prob.u_init # check if dtype_u works with init
u_init = prob.f_init # check if dtype_f works with init If you are OK with this @pancetta @brownbaerchen, I'll write down the full documentation for those parts ... |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to me apart from minor things. Also, we should probably have either the helpers/pysdc_helper.py
file or the core/Common.py
file, but not both, since they have the same purpose. I don't care what name the file has, though.
|
||
# register parameters | ||
self._register('nvars', 'ndim', 'c', 'stencil_type', 'order', 'bc', readOnly=True) | ||
self._register('freq', 'sigma', 'lintol', 'liniter', 'direct_solver') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I personally would like the _register
function to accept a dictionary instead of *names
. Then don't need the separate steps of storing and registering. But I get the feeling you are not a fan of dictionaries. So if you prefer this, I am fine with it as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not that I'm not a fan of dictionary. Actually, one could even store automatically parameters as arguments without dictionaries, like this
self._register('nvars', 'ndim', 'c', 'stencil_type', 'order', 'bc', readOnly=True, localVars=locals())
# => get the parameters values from locals() and store it directly as attribute in _register method
But I'm following one of Python's Zen : "Explicit is better than implicit"
By setting all parameters as attributes in the _register method, you hide the storing of parameters as object attribute, and never write it explicitly, e.g self.nvars = nvars
. From a developer point of view, once you are aware of this mechanism, it is indeed simpler to write and avoid this whole self.blabla = blabla
multiple times.
But this is only for one person, and she does it only one time ! While for someone who want read the code, specifying in the constructor self.thisPar = thisPar
(or something else) is explicit and easier to understand, especially if you are not aware of the _register
mechanism.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd rather have one mechanism of "registering" attributes than two (which have to be done both). If you are clear about what the _register
method does, I think there will be no confusion. Maybe with a more explicit name for this method (e.g. _make_attribute_and_register
) this is not such a problem? The current proposal is not clear to me (if I were someone who wants to read the code): why do I need to store AND register? And what happens if I store but don't register?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@pancetta I do like your idea of making the method name more explicit. I've implemented this in the last commit. Also on a side note : parameters are stored in set
, as looking up an element is faster than in a list. But then the order they are given in the _makeAttributeAndRegister
function does not matter, only the alphabetic order is used, see :
Since setting attribute of the class method is (theoretically) done only during the instantiation with __init__
, it should not degrade that much performance to use list
instead, which would allow to keep the parameter order in the params
dictionary. Would you prefer that ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any scenario where the order would matter? If not, a set
it is.
|
Just added the documentation (and also, did the same mistake as @brownbaerchen did before by merging master into my local v6 😅). I used Numpy docstyle instead of Google docstyle. Yes it's produce longer documentation, but at least those can have more details and can be easily read from the code. Also, if necessary, most IDE's and editors have a way to hide docstring if necessary (for instance, if you are developing the class and don't care about documentation). Also, there are a lot of tools that generate automatically a template for the docstring from the signature of the function ... Additional points :
It does (probably) not break the website documentation rendering. Any comment/thought ? |
Alright! Good job! For a second I thought you already changed all the problems. Very annoying... While we have to go through all the problems: I am in the process of adding a hook for storing the local error wrt to Currently this is the only problem supporting this and so I am unsure if everything associated should just go in my project folders rather than the implementations folder. But I do think this is a useful feature and I suggest to add the arguments to all Given that the What do you think? Should I keep this to myself or should we add the extra lines to all classes? |
@brownbaerchen I'd be ok with that. |
Looks good indeed, but I worry that we're going to mess up things. There is no consistency in the documentation anymore, if we have (1) |
This is just a suggestion for v6. We will anyway have to rework many classes with this idea of default parameters and So the point here is : Numpy of Google docstyle, what do you think is best ? (I used Numpy style here to have a comparison ...) And about the mix |
I do aggree (too), see Discussion #253 |
Agreed, agreed. I just wanted to make sure we're not mixing up too many things. Concerning docstyles: I'm ok with either of these. NumPy's would be probably more fitting from what I see and it would give us the chance of checking all docstrings for consistency and correctness. |
Concerning helpers: the fewer we have the better. If you see a way to get rid of some of then by integrating them into some core functionality, feel free! |
@brownbaerchen @pancetta can we merge this into v6 ? So I can focus on #254 (see all steps proposed in #255 ) |
LGTM |
To follow up on #240 : here is one way to put class parameters as argument, and still allow to display all the main parameters from the controller class.
It is based on a
RegisterParams
class, currently implemented in Problem.py, but that could serve as (one of the) parent class of each core classes. I've applied this to theadvectionNd
class, but there is still a few issues to solve ... :nvars
, since it needsnvars
as tuple. Is the format for thisinit
attribute of the problem class a requirement for all children class, or it is like it just foradvectionNd
@pancetta ?ndim
argument can always be determined from thenvars
one, and should be since there was no "prolongation" ofnvars
to larger dimension (for instance, ifnvars=4
and ndim=3
, thennvars
is automatically transformed to[4,4,4]
). But the current implementation actually does not allows different size fornvars
since the theA
matrix is generated taking onlynvars[0]
into account. So should we keepnvars
multidimensional forndim>1
or can we just use an integer for it and set the number of dimension withndim
? This could also simplify the generation of xv, and only keepxvalues
as main attribute, from which the rest can be derived (dx
,xv
, etc ...).xv
can be stored as sparse, which will save memory (especially in 3D) and if we indeed keep the same mesh on each dimension, we could simply storexvalues
, which will enough to generate the analytical solution inu_exact
.Other commits may come on this PR (for instance for documentation, etc ...) but let me know what you think about it yet @brownbaerchen