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

feat: apdl submodule #3385

Open
wants to merge 47 commits into
base: feat/main_commands
Choose a base branch
from
Open

feat: apdl submodule #3385

wants to merge 47 commits into from

Conversation

clatapie
Copy link
Contributor

@clatapie clatapie commented Sep 5, 2024

This PR is the first one in order to automate the PyMAPDL _commands documentation.
The changes have been generated using pyconverter-xml2py.

This PR focus on the apdl submodule.

Pinging @ansys/pymapdl-developers for visibility. Feel free to provide any feedback on the way the docstrings and the source code generation are handled.

Note

This PR is meant to be merged within the feat/main_commands branch. The latter will gather all the submodule changes, one by one, prior to be merged to the main branch.

Checklist

@clatapie clatapie added documentation Documentation related (improving, adding, etc) enhancement Improve any current implemented feature labels Sep 5, 2024
@clatapie clatapie self-assigned this Sep 5, 2024
@clatapie clatapie requested a review from a team as a code owner September 5, 2024 16:03
@clatapie clatapie requested review from germa89 and pyansys-ci-bot and removed request for a team September 5, 2024 16:03
@ansys-reviewer-bot
Copy link
Contributor

Thanks for opening a Pull Request. If you want to perform a review write a comment saying:

@ansys-reviewer-bot review

@clatapie clatapie requested a review from RobPasMue September 5, 2024 16:04
@github-actions github-actions bot added new feature Request or proposal for a new feature and removed documentation Documentation related (improving, adding, etc) labels Sep 5, 2024
@germa89
Copy link
Collaborator

germa89 commented Sep 5, 2024

I am setting this PR as draft because I think it is still not ready until you fix the line length thing.

Ping us and switch this PR to non-draft when you feel it is ready for it.

@germa89 germa89 marked this pull request as draft September 5, 2024 16:06
@clatapie
Copy link
Contributor Author

clatapie commented Sep 5, 2024

I can rework on it if docstring length is a priority. I already fixed some issues related in ansys/pyconverter-xml2py#222 but not all of them as you can see.
Except from this issue, feel free to comment any other change you would like me to work on.

Also, I had to comment the codespell pre-commit hook because it was failing even when I was ignoring the dedicated directory ``./src/ansys/mapdl/core/_commands). The next commit will show it.

@github-actions github-actions bot added CI/CD Related with CICD, Github Actions, etc examples Publishing PyMAPDL examples documentation Documentation related (improving, adding, etc) dependencies maintenance General maintenance of the repo (libraries, cicd, etc) labels Oct 18, 2024
@wiz-inc-572fc38784
Copy link
Contributor

wiz-inc-572fc38784 bot commented Oct 18, 2024

Wiz Scan Summary

Scanner Findings
Vulnerability Finding Vulnerabilities
Data Finding Sensitive Data
Secret Finding Secrets
IaC Misconfiguration IaC Misconfigurations
Total

View scan details in Wiz

To detect these findings earlier in the dev lifecycle, try using Wiz Code VS Code Extension.

@clatapie clatapie force-pushed the feat/apdl_submodule branch from ac7b46a to 04dac45 Compare October 18, 2024 12:15
@github-actions github-actions bot removed CI/CD Related with CICD, Github Actions, etc examples Publishing PyMAPDL examples documentation Documentation related (improving, adding, etc) dependencies maintenance General maintenance of the repo (libraries, cicd, etc) labels Oct 18, 2024
@github-actions github-actions bot added the CI/CD Related with CICD, Github Actions, etc label Oct 18, 2024
@github-actions github-actions bot removed the examples Publishing PyMAPDL examples label Dec 16, 2024
@germa89
Copy link
Collaborator

germa89 commented Dec 17, 2024

@clatapie ... CICD is SUPER unstable right now since I merged #3268. I'm working on that.

I would probably revert that commit in the main_commands branch and see if the PR passes. To be safe, I would probably revert any other commit after since I'm working quite a lot on that at the moment.

btw, this was fixed. CICD is "stable" again.

@germa89
Copy link
Collaborator

germa89 commented Dec 17, 2024

For the commands with non-pythonic MAPDL commands (i.e. SECMODIF) where the MAPDL command signature might change depending on the argument:

image

additional_arguments option

@clatapie suggested an extra string argument such as:

def secmodif(self, secid="", Keyword="", additional_arguments="", **kwargs):
    # implementation
    return self.run(f"SECMODIF,{secid}, {keyword},{additional_arguments}")

So you can do:

mapdl.secmodif(1, "NORM", "NX=2,NY=3, NZ=2, KCN=2")

This effectively injects all the additional arguments as an string.

Caveats

While this method might work, it delegates to the user all the responsability of building the command, and additionally it forces you to specify all the intermediate arguments (or commas). For instance if you only wants to use KCN, you will have to:

mapdl.secmodif(1, "NORM", ", , , KCN=2")

which looks rather weird.

The * method

I would propose to use * in the function signature after the argument keyword. This way, the user is forced to use key arguments to specify the values.

def secmodif(self, secid, Keyword, *, nx="", ny="", nz="", kcn="", name="", Option="", dispPnltVal="", RotPnltVal=""):
    # We will know which command option by internally switching like this:
    if Keyword  == "NORM" or nx or ny:
         cmd = "SECMODIF, NORM, {nx}, {ny}, {nz}"
    elif Keyword  == "NAME" or name:
         cmd = "SECMODIF, NAME, {name}"
    else:
        raise ValueError("We couldn't map the arguments given....")

Then we can quickly use this like:

mapdl.secmodif(1, nx=1) # implicitly using keyword=NORM
mapdl.secmodif(name='name')  # implicitly using keyword=NAME

And because of * in the signature, you will get an error if trying to use more args than allowed:

mapdl.secmodif(1, "NORM", 1, 2) # Raise an error

Caveats

The problem of this is that the API can be broken... because the above mapdl.secmodif(1, "NORM", 1, 2) is something that most of other commands do. Furthermore, this will need for the translator module to be adapted so it can predict the key arguments (or just bypass the conversion using mapdl.run).

The *args option

We will use the *args option, but the implementation is rather complicated:

def secmodif(self, secid, Keyword, *args, **kwargs):
    # We will know which command option by internally switching like this:
    # getting kword
    args_kw = {}
    # dict with arguments names and their position
    arg_names = {
    "nx": 0, "ny": 1, "nz": 2,  "kcn": 3, "name": 0, "Option": 0, "dispPnltVal": 1, "RotPnltVal": 2
    }
    for arg_name, arg_indx in arg_names.items():
        args_kw[arg_name] = kwargs.pop(arg_name, args[arg_indx] if len(args) >= arg_indx + 1 else "")

    args_kw["secid"] = secid

    if Keyword  == "NORM" or nx or ny:
        cmd = "SECMODIF, {secid}, NORM, {nx}, {ny}, {nz}, {kcn}".format(**args_kw)
    elif Keyword  == "NAME" or name:
        cmd = "SECMODIF, {secid}, NAME, {name}".format(**args_kw)
    else:
        raise ValueError("We couldn't map the arguments given....")
    
    print(cmd)

secmodif("self", 1, "NORM", nx=1)
secmodif("self", 1, "NORM", 1, kcn=2)

It does respect the compatibility of the current API, and we do not have to bother about the converter. The signature si very clean, but we depend on the docs for explaining all the arguments. Intellisense might not help much in this case (maybe we can do something with typing module).

Opinions

I personally like more the * option, it is more elegant, and cleaner. But it does break the compatibility with the current Python code.

What do you think @clatapie @RobPasMue @koubaa @mikerife @mcMunich @pmaroneh??

@germa89
Copy link
Collaborator

germa89 commented Dec 17, 2024

@germa89 - this PR should be "automated". I don't understand the reason to make local changes.

Very true... I do not expect @clatapie applies the changes rather she is aware of them, so she can fix the package accordingly.

@germa89
Copy link
Collaborator

germa89 commented Dec 17, 2024

With respect to the arguments that have the same exact description, I will refer to the current discussion #3385 (comment)

@clatapie
Copy link
Contributor Author

Answering @germa89's comment:

additional_arguments option

additional_arguments needs to be used as follow:

mapdl.secmodif(1, "NORM", "2,3,2,2")

Thus, NX, NY, NZ and KCN are not mentioned in the current implementation.

This is due to the Python source code as reminded by @germa89:

def secmodif(self, secid="", kywrd="", additional_arguments="", **kwargs):
    # implementation
    command = f"SECMODIF,{secid},{kywrd},{additional_arguments}"
    return self.run(command)

With previous example, command == SECMODIF,1,NORM,2,3,2,2

I agree the API is not ideal this way but it enables passing all the needed values.

*-method

The * method is interesting because it would avoid a lot of issues.
However, I would not make those changes at the pyconverter-xml2py level but I would modify the functions one by one and add them as custom_functions, at least for now.
IMO, parsing the initial file to obtain the proposed code might not be that easy. Especially, this format appears in only 4 methods in all the converted PyMAPDL commands.
We can open an issue to keep a track of this enhancement

Proposed solution

Overall, as mentioned in the second section, I would recommend customizing one by one the 4 relevant functions with the *-method proposed by @germa89.
In the future, if we discover the issue appears quite often, a modification could be implemented.

@RobPasMue
Copy link
Member

RobPasMue commented Dec 17, 2024

My 2 cents... the problem with the The * method and The *args option is that it is not easy to automate IMO. If you are willing to pay the price and have them as custom functions which you implement ad-hoc... then I would go with The * method. Option The *args option seems overly complicated assuming you are already doing a custom function.

@MaxJPRey
Copy link
Contributor

MaxJPRey commented Dec 24, 2024

I agree with your approach too @clatapie.

The ROI seems low for now regarding the automation. It could even be difficult to maintain at first.
We can always come back on it later if our strategy happens to not be sustainable. This could be done in futur versions.

@github-actions github-actions bot added the examples Publishing PyMAPDL examples label Jan 8, 2025
@github-actions github-actions bot removed the examples Publishing PyMAPDL examples label Jan 8, 2025
@clatapie
Copy link
Contributor Author

clatapie commented Jan 9, 2025

A warning feature has been added in case some functions need specific warning at the top of its docstring.
Here is an example of how it can be used:
image

@github-actions github-actions bot removed the CI/CD Related with CICD, Github Actions, etc label Jan 9, 2025
@germa89
Copy link
Collaborator

germa89 commented Jan 14, 2025

@RobPasMue @MaxJPRey @clatapie since the MAPDL commands are pretty stable, I do not think we will be expecting many changes in the custom functions, so I would say that priorities should be:

  • MAPDL API compatibility (MAPDL users feedback)
  • Users feedback (PyMAPDL users feedback)
  • Translator module support
  • Maintainability

There is always time to break the API, I guess?

@RobPasMue
Copy link
Member

@RobPasMue @MaxJPRey @clatapie since the MAPDL commands are pretty stable, I do not think we will be expecting many changes in the custom functions, so I would say that priorities should be:

  • MAPDL API compatibility (MAPDL users feedback)
  • Users feedback (PyMAPDL users feedback)
  • Translator module support
  • Maintainability

There is always time to break the API, I guess?

I might be missing something. What are you proposing with this priority list? I think I got lost somewhere...

BTW - I do not agree on having Maintainability the last element of a priority list anyway 😄 maintainability should be at the core of whatever we decide, because it will make our lives easier in the future.

@germa89
Copy link
Collaborator

germa89 commented Jan 14, 2025

(I was still building on my previous comment, I hit enter too fast)

I think we have a choice to make here... maintainability (leave everything as the converter gives it) or user experience (better docs, better arguments handling). While I have always priorised both, I rarely had to choose one or another. So I think for this specific context, I am priorizing the list of items in my previous comment.

I do understand that PyAnsys core team might be more interested in maintainability because you manage way too many things. But I think PyMAPDL developers should focus on MAPDL and PyMAPDL users and their user experience, and since the MAPDL commands are not expected to change much, I rather do the initial work in detrimental of automation.

I am still not sure what is the best as the * methods breaks the translator module and the current API. So I think we should go for custom functions (even if it has more work).

I would love to see something like this for SECMODIF:

def secmodif(self, secid, keyword, nx="", ny="", nz="", kcn="", name="", name_new="", option="", dispPnltVal="", RotPnltVal="", **kwargs):
    """Modifies a pretension section

    APDL Command: SECMODIF

    This command have specific signature depending on the values of the given
    arguments.
    - If `Keyword = NORM`:
        SECMODIF,SECID, NORM, NX, NY, NZ, KCN
    - If `Keyword = NAME`:
        SECMODIF,SECID, NAME, Name
    - If `Keyword = JOIN`:
        SECMODIF,SECID, JOIN, Option, dispPnltVal, RotPnltVal

    Parameters
    ----------
    secid
        Unique section number. This number must already be assigned to a
        section.

    norm
        Keyword specifying that the command will modify the pretension
        section normal direction.

    nx, ny, nz
        Specifies the individual normal components to modify.

    kcn
        Coordinate system number. This can be either 0 (Global Cartesian),
        1 (Global Cylindrical) 2 (Global Spherical), 4 (Working Plane), 5
        (Global Y Axis Cylindrical) or an arbitrary reference number
        assigned to a coordinate system.

    name
        Change the name of the specified pretension section.
    
    name_new
        The new name to be assigned to the pretension section.

    join
        Set command actions to apply to joint sections only.
    
    option
        PNLT -- Modify penalty factors for the specified section.
    
    dispPnltVal
        Penalty value for displacement-based constraints:
        - `> 0` -- The number is used as a scaling factor to scale the
            internally calculated penalty values.
        - `< 0` -- The absolute value of the number is used as the penalty
            factor in calculations.
    
    RotPnltVal
        Penalty value for rotation-based constraints.
        - `> 0` -- The number is used as a scaling factor to scale the
            internally calculated penalty values.
        - `< 0` -- The absolute value of the number is used as the penalty
            factor in calculations.


    Notes
    -----
    The SECMODIF command either modifies the normal for a specified
    pretension section, or changes the name of the specified pretension
    surface.
    """
    # Sanity checks
    if keyword.upper() not in ["NORM", "NAME", "JOIN"]:
        raise ValueError(f"The given argument 'keyword' ({keyword}) is not valid.")

    if keyword  == "NORM":
        cmd = f"SECMODIF, {secid}, NORM, {nx}, {ny}, {nz}, {kcn}"
    elif keyword  == "NAME":
        cmd = f"SECMODIF, {secid}, NAME, {name or nx}, {name_new or ny}"
    elif keyword == "JOIN":
        cmd = f"SECMODIF, {secid}, JOIN, {option or nx},{dispPnltVal or ny},{RotPnltVal or nz}"
    else:
        raise ValueError("We couldn't map the arguments given....")
    
    self.run(cmd, **kwargs)

The doc string is slightly modified, just adding some info about the signatures in the extended summary part (before parameters).
The code is bit more complex, but I do believe it won't change much, and it can be included in a wrapped function using functools.wrap, this way it wont be much affected by docstring changes.

@RobPasMue
Copy link
Member

I would leave it up to @clatapie to decide since she is doing the work mostly, but for me I would keep any kind of custom function to the minimum (i.e. reduce their number as much as possible). Mostly because they will go outdated and it will be on the maintainers to keep them up to date.

The whole point of automating the API generation process (which was the initial purpose of all these efforts) was to free up time for maintainers and developers to work on actual problems inside PyMAPDL. Not to generate more work on the long run IMO.

In any case, we need to make progress with this. We have been iterating for too long and we don't have anything merged or close to be merged yet. We should be doing more iterations rather than trying to get it 100% right in the first shot.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
dependencies documentation Documentation related (improving, adding, etc) enhancement Improve any current implemented feature maintenance General maintenance of the repo (libraries, cicd, etc) new feature Request or proposal for a new feature
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants