Skip to content

Commit

Permalink
Adding documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
jjcremmers committed Dec 31, 2024
1 parent 94635b5 commit f15a202
Show file tree
Hide file tree
Showing 7 changed files with 561 additions and 131 deletions.
58 changes: 44 additions & 14 deletions doc/installation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -18,25 +18,55 @@ matplotlib. Installation guidelines are given for various operating systems.
Linux
-----

The ''python'' program and the modules ''numpy'', ''scipy'' and ''matplotlib''
are included in most common distributions of Linux and can be installed without any problems. In many
cases, different versions of ''python'' are offered. Please make sure that ''python'' version 3.6 or higher is
installed. In addition, the modules ''meshio'', ''pickle'' and ''h5py'' can be installed for additional functionality.
The Python compiler and the modules ``numpy``, ``scipy``, and ``matplotlib`` are included in
most common distributions of Linux and can be installed without any problems. In many cases,
different versions of ``python`` are offered. Please make sure that ``python`` version 3.6 or
higher is installed. In addition, the modules ``meshio``, ``pickle``, and ``h5py`` can be
installed for additional functionality.

Execute the file ''install.py'' in the root directory ''pyfem''. In a terminal, one can type:
Execute the file ``install.py`` in the root directory ``pyfem``. In a terminal, one can type:

python3 install.py
.. code-block:: bash
This script will check if the correct versions of Python and the various modules are available. In addition,
the total path to the executable is given. For your own convenience, you can add this to your ''.bashrc'' file:
./install
alias pyfem="python <pyfemdir>/PyFEM.py"
This script will check if the correct versions of Python and the various modules are available.
If not, it will ask your permission to install the correct modules for you.

When using csh or tcsh add the following line to ''.cshrc'' or ''.tcshrc'':
The main executables are created. In commandline you can run PyFEM by typing

alias pyfem "python <pyfemdir>/PyFEM.py"
.. code-block:: bash
<relative_path_to_this_directory>/pyfem.sh inputFile.pro
The main program ''pyfem'' can be run from the command prompt. For example, in order to run the
file ''StressWave20x20.pro'' in the directory ''examples/ch05'', simply type:
The Graphical User Interface of the code (currently under development) can be exectuted
by typing from any directory:

pyfem StressWave20x20.pro
.. code-block:: bash
<relative_path_to_this_directory>/pyfem_gui.exe
It is advised to create aliases. When using a bash shell, please
add the following lines to the file ``~/.bashrc``:

.. code-block:: bash
alias pyfem='python3 /home/joris/Git/pyfem_github/PyFEM/PyFEM.py'
alias pyfem_gui = '/home/joris/Git/pyfem_github/PyFEM/pyfem_gui.x'
You can then run PyFEM in commandline from any directory by typing:

.. code-block:: bash
pyfem inputFile.pro
You can start the gui by typing:

.. code-block:: bash
pyfem_gui
Windows
-------

Under construction

MacOS
-----

Under construction
85 changes: 65 additions & 20 deletions pyfem/util/itemList.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,33 +30,78 @@

class itemList ( dict ):

def add ( self, ID, item ):
"""
Class to construct a list of items that have a coninuous local number, and
a global ID.
"""

def add ( self, ID: int, item ):

"""
Adds an item with an ID to the list. This item will be stored in the list.
if ID in self:
raise RuntimeError( 'ID ' + str(ID) + ' already exists in ' + type(self).__name__ )
Args:
ID (int): the ID of the item to be stored.
item: the value(s) of the item to be stored.
"""

if ID in self:
raise RuntimeError( 'ID ' + str(ID) + ' already exists in ' + type(self).__name__ )

self[ID] = item
self[ID] = item

def get ( self, IDs ):
def get ( self, IDs ):

if isinstance(IDs,int):
return self[IDs]
elif isinstance(IDs,list):
return [ self[ID] for ID in IDs ]
"""
Returns the index / indices of an ID or list of IDs of items in the list.
Args:
IDs (list[int]|int,optional): the ID/IDs. If ommited, a list with all indces
will be returned.
Returns:
list[int]: a list with the indices. In the case of a single ID, this list has
length 1.
"""

if isinstance(IDs,int):
return self[IDs]
elif isinstance(IDs,list):
return [ self[ID] for ID in IDs ]

raise RuntimeError('illegal argument for itemList.get')
raise RuntimeError('illegal argument for itemList.get')

def getIndices ( self, IDs = -1 ):
def getIndices ( self, IDs : list[int] | int = -1 ) -> list[int]:

"""
Returns the index / indices of an ID or list of IDs of items in the list.
if IDs == -1:
return list(self.keys())
elif isinstance(IDs,int):
return list(self.keys()).index( IDs )
elif isinstance(IDs,list):
return [ list(self.keys()).index( ID ) for ID in IDs ]
Args:
IDs (list[int]|int,optional): the ID/IDs. If ommited, a list with all indces
will be returned.
Returns:
list[int]: a list with the indices. In the case of a single ID, this list has
length 1.
"""

if IDs == -1:
return list(self.keys())
elif isinstance(IDs,int):
return list(self.keys()).index( IDs )
elif isinstance(IDs,list):
return [ list(self.keys()).index( ID ) for ID in IDs ]

raise RuntimeError('illegal argument for itemList.getIndices')
raise RuntimeError('illegal argument for itemList.getIndices')

def findID( self , index ):
def findID( self , index : int ) -> int:

return list(self.keys())[index]
"""
Returns the ID of an index in the list.
Args:
index (int): the index of the item
Returns:
int: the ID of the item
"""

return list(self.keys())[index]
21 changes: 15 additions & 6 deletions pyfem/util/kinematics.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,19 @@

class Kinematics:

def __init__( self , nDim , nStr ):
"""
Class that contains the kinematic state of a material
point, i.e. strain and deformation gradient.
Args:
nDim (int): the number of spatial dimensions of the problem (2 or 3)
nStr (int): the number of strain components (2, 3 or 6)
"""

def __init__( self , nDim: int , nStr: int ):

self.F = zeros( shape=( nDim , nDim ) )
self.E = zeros( shape=( nDim , nDim ) )
self.strain = zeros( nStr )
self.dgdstrain = zeros( nStr )
self.g = 0.
self.F = zeros( shape=( nDim , nDim ) )
self.E = zeros( shape=( nDim , nDim ) )
self.strain = zeros( nStr )
self.dgdstrain = zeros( nStr )
self.g = 0.
74 changes: 41 additions & 33 deletions pyfem/util/logger.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,48 +30,56 @@

import logging

#-------------------------------------------------------------------------------
#
#-------------------------------------------------------------------------------


def setLogger( props ):
def setLogger( props : dict ):

level = "normal"
"""
Creates a logger for the current analysis with a given format and level.
Args:
props(dict): A dictionary containing the input file of the problem.
Returns:
logger: an instance of the logger.
"""

level = "normal"

if hasattr(props,"logger"):
level = props.logger.level
if hasattr(props,"logger"):
level = props.logger.level

if level not in ["normal","info","debug","critical","warning","silent"]:
raise NotImplementedError('Logger level should be "normal", "info", "debug", "critical", "silent" or "warning"')
if level not in ["normal","info","debug","critical","warning","silent"]:
raise NotImplementedError('Logger level should be "normal", "info", "debug", "critical", "silent" or "warning"')

logger = logging.getLogger()
handler = logging.StreamHandler()
logger = logging.getLogger()
handler = logging.StreamHandler()

if level == "debug":
formatter = logging.Formatter('%(asctime)s %(levelname)-8s %(message)s')
logger .setLevel(logging.DEBUG)
elif level == "critical" or level == "silent":
formatter = logging.Formatter(' %(message)s')
logger .setLevel(logging.CRITICAL)
elif level == "warning":
formatter = logging.Formatter(' %(message)s')
logger .setLevel(logging.WARNING)
else:
formatter = logging.Formatter(' %(message)s')
logger .setLevel(logging.INFO)
if level == "debug":
formatter = logging.Formatter('%(asctime)s %(levelname)-8s %(message)s')
logger .setLevel(logging.DEBUG)
elif level == "critical" or level == "silent":
formatter = logging.Formatter(' %(message)s')
logger .setLevel(logging.CRITICAL)
elif level == "warning":
formatter = logging.Formatter(' %(message)s')
logger .setLevel(logging.WARNING)
else:
formatter = logging.Formatter(' %(message)s')
logger .setLevel(logging.INFO)

handler.setFormatter(formatter)
logger .addHandler(handler)
handler.setFormatter(formatter)
logger .addHandler(handler)

return logger
return logger


#-------------------------------------------------------------------------------
#
#-------------------------------------------------------------------------------


def getLogger():

return logging.getLogger()
"""
Function that returns an instance of the active logger.
Args:
None
Returnslogger: an instance of the active logger.
"""

return logging.getLogger()
47 changes: 29 additions & 18 deletions pyfem/util/plotUtils.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
# R. de Borst, M.A. Crisfield, J.J.C. Remmers and C.V. Verhoosel #
# John Wiley and Sons, 2012, ISBN 978-0470666449 #
# #
# Copyright (C) 2011-2024. The code is written in 2011-2012 by #
# Copyright (C) 2011-2025. The code is written in 2011-2012 by #
# Joris J.C. Remmers, Clemens V. Verhoosel and Rene de Borst and since #
# then augmented and maintained by Joris J.C. Remmers. #
# All rights reserved. #
Expand All @@ -28,39 +28,50 @@
# event caused by the use of the program. #
################################################################################

import numpy as np

#-------------------------------------------------------------------------------
#
#-------------------------------------------------------------------------------
def plotCurve( output: np.ndarray ) -> None:

"""
Plots a curve based on the given output data points.
def plotCurve( output ):
Args:
output (List[Tuple[float, float]]): A list of (x, y) data points to plot.
from pylab import plot, show, xlabel, ylabel
Returns:
None
"""

plot( [x[0] for x in output], [x[1] for x in output], 'r-o' )
from pylab import plot, show, xlabel, ylabel

show()


#-
#
#----------------
plot( [x[0] for x in output], [x[1] for x in output], 'r-o' )

show()


def plotTime(t: float) -> str:

"""
Formats a given time duration into a human-readable string.
def plotTime( t ):
Args:
t (float): Time duration in seconds.
Returns:
str: A formatted string representing the time in seconds, minutes, or hours.
"""
if t < 0.1:
return f"{t:.1e} sec."
elif t < 60.0:
return f"{t:.3f} sec."
elif t < 3600.0:
minutes = int(t // 60 )
minutes = int(t // 60)
seconds = t % 60
return f"{minutes} min. {seconds:.2f} sec."
else:
hours = int(t // 3600 )
minutes = int((t % 3600 ) // 60 )
hours = int(t // 3600)
minutes = int((t % 3600) // 60)
seconds = t % 60
return f"{hours} hrs. {minutes} min. {seconds:.2f} sec."
return f"{hours} hrs. {minutes} min. {seconds:.2f} sec."


Loading

0 comments on commit f15a202

Please sign in to comment.