diff --git a/.gitignore b/.gitignore index b6429eebcb..a3bd2f86c1 100644 --- a/.gitignore +++ b/.gitignore @@ -164,3 +164,4 @@ cython_debug/ # Ignore rendered examples doc/source/examples/ doc/source/API/_autosummary/ +doc/source/autoapi \ No newline at end of file diff --git a/doc/source/conf.py b/doc/source/conf.py index 25c2ff31c9..264acad35a 100755 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -33,7 +33,7 @@ # Intersphinx mapping intersphinx_mapping = { - "python": ("https://docs.python.org/dev", None), + "python": ("https://docs.python.org/3", None), "numpy": ("https://numpy.org/devdocs", None), "matplotlib": ("https://matplotlib.org/stable", None), "imageio": ("https://imageio.readthedocs.io/en/stable", None), @@ -50,7 +50,7 @@ # general "GL06", # Found unknown section "GL07", # Sections are in the wrong order. - "GL08", # The object does not have a docstring + # "GL08", # The object does not have a docstring "GL09", # Deprecation warning should precede extended summary "GL10", # reST directives {directives} must be followed by two colons # Summary diff --git a/doc/source/getting-started/index.rst b/doc/source/getting-started/index.rst index edec344234..250be096ef 100644 --- a/doc/source/getting-started/index.rst +++ b/doc/source/getting-started/index.rst @@ -1,50 +1,71 @@ Getting started =============== +************ Installation -~~~~~~~~~~~~ +************ -This package is not yet available on the public PyPI, but you can still install -it using ``pip`` from the private PyPI repository. +Python module +~~~~~~~~~~~~~ -The following on Windows: +The ``ansys.dyna.core`` package currently supports Python 3.8 through +Python 3.10 on Windows, Mac OS, and Linux. -.. code:: +Install the latest release from +`PyPI `_ with: - set PYANSYS_PYPI_PRIVATE_PAT= - set INDEX_URL=https://%PYANSYS_PYPI_PRIVATE_PAT%@pkgs.dev.azure.com/pyansys/_packaging/pyansys/pypi/simple/ - python -m pip install ansys-dyna-core --index-url %INDEX_URL% +.. code:: console -And if you are running Linux: + pip install ansys-dyna-core -.. code:: +Alternatively, install the latest from +`PyDyna GitHub `_ via: - PYANSYS_PYPI_PRIVATE_PAT= - export INDEX_URL='https://$PYANSYS_PYPI_PRIVATE_PAT@pkgs.dev.azure.com/pyansys/_packaging/pyansys/pypi/simple/' - python -m pip install ansys-dyna-core --index-url $INDEX_URL +.. code:: console + + pip install git+https://github.com/pyansys/pydyna.git + -Email your friendly PyAnsys team member for the ``PYANSYS_PYPI_PRIVATE_PAT`` -at `pyansys.core@ansys.com `_ or send a message via Teams. +For a local *development* version, install with: -**Installing from git** +.. code:: console -If you have ``git`` installed and want the bleeding edge version: + git clone https://github.com/pyansys/pydyna.git + cd pydyna + pip install -e . -.. code:: +This allows you to install the ``ansys-dyna-core`` module +and modify it locally and have the changes reflected in your setup +after restarting the Python kernel. - pip install -U git+https://github.com/pyansys/pyDyna@main +Offline installation +~~~~~~~~~~~~~~~~~~~~ +If you lack an internet connection on your install machine, the recommended way +of installing PyDyna is downloading the wheelhouse archive from the +`Releases Page `_ for your corresponding +machine architecture. -You need to be logged into GitHub locally and be a member of the `PyAnsys Organization `_. +Each wheelhouse archive contains all the Python wheels necessary to install +PyDyna from scratch on Windows and Linux for Python 3.8 through 3.11. You can install +this on an isolated system with a fresh Python or on a virtual environment. -Alternatively, if you need to modify the repository locally (or want to -do local development), you can clone it and install it in "development" mode with: +For example, on Linux with Python 3.8, unzip it and install it with the following: -.. code:: +.. code:: console - git clone https://github.com/pyansys/pyDyna - cd pyDyna - pip install -e . + unzip ansys-dyna-core-v0.3.1-wheelhouse-ubuntu-latest-3.8.zip wheelhouse + pip install ansys-dyna-core -f wheelhouse --no-index --upgrade --ignore-installed + +If you're on Windows with Python 3.8, unzip to a ``wheelhouse`` directory and +install using the preceding command. + +Consider installing using a `virtual environment `_. + +.. include:: ../../../docker/pre/README.rst +.. include:: ../../../docker/solver/README.rst -Note the ``-e`` flag, which denotes that you are in development mode. -You can make changes in the local ``pyDyna`` and have them reflected -in your local install of PyDyna. +.. LINKS +.. _pydyna_pypi: https://pypi.org/projects/ansys-dyna-core/ +.. _pydyna_releases: https://github.com/ansys/pydyna/releases +.. _pydyna_issues: https://github.com/ansys/pydyna/issues +.. _using_venv: https://docs.python.org/3/library/venv.html \ No newline at end of file diff --git a/doc/source/user-guide/index.rst b/doc/source/user-guide/index.rst index eccbf28f7d..0ad53c787d 100644 --- a/doc/source/user-guide/index.rst +++ b/doc/source/user-guide/index.rst @@ -26,12 +26,3 @@ leaving a Python environment. Visit the `DPF-Post Documentation `_ for a detailed description of the package - -.. toctree:: - :hidden: - - pydyna_pre - pydyna_solver - pydyna_post - - diff --git a/docker/pre/README.rst b/docker/pre/README.rst index e46ec450d4..eeeccf4e14 100644 --- a/docker/pre/README.rst +++ b/docker/pre/README.rst @@ -1,13 +1,17 @@ -Create your own pydyna-pre service docker container -=================================================== +Build pydyna-pre service docker container +::::::::::::::::::::::::::::::::::::::::: The pydyna-pre service Docker containers can be easily built by following these steps. -Inside this folder, the instructions (i.e. ``Dockerfile`` files) for -building the pydyna-pre service Docker containers are made available. +To build the docker image you will need to clone pydyna repo locally: -* ``Dockerfile``: this file builds the Linux-based Docker image. +.. code:: console + + git clone https://github.com/pyansys/pydyna.git + cd pydyna + +* ``docker/pre/Dockerfile``: this file builds the Linux-based Docker image. Prerequisites ^^^^^^^^^^^^^ @@ -15,29 +19,20 @@ Prerequisites * Ensure that ``docker`` is installed in your machine. If you do not have ``docker`` available, please refer to the `official Docker site `_. - Note that the container can also be started on Windows if the Docker Desktop has been installed. - How to install the Docker Desktop: https://docs.docker.com/desktop/install/windows-install/ -* Download the latest release artifacts. You can do this as follows: +* Download the latest release artifacts for the Linux + Docker container. You can do this as follows: * Latest Linux artifacts: `linux-binaries.zip `_ -* Move these ``.zip`` files to the current location (i.e. ``/docker/pre``). - -Starting the docker container -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -There are two ways to start docker container. - -1.bulid image and run container ->>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> +* Move these ``.zip`` files to the current location (i.e. ``/docker``). Building the Docker images -:::::::::::::::::::::::::: +^^^^^^^^^^^^^^^^^^^^^^^^^^ In order to build your images, follow the next instructions: -* Locate yourself at ``/docker/pre`` in your terminal. +* Locate yourself at ``/docker`` in your terminal. * Run the following Docker command: .. code:: bash @@ -61,13 +56,13 @@ In order to build your images, follow the next instructions: >>> ...... ...... ............ .............. ...... Run the image as a container -:::::::::::::::::::::::::::: +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ * Run the following Docker command: .. code:: bash - docker run -d -p 50051:50051 ghcr.io/ansys/ls-pre + docker run -d -p 50051:50051 ghcr.io/ansys/ls-pre . * Check that the image has been created successfully. @@ -76,19 +71,4 @@ Run the image as a container >>> CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES - >>> c77ffd67f9fa ghcr.io/ansys/ls-pre "python3 ./linux-bin…" 7 seconds ago Up 7 seconds 0.0.0.0:50051->50051/tcp, :::50051->50051/tcp hardcore_margulis - - -2.Start the container from docker-compose.yml file ->>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> - -Make sure the docker compose have been installed on your computer. -For more information: https://docs.docker.com/compose/install/ - -* Locate yourself at ``/docker/pre`` in your terminal. -* Run the following Docker command: - - .. code:: bash - - docker compose up -d - \ No newline at end of file + >>> c77ffd67f9fa ghcr.io/ansys/ls-pre "python3 ./linux-bin…" 7 seconds ago Up 7 seconds 0.0.0.0:50051->50051/tcp, :::50051->50051/tcp hardcore_margulis \ No newline at end of file diff --git a/docker/solver/Dockerfile b/docker/solver/Dockerfile new file mode 100644 index 0000000000..7b43ed5193 --- /dev/null +++ b/docker/solver/Dockerfile @@ -0,0 +1,87 @@ +FROM centos:7 +# +# The order of the lines in here should be (as much as possible) in +# an order that will create the same series of intermediate images +# no mater what version of dyna we are using. This will speed up +# experiments when creating containers over and over. Ordering the +# commands this way makes the Dockerfile a bit more confusing, because +# for example we make all the directories up top, but don't put things +# in them until further down. And some environment variables are near +# the top, but others near the bottom + +LABEL "com.ansys.description"="Ansys MPPDYNA with gRPC server" + +# install some missing stuff we want/need + +RUN yum -y install openssh-clients openssh-server bind-utils sudo python3 +RUN python3 -m pip install --upgrade pip +RUN python3 -m pip install grpcio +RUN python3 -m pip install grpcio-tools +# +ENV USER mpirun +ENV HOME /home/mpirun +ENV LD_LIBRARY_PATH /ansys_inc/lib +ENV LSTC_LICENSE network +ENV LSTC_LICENSE_SERVER license +ENV SSHDIR ${HOME}/.ssh/ + + +RUN groupadd ${USER} +RUN useradd -g ${USER} -d ${HOME} ${USER} && \ + echo "${USER} ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers +# +RUN mkdir -p /ansys_inc/lib +RUN mkdir -p /rundir +RUN mkdir /var/run/sshd +RUN mkdir -p ${SSHDIR} +RUN chown -R ${USER}:${USER} /rundir +RUN chmod -R 755 /rundir +WORKDIR /rundir + +# set up the runtime environment variables for +# dyna + +RUN echo "export LD_LIBRARY_PATH=/ansys_inc/lib:/opt/openmpi/lib" > ${HOME}/.bashrc +# Adding these causes problems because they can't be overridden +# via the "environment" attribute in a docker-compose file. +# The ENV commands above come through as defaults, but can be +# overridden (to use the ANSYS license, or a different license server) +# +# RUN echo "export LSTC_LICENSE=network" >> ${HOME}/.bashrc +# RUN echo "export LSTC_LICENSE_SERVER=license" >> ${HOME}/.bashrc +# +# Get ssh properly set up +# +RUN sed -i 's/PermitRootLogin without-password/PermitRootLogin yes/' /etc/ssh/sshd_config +# SSH login fix. Otherwise user is kicked off after login +RUN sed 's@session\s*required\s*pam_loginuid.so@session optional pam_loginuid.so@g' -i /etc/pam.d/sshd +# +EXPOSE 22 +CMD ["/usr/sbin/sshd", "-D"] +# +# Everything above here should not depend on the version of DYNA or the MPI we are using +# and so should behave nicely as regards the Docker image cache. Below here not so much +# +ENV PATH /opt/openmpi/bin:${PATH} +RUN echo "export PATH=/opt/openmpi/bin:\${PATH}" >> ${HOME}/.bashrc + +ADD ssh/config ${SSHDIR}/config +ADD ssh/id_rsa ${SSHDIR}/id_rsa +ADD ssh/id_rsa.pub ${SSHDIR}/id_rsa.pub +ADD ssh/id_rsa.pub ${SSHDIR}/authorized_keys +RUN ssh-keygen -A + +RUN chmod -R 600 ${SSHDIR}* && \ + chown -R ${USER}:${USER} ${SSHDIR} + +RUN chown -R ${USER}:${USER} ${HOME} + +# Copy the openmpi libraries + +RUN mkdir -p /opt +COPY mpi /opt/openmpi + +# The executable will go in /ansys_inc, and the +# ifort runtime libraries in /ansys_inc/lib + +COPY docker_dir /ansys_inc diff --git a/docker/solver/README.rst b/docker/solver/README.rst new file mode 100644 index 0000000000..b29bcd6f34 --- /dev/null +++ b/docker/solver/README.rst @@ -0,0 +1,67 @@ +Build pydyna-solver service docker container +:::::::::::::::::::::::::::::::::::::::::::: + +The pydyna-solver service Docker containers can be easily built by following +these steps. + +* ``docker/solver/Dockerfile``: this file builds the Linux-based Docker image. + +Prerequisites +^^^^^^^^^^^^^ + +* Ensure that ``docker`` is installed in your machine. + If you do not have ``docker`` available, please refer to the + `official Docker site `_. + +* If you are building the image on Windows, you will need to have + Windows Subsystem for Linux (WSL) installed. The instructions for that can be found `here ` + +* Download the latest release artifacts for the Linux + Docker container. You can do this as follows: + + * Latest Linux artifacts: `mppdyna_docker_centos7.zip `_ + +* Move these ``.zip`` files to a local directory ``local_image_build_dir``. + +Building the Docker images +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +In order to build your images, follow the next instructions: + +* cd to ``local_image_build_dir``. +* Run the following Docker command: + + .. code:: bash + + ./do_build + +* Check that the image has been created successfully. You should see an output similar + to this one when running the following command: + + .. code:: bash + + docker images + + >>> REPOSITORY TAG IMAGE ID CREATED SIZE + >>> dyna_solver_v04 latest defbadbeee8e 16 minutes ago 730MB + >>> ...... ...... ............ .............. ...... + +Run the image as a container +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Edit the docker-compose.yml file and replace ```` with the correct license server hosting the DYNA license. + If you are using Ansy Flexlm license + +* Run the following Docker command: + + .. code:: bash + + docker-compose up + +* Check that the image has been created successfully. + + +.. code:: bash + + >>> CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES + >>> be84c95db31d dyna_solver_v04 "/ansys_inc/server.p…" 18 minutes ago Up 8 seconds 22/tcp, 0.0.0.0:5000->5000/tcp mppdyna_docker_centos7_dyna_1 diff --git a/docker/solver/do_build b/docker/solver/do_build new file mode 100644 index 0000000000..99df1bdb95 --- /dev/null +++ b/docker/solver/do_build @@ -0,0 +1,13 @@ +#!/bin/sh +# +# Do some basic ssh setup +# +rm -rf ssh +mkdir ssh +ssh-keygen -q -b 2048 -f ssh/id_rsa -N "" +echo "Host *" > ssh/config +echo " StrictHostKeyChecking no" >> ssh/config +# +# Build container +# +docker build -t dyna_solver_v04 . diff --git a/docker/solver/docker-compose.yml b/docker/solver/docker-compose.yml index d65afde474..0eef2a2fac 100644 --- a/docker/solver/docker-compose.yml +++ b/docker/solver/docker-compose.yml @@ -1,11 +1,9 @@ -version: "3.8" +version: "3.3" services: dyna: - image: ghcr.io/ansys/dynasolver:0.3 + image: dyna_solver_v04 networks: - dyna_internal - deploy: - replicas: 1 volumes: - /rundir cap_add: @@ -15,8 +13,8 @@ services: published: 5000 mode: ingress user: mpirun - entrypoint: ["/ansys_inc/server.py","dyna"] environment: - - LSTC_LICENSE_SERVER=lvrpanda.ansys.com + - LSTC_LICENSE_SERVER= + entrypoint: ["/ansys_inc/server.py","dyna"] networks: - dyna_internal: + dyna_internal: \ No newline at end of file diff --git a/examples/Airbag/airbag_deploy.py b/examples/Airbag/airbag_deploy.py index 85249d01da..f06f4fe5d1 100644 --- a/examples/Airbag/airbag_deploy.py +++ b/examples/Airbag/airbag_deploy.py @@ -1,5 +1,4 @@ """ -.. _ref_airbag_deploy: Airbag deploy example --------------------- @@ -65,7 +64,7 @@ # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Dynasolution class is like a workflow orchestrator. # It inherits methods from other classes and helps create a complete workflow. -# "set_termination" method here is used to set the termination time to 0.03 in *CONTROL_TERMINATION. +# "set_termination" method here is used to set the termination time to 0.03 in *CONTROL_TERMINATION*. # DynaMech class automatically generates the common control cards used in # explicit problems. CONTROL_ACCURACY, CONTACT, BULK VISCOCITY, CONTACT # are all automatically generated @@ -75,8 +74,8 @@ airbag_solution.add(airbagdeploy) ############################################################################### -# Define *AIRBAG_SIMPLE_AIRBAG_MODEL -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Define *AIRBAG_SIMPLE_AIRBAG_MODEL* +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # DynaMech class has Airbag function that can be used to create this keyword. # LSDYNA has many different AIRBAG models. Only SIMPLE_AIRBAG_MODEL is supported # by pydyna at this moment. Please contact us if there is an urgent need for other @@ -95,16 +94,16 @@ airbagdeploy.add(airbag) ############################################################################### -# Define *RIGIDWALL_PLANAR -# ~~~~~~~~~~~~~~~~~~~~~~~~ +# Define *RIGIDWALL_PLANAR* +# ~~~~~~~~~~~~~~~~~~~~~~~~~ # Infinite planar rigidwall is generated by defining the coordinates of the heat vector # and the tail vector of the plane. rigidwall = RigidwallPlanar(Point(0, 0, 0), Point(0, 1, 0), coulomb_friction_coefficient=0.5) airbagdeploy.add(rigidwall) ############################################################################### -# Define *CONTACT_NODES_TO_SURFACE -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Define *CONTACT_NODES_TO_SURFACE* +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # A contact NODES_TO_SURFACE is defined here by passing a master set and a slave part set. contact = Contact(category=ContactCategory.NODES_TO_SURFACE) diff --git a/examples/Airbag/airbag_post.py b/examples/Airbag/airbag_post.py index 9fa403cfad..875771256e 100644 --- a/examples/Airbag/airbag_post.py +++ b/examples/Airbag/airbag_post.py @@ -1,17 +1,16 @@ """ -.. _ref_airbag_deploy_post: Airbag deploy post processing example ------------------------------------- This example show how to animate the d3plot and display the stress on the airbag. """ -# from ansys.dpf import core as dpf -# from ansys.dpf.core import examples +from ansys.dpf import core as dpf +from ansys.dpf.core import examples ############################################################################### # Connect to DPF # ~~~~~~~~~~~~~~ -# dpf.connect_to_server() +dpf.connect_to_server() ############################################################################### # Load the model @@ -19,39 +18,39 @@ # Load the model and print the contents of the model. All parts in the model are shell parts. # Model info lists the result components as well as the number of states available in the d3plot # -# ds = dpf.DataSources() -# ds.set_result_file_path(r'D:\PYDYNA_BETA_V.0.1\example-data\pydyna\Airbag\d3plot', 'd3plot') -# model = dpf.Model(ds) -# print(model) +""" ds = dpf.DataSources() +ds.set_result_file_path(r'D:\PYDYNA_BETA_V.0.1\example-data\pydyna\Airbag\d3plot', 'd3plot') +model = dpf.Model(ds) +print(model) """ ############################################################################### # Let's extract the stress on all the parts. The stress field container is scoped to all time frequencies # so as to be able to animate the change in stress on the airbag fabric. # -# stress = model.results.stress.on_all_time_freqs() -# stress.inputs.data_sources(ds) -# stress.inputs.requested_location.connect("Nodal") -# fieldsStr = stress.outputs.fields_container() +""" stress = model.results.stress.on_all_time_freqs() +stress.inputs.data_sources(ds) +stress.inputs.requested_location.connect("Nodal") +fieldsStr = stress.outputs.fields_container()""" ############################################################################### # Since the shell stress is reported at three through thickness points as default # in the d3plot file, the next few lines depicts how the stress # can be extracted on the mid integration point. # -# shell_layer_extract = dpf.operators.utility.change_shell_layers() -# shell_layer_extract.inputs.fields_container.connect(fieldsStr) -# shell_layer_extract.inputs.e_shell_layer.connect(dpf.common.shell_layers.mid.value) -# fields_top = shell_layer_extract.outputs.fields_container_as_fields_container() +""" shell_layer_extract = dpf.operators.utility.change_shell_layers() +shell_layer_extract.inputs.fields_container.connect(fieldsStr) +shell_layer_extract.inputs.e_shell_layer.connect(dpf.common.shell_layers.mid.value) +fields_top = shell_layer_extract.outputs.fields_container_as_fields_container() """ ############################################################################### # Plot the deformed state at 9ms # -# N = fields_top[19] -# D = model.results.displacement(time_scoping=[19]).eval() -# N.plot(deform_by=D[0],show_edges=False) +""" N = fields_top[19] +D = model.results.displacement(time_scoping=[19]).eval() +N.plot(deform_by=D[0],show_edges=False) """ ############################################################################### # Finally display the stress field and set the mesh to deform by the displacement of the nodes. # -# disp = model.results.displacement.on_all_time_freqs.eval() -# fields_top.animate(deform_by=disp,show_edges=False) \ No newline at end of file +""" disp = model.results.displacement.on_all_time_freqs.eval() +fields_top.animate(deform_by=disp,show_edges=False) """ \ No newline at end of file diff --git a/examples/EM/em_post.py b/examples/EM/railgun/em_post.py similarity index 63% rename from examples/EM/em_post.py rename to examples/EM/railgun/em_post.py index 42c6823a93..e6b2442044 100644 --- a/examples/EM/em_post.py +++ b/examples/EM/railgun/em_post.py @@ -6,13 +6,13 @@ This example show how to animate the d3plot and display the electric field in the railgun. """ -# from ansys.dpf import core as dpf -# from ansys.dpf.core import examples +from ansys.dpf import core as dpf +from ansys.dpf.core import examples ############################################################################### # Connect to DPF # ~~~~~~~~~~~~~~ -# dpf.connect_to_server() +dpf.connect_to_server() ############################################################################### # Load the model @@ -20,10 +20,10 @@ # Load the model and print the contents of the model. Since this is a multiphysics problem # the default results returned is the structural results. # -# ds = dpf.DataSources() -# ds.set_result_file_path(r'D:\PYDYNA_BETA_V.0.1\example-data\pydyna\EM\d3plot', 'd3plot') -# model=dpf.Model(ds) -# print(model) +ds = dpf.DataSources() +ds.set_result_file_path(r'D:\PYDYNA_BETA_V.0.1\example-data\pydyna\EM\d3plot', 'd3plot') +model=dpf.Model(ds) +print(model) ############################################################################### # Get MS mesh @@ -33,23 +33,23 @@ # Since the meshes container contains the mesh for all time states, we need to scope it to the # desired timestate. # -# meshOP = dpf.Operator("lsdyna::ms::meshes_provider") -# meshOP.inputs.data_sources.connect(ds) -# timeScoping = dpf.Scoping() -# timeScoping.ids = list(range(1, 21)) -# meshOP.inputs.time_scoping.connect(timeScoping) -# meshes = meshOP.outputs.meshes() -# mesh = meshes.get_mesh({'time':1}) +meshOP = dpf.Operator("lsdyna::ms::meshes_provider") +meshOP.inputs.data_sources.connect(ds) +timeScoping = dpf.Scoping() +timeScoping.ids = list(range(1, 21)) +meshOP.inputs.time_scoping.connect(timeScoping) +meshes = meshOP.outputs.meshes() +mesh = meshes.get_mesh({'time':1}) ############################################################################### # MS Result Info # ~~~~~~~~~~~~~~ # "result_info_provider" lets us list all the variables available in the container. # -# resultInfoOp = dpf.Operator("lsdyna::ms::result_info_provider") -# resultInfoOp.inputs.data_sources(ds) -# result_info = resultInfoOp.outputs.result_info() -# print(result_info) +resultInfoOp = dpf.Operator("lsdyna::ms::result_info_provider") +resultInfoOp.inputs.data_sources(ds) +result_info = resultInfoOp.outputs.result_info() +print(result_info) ############################################################################### # Get Field Variable from the available results @@ -60,14 +60,14 @@ # In this case Domain=0 and Variable=1014 represents the electric field as seen from the output above. # electric_fielddomain_id__0__variable_id__1014: Elemental Electric Field(domain Id: 0, Variable Id: 1014) # -# ms_op = dpf.Operator("lsdyna::ms::results") -# ms_op.inputs.data_sources(ds) -# ms_op.inputs.time_scoping([44]) -# fields = ms_op.outputs.results() -# for f in fields: -# f.meshed_region=mesh -# field0 = fields.get_field({"domain_id":0, "variable_id":1014}) -# print(field0) +ms_op = dpf.Operator("lsdyna::ms::results") +ms_op.inputs.data_sources(ds) +ms_op.inputs.time_scoping([44]) +fields = ms_op.outputs.results() +for f in fields: + f.meshed_region=mesh +field0 = fields.get_field({"domain_id":0, "variable_id":1014}) +print(field0) ############################################################################### # Plot the Electric Field @@ -75,9 +75,9 @@ # Now that we have the field of interest, we can plot it at any given state. In order to display the mesh at that # state, we need to extract the displacement and deform the field by the displacement field which is shown below. # -# disp = model.results.displacement(time_scoping=[44]).eval() -# c_pos = [(346.9131285482345, 313.2551112639297, 39.299903249251045), -# (101.24994659423828, 0.0, 0.0), -# (-0.09694442015878338, -0.04868966261897064, 0.9940981320544406)] -# field0.plot(deform_by=disp[0],show_edges=False,cpos=c_pos) +disp = model.results.displacement(time_scoping=[44]).eval() +c_pos = [(346.9131285482345, 313.2551112639297, 39.299903249251045), + (101.24994659423828, 0.0, 0.0), + (-0.09694442015878338, -0.04868966261897064, 0.9940981320544406)] +field0.plot(deform_by=disp[0],show_edges=False,cpos=c_pos) diff --git a/examples/EM/em_railgun.py b/examples/EM/railgun/em_railgun.py similarity index 100% rename from examples/EM/em_railgun.py rename to examples/EM/railgun/em_railgun.py diff --git a/examples/Explicit/belted_dummy.py b/examples/Explicit/belted_dummy.py index 01b9385099..936f859b72 100644 --- a/examples/Explicit/belted_dummy.py +++ b/examples/Explicit/belted_dummy.py @@ -1,5 +1,4 @@ """ -.. _ref_belted_dummy: Belted dummy example ==================== @@ -61,7 +60,7 @@ # Start the Solution workflow # ~~~~~~~~~~~~~~~~~~~~~~~~~~~ # NODES and ELEMENTS are read in from the "belted_dummy.k" file. This file also has the -# *PART defined in it but the section and material fields are empty to begin with +# *PART* defined in it but the section and material fields are empty to begin with fns = [] path = examples.belted_dummy + os.sep diff --git a/examples/Implicit/camry_rc.py b/examples/Implicit/camry_rc.py index 8619798df1..aee61ddd83 100644 --- a/examples/Implicit/camry_rc.py +++ b/examples/Implicit/camry_rc.py @@ -1,5 +1,4 @@ """ -.. _ref_implicit: Implicit Example ===================== @@ -189,10 +188,10 @@ ) ############################################################################### -# Assining Section and Material Properties -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Assigning Section and Material Properties +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Once all the materials are explicitly defined, these material IDs needs to be cross-referenced -# in the *PART card. set_material() method is used for this. Since many parts share common materials +# in the *PART* card. set_material() method is used for this. Since many parts share common materials # the assignment happens within a loop. While within the loop, set_element_formulation() method # is called to assign the elform for the beam and the shell elements. Accordingly either the beam # diameter or the shell thickness is also defined. To identify the part ID that has a particular material type @@ -253,7 +252,7 @@ # Spotwelds and Nodal Rigid Bodies # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Again, camry_rc_data.py contains the predefined node pairs and node sets required for -# *CONSTRAINED_SPOTWELD and *CONSTRAINED_NODAL_RIGID_BODY definitions. We are looping through +# *CONSTRAINED_SPOTWELD* and *CONSTRAINED_NODAL_RIGID_BODY* definitions. We are looping through # these lists to generate the appropriate keywords. for sw in spotweld: camry.constraints.create_spotweld(nodeid1=sw[0], nodeid2=sw[1]) @@ -265,11 +264,13 @@ # Define Contacts # ~~~~~~~~~~~~~~~ # There are three Contacts defined in this model. +# # 1. Automatic Single surface contact for the BIW self contact # 2. Surface to Surface Contact between the platen and the BIW # 3. Tied contact for the Spotweld beams +# # The ContactSurface() method here sets the SSTYPE and MSTYPE. -# PartSet() method accepts the name of a list and converts it to *PART_SET_LIST. +# PartSet() method accepts the name of a list and converts it to *PART_SET_LIST*. # Notice how the contact type and category can be used to create the three # different type of contacts for this model. selfcontact = Contact(type=ContactType.AUTOMATIC) diff --git a/examples/NVH/frf_plate_damping.py b/examples/NVH/frf_plate_damping.py index 4063a024cc..c335336575 100644 --- a/examples/NVH/frf_plate_damping.py +++ b/examples/NVH/frf_plate_damping.py @@ -1,5 +1,4 @@ """ -.. _ref_frf: FRF for a rectangular plate =========================== @@ -44,7 +43,7 @@ ############################################################################### # Import the initial mesh data(nodes and elements) # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -# Mesh data is imported which includes the *NODE, *ELEMENT_ and *PART cards predefined +# Mesh data is imported which includes the *NODE*, *ELEMENT_* and *PART* cards predefined fns = [] path = examples.nvh_frf_plate_damping + os.sep fns.append(path + "frf_plate_damping.k") @@ -69,7 +68,7 @@ ############################################################################### # Frequency Domain Cards # ~~~~~~~~~~~~~~~~~~~~~~ -# *FREQUENCY_DOMAIN_FRF is used to compute the frequency response function due to nodal excitations. +# *FREQUENCY_DOMAIN_FRF* is used to compute the frequency response function due to nodal excitations. # In this case a base velocity is define as an input at node 131. The base acceleration response is measured at # nodes 131 and 651. The max natural frequency employed in FRF is limited to 2000Hz. fd = FrequencyDomain() diff --git a/examples/Thermal/thermal_stress.py b/examples/Thermal/thermal_stress.py index ae3e6b81d6..f8a9e60f55 100644 --- a/examples/Thermal/thermal_stress.py +++ b/examples/Thermal/thermal_stress.py @@ -1,5 +1,4 @@ """ -.. _ref_thermal_stress: Thermal stress example ====================== @@ -43,7 +42,7 @@ # Start the Solution workflow # ~~~~~~~~~~~~~~~~~~~~~~~~~~~ # NODES and ELEMENTS are read in from the "thermal_stress.k" file. This file also has the -# *PART defined in it but the section and material fields are empty to begin with +# *PART* defined in it but the section and material fields are empty to begin with fns = [] path = examples.thermal_stress + os.sep fns.append(path + "thermal_stress.k") diff --git a/src/ansys/dyna/core/post/README.md b/src/ansys/dyna/core/post/README.md deleted file mode 100644 index 963a0a4b50..0000000000 --- a/src/ansys/dyna/core/post/README.md +++ /dev/null @@ -1 +0,0 @@ -This is where pydyna postprocessing module will live \ No newline at end of file diff --git a/src/ansys/dyna/core/post/__init__.py b/src/ansys/dyna/core/post/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/src/ansys/dyna/core/pre/launcher.py b/src/ansys/dyna/core/pre/launcher.py index fdb14d8474..bfd2e1c210 100644 --- a/src/ansys/dyna/core/pre/launcher.py +++ b/src/ansys/dyna/core/pre/launcher.py @@ -21,12 +21,17 @@ def check_ports(port_range, ip="localhost"): def port_in_use(port, host=LOCALHOST): - """Returns True when a port is in use at the given host. - Must actually "bind" the address. Just checking if we can create + """ + Returns ``True`` when a port is in use at the given host. + + Notes + ----- + Must actually "bind" the address. Just checking if we can create a socket is insufficient as it's possible to run into permission errors like: - - An attempt was made to access a socket in a way forbidden by its - access permissions. + + "An attempt was made to access a socket in a way forbidden by its + access permissions." """ with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock: try: @@ -37,18 +42,19 @@ def port_in_use(port, host=LOCALHOST): def launch_grpc(port=DYNAPRE_DEFAULT_PORT, ip=LOCALHOST, server_path=None) -> tuple: # pragma: no cover - """Start kwserver locally in gRPC mode. + """ + Start kwserver locally in gRPC mode. + Parameters ---------- port : int - Port to launch PyDyna gRPC on. Final port will be the first + Port to launch PyDyna gRPC on. Final port will be the first port available after (or including) this port. Returns ------- int Returns the port number that the gRPC instance started on. - """ LOG.debug("Starting 'launch_kwserver'.") @@ -86,7 +92,9 @@ def launch_dynapre( port=50051, ip="localhost", ): - """Start kwserver locally. + """ + Start kwserver locally. + Parameters ---------- port : int