Merge remote-tracking branch 'origin/development' into select-mu

This commit is contained in:
Sharan Roongta 2022-11-29 12:12:02 +01:00
commit 599e4472e8
81 changed files with 3826 additions and 921 deletions

View File

@ -47,9 +47,9 @@ variables:
PETSC_INTELLLVM: "Libraries/PETSc/3.16.3/oneAPI-2022.0.1-IntelMPI-2021.5.0" PETSC_INTELLLVM: "Libraries/PETSc/3.16.3/oneAPI-2022.0.1-IntelMPI-2021.5.0"
PETSC_INTEL: "Libraries/PETSc/3.16.5/Intel-2022.0.1-IntelMPI-2021.5.0" PETSC_INTEL: "Libraries/PETSc/3.16.5/Intel-2022.0.1-IntelMPI-2021.5.0"
# ++++++++++++ MSC Marc +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ # ++++++++++++ MSC Marc +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
MSC: "FEM/MSC/2022.1" MSC: "FEM/MSC/2022.2"
IntelMarc: "Compiler/Intel/19.1.2 Libraries/IMKL/2020" IntelMarc: "Compiler/Intel/19.1.2 Libraries/IMKL/2020"
HDF5Marc: "HDF5/1.12.1/Intel-19.1.2" HDF5Marc: "HDF5/1.12.2/Intel-19.1.2"
################################################################################################### ###################################################################################################

@ -1 +1 @@
Subproject commit 7b1ad767256f796f56514d8888027499fe777132 Subproject commit 81f5f24d076a623e6052c234825c591267915285

View File

@ -1 +1 @@
3.0.0-alpha7-86-g72408f389 3.0.0-alpha7-168-g741aeab1d

View File

@ -80,4 +80,4 @@ commercialFEM:
generic: generic:
random_seed: 0 # fixed seeding for pseudo-random number generator, Default 0: use random seed. random_seed: 0 # fixed seeding for pseudo-random number generator, Default 0: use random seed.
residualStiffness: 1.0e-6 # non-zero residual damage. phi_min: 1.0e-6 # non-zero residual damage.

View File

@ -6,8 +6,8 @@ references:
https://doi.org/10.1016/0040-6031(93)80437-F, https://doi.org/10.1016/0040-6031(93)80437-F,
fit to Fig. 6 (T_min=100K, T_max=1400K) fit to Fig. 6 (T_min=100K, T_max=1400K)
A_11: 2.068e-08 Alpha_11: 2.068e-08
A_11,T: 1.579e-09 Alpha_11,T: 1.579e-09
A_11,T^2: 3.449e-13 Alpha_11,T^2: 3.449e-13
T_ref: 293.15 T_ref: 293.15

View File

@ -4,4 +4,4 @@ references:
- https://en.wikipedia.org/wiki/Thermal_expansion, - https://en.wikipedia.org/wiki/Thermal_expansion,
293.15K 293.15K
A_11: 23.1e-6 Alpha_11: 23.1e-6

View File

@ -4,4 +4,4 @@ references:
- https://en.wikipedia.org/wiki/Thermal_expansion, - https://en.wikipedia.org/wiki/Thermal_expansion,
293.15K 293.15K
A_11: 14.e-6 Alpha_11: 14.e-6

View File

@ -4,8 +4,8 @@ references:
- https://commons.wikimedia.org/wiki/File:Coefficient_dilatation_lineique_aciers.svg, - https://commons.wikimedia.org/wiki/File:Coefficient_dilatation_lineique_aciers.svg,
fit to image description (Scilab code) fit to image description (Scilab code)
A_11: 12.70371e-6 Alpha_11: 12.70371e-6
A_11,T: 7.54e-9 Alpha_11,T: 7.54e-9
A_11,T^2: -1.0e-11 Alpha_11,T^2: -1.0e-11
T_ref: 273.0 T_ref: 273.0

View File

@ -4,4 +4,4 @@ references:
- https://en.wikipedia.org/wiki/Thermal_expansion, - https://en.wikipedia.org/wiki/Thermal_expansion,
293.15K 293.15K
A_11: 17.e-6 Alpha_11: 17.e-6

View File

@ -4,4 +4,4 @@ references:
- https://en.wikipedia.org/wiki/Thermal_expansion, - https://en.wikipedia.org/wiki/Thermal_expansion,
293.15K 293.15K
A_11: 11.8e-6 Alpha_11: 11.8e-6

View File

@ -6,12 +6,12 @@ references:
https://doi.org/10.1107/S0365110X62000742, https://doi.org/10.1107/S0365110X62000742,
fit to Tab. 2 (T_min=30ºC, T_max=210ºC) fit to Tab. 2 (T_min=30ºC, T_max=210ºC)
A_11: 1.639e-05 Alpha_11: 1.639e-05
A_11,T: 1.799e-08 Alpha_11,T: 1.799e-08
A_11,T^2: 1.734e-10 Alpha_11,T^2: 1.734e-10
A_33: 3.263e-05 Alpha_33: 3.263e-05
A_33,T: 1.387e-08 Alpha_33,T: 1.387e-08
A_33,T^2: 5.794e-10 Alpha_33,T^2: 5.794e-10
T_ref: 293.15 T_ref: 293.15

View File

@ -4,4 +4,4 @@ references:
- https://en.wikipedia.org/wiki/Thermal_expansion, - https://en.wikipedia.org/wiki/Thermal_expansion,
293.15K 293.15K
A_11: 4.5e-6 Alpha_11: 4.5e-6

View File

@ -4,7 +4,7 @@ references:
- https://commons.wikimedia.org/wiki/File:Coefficient_dilatation_lineique_aciers.svg, - https://commons.wikimedia.org/wiki/File:Coefficient_dilatation_lineique_aciers.svg,
fit to image description (Scilab code) fit to image description (Scilab code)
A_11: 11.365e-6 Alpha_11: 11.365e-6
A_11,T: 5.0e-9 Alpha_11,T: 5.0e-9
T_ref: 273.0 T_ref: 273.0

View File

@ -46,7 +46,7 @@
+ +
+# determine DAMASK version +# determine DAMASK version
+if test -n "$DAMASK_USER"; then +if test -n "$DAMASK_USER"; then
+ DAMASKROOT=`dirname $DAMASK_USER`/.. + DAMASKROOT=`dirname $DAMASK_USER`/../..
+ read DAMASKVERSION < $DAMASKROOT/VERSION + read DAMASKVERSION < $DAMASKROOT/VERSION
+ DAMASKVERSION="'"$DAMASKVERSION"'" + DAMASKVERSION="'"$DAMASKVERSION"'"
+else +else

View File

@ -251,7 +251,7 @@
- usersub=$usersubname - usersub=$usersubname
- fi - fi
- -
+ userobj=$usermoext.o + userobj=$usernoext.o
fi fi
cat > $jid.runmarcscript << END4 cat > $jid.runmarcscript << END4
if test "$user" if test "$user"

View File

@ -251,7 +251,7 @@
- usersub=$usersubname - usersub=$usersubname
- fi - fi
- -
+ userobj=$usermoext.o + userobj=$usernoext.o
fi fi
cat > $jid.runmarcscript << END4 cat > $jid.runmarcscript << END4
if test "$user" if test "$user"

View File

@ -251,7 +251,7 @@
- usersub=$usersubname - usersub=$usersubname
- fi - fi
- -
+ userobj=$usermoext.o + userobj=$usernoext.o
fi fi
cat > $jid.runmarcscript << END4 cat > $jid.runmarcscript << END4
if test "$user" if test "$user"

View File

@ -66,7 +66,7 @@
+ label { + label {
+ position -32 +6 + position -32 +6
+ size 12 6 + size 12 6
+ text "O2 / OpenMP" + text "O3 / OpenMP"
+ border_width 1 + border_width 1
+ border_color black + border_color black
+ } + }

View File

@ -46,7 +46,7 @@
+ +
+# determine DAMASK version +# determine DAMASK version
+if test -n "$DAMASK_USER"; then +if test -n "$DAMASK_USER"; then
+ DAMASKROOT=`dirname $DAMASK_USER`/.. + DAMASKROOT=`dirname $DAMASK_USER`/../..
+ read DAMASKVERSION < $DAMASKROOT/VERSION + read DAMASKVERSION < $DAMASKROOT/VERSION
+ DAMASKVERSION="'"$DAMASKVERSION"'" + DAMASKVERSION="'"$DAMASKVERSION"'"
+else +else

View File

@ -284,7 +284,7 @@
- usersub=$usersubname - usersub=$usersubname
- fi - fi
- -
+ userobj=$usermoext.o + userobj=$usernoext.o
fi fi
cat > $jid.runmarcscript << END4 cat > $jid.runmarcscript << END4
if test "$user" if test "$user"

View File

@ -284,7 +284,7 @@
- usersub=$usersubname - usersub=$usersubname
- fi - fi
- -
+ userobj=$usermoext.o + userobj=$usernoext.o
fi fi
cat > $jid.runmarcscript << END4 cat > $jid.runmarcscript << END4
if test "$user" if test "$user"

View File

@ -284,7 +284,7 @@
- usersub=$usersubname - usersub=$usersubname
- fi - fi
- -
+ userobj=$usermoext.o + userobj=$usernoext.o
fi fi
cat > $jid.runmarcscript << END4 cat > $jid.runmarcscript << END4
if test "$user" if test "$user"

View File

@ -65,7 +65,7 @@
+ label { + label {
+ position -32 +6 + position -32 +6
+ size 12 6 + size 12 6
+ text "O2 / OpenMP" + text "O3 / OpenMP"
+ border_width 1 + border_width 1
+ border_color black + border_color black
+ } + }

View File

@ -50,7 +50,7 @@
+# determine DAMASK version +# determine DAMASK version
+if test -n "$DAMASK_USER"; then +if test -n "$DAMASK_USER"; then
+ DAMASKROOT=`dirname $DAMASK_USER`/.. + DAMASKROOT=`dirname $DAMASK_USER`/../..
+ read DAMASKVERSION < $DAMASKROOT/VERSION + read DAMASKVERSION < $DAMASKROOT/VERSION
+ DAMASKVERSION="'"$DAMASKVERSION"'" + DAMASKVERSION="'"$DAMASKVERSION"'"
+else +else

View File

@ -283,7 +283,7 @@
- usersub=$usersubname - usersub=$usersubname
- fi - fi
- -
+ userobj=$usermoext.o + userobj=$usernoext.o
fi fi
cat > $jid.runmarcscript << END4 cat > $jid.runmarcscript << END4
if test "$user" if test "$user"

View File

@ -283,7 +283,7 @@
- usersub=$usersubname - usersub=$usersubname
- fi - fi
- -
+ userobj=$usermoext.o + userobj=$usernoext.o
fi fi
cat > $jid.runmarcscript << END4 cat > $jid.runmarcscript << END4
if test "$user" if test "$user"

View File

@ -301,7 +301,7 @@
- usersub=$usersubname - usersub=$usersubname
- fi - fi
- -
+ userobj=$usermoext.o + userobj=$usernoext.o
fi fi
cat > $jid.runmarcscript << END4 cat > $jid.runmarcscript << END4
if test "$user" if test "$user"

View File

@ -67,7 +67,7 @@
+ label { + label {
+ position -32 +6 + position -32 +6
+ size 12 6 + size 12 6
+ text "O2 / OpenMP" + text "O3 / OpenMP"
+ border_width 1 + border_width 1
+ border_color black + border_color black
+ } + }

View File

@ -40,7 +40,7 @@
+# determine DAMASK version +# determine DAMASK version
+if test -n "$DAMASK_USER"; then +if test -n "$DAMASK_USER"; then
+ DAMASKROOT=`dirname $DAMASK_USER`/.. + DAMASKROOT=`dirname $DAMASK_USER`/../..
+ read DAMASKVERSION < $DAMASKROOT/VERSION + read DAMASKVERSION < $DAMASKROOT/VERSION
+ DAMASKVERSION="'"$DAMASKVERSION"'" + DAMASKVERSION="'"$DAMASKVERSION"'"
+else +else

View File

@ -228,7 +228,7 @@
- usersub=$usersubname - usersub=$usersubname
- fi - fi
- -
+ userobj=$usermoext.o + userobj=$usernoext.o
fi fi
cat > $jid.runmarcscript << END4 cat > $jid.runmarcscript << END4
if test "$user" if test "$user"

View File

@ -228,7 +228,7 @@
- usersub=$usersubname - usersub=$usersubname
- fi - fi
- -
+ userobj=$usermoext.o + userobj=$usernoext.o
fi fi
cat > $jid.runmarcscript << END4 cat > $jid.runmarcscript << END4
if test "$user" if test "$user"

View File

@ -228,7 +228,7 @@
- usersub=$usersubname - usersub=$usersubname
- fi - fi
- -
+ userobj=$usermoext.o + userobj=$usernoext.o
fi fi
cat > $jid.runmarcscript << END4 cat > $jid.runmarcscript << END4
if test "$user" if test "$user"

View File

@ -67,7 +67,7 @@
+ label { + label {
+ position -32 +6 + position -32 +6
+ size 12 6 + size 12 6
+ text "O2 / OpenMP" + text "O3 / OpenMP"
+ border_width 1 + border_width 1
+ border_color black + border_color black
+ } + }

View File

@ -0,0 +1,49 @@
---
+++
@@ -6,18 +6,27 @@
DIR=$1
user=$3
program=$4
+usernoext=$user
+usernoext=`dirname $usernoext`/`$BASENAME $usernoext .f`
+usernoext=`dirname $usernoext`/`$BASENAME $usernoext .F`
+usernoext=`dirname $usernoext`/`$BASENAME $usernoext .for`
+usernoext=`dirname $usernoext`/`$BASENAME $usernoext .f90`
+
+# add BLAS options for linking
+ BLAS="%BLAS%"
+
. $DIR/tools/include
DIRJOB=$2
cd $DIRJOB
-echo "Compiling and linking user subroutine $user.f on host `hostname`"
+echo "Compiling and linking user subroutine $user on host `hostname`"
echo "program: $program"
- $FORTRAN $user.f || \
+ $DFORTHIGHMP $user || \
{
- echo "$0: compile failed for $user.f"
+ echo "$0: compile failed for $user"
exit 1
}
/bin/rm $program 2>/dev/null
- userobj=$user.o
+ userobj=$usernoext.o
$LOAD ${program} $DIR/lib/main.o\
@@ -33,9 +42,13 @@
$TKLIBS \
$MRCLIBS \
$METISLIBS \
+ $BLAS \
$SYSLIBS || \
{
- echo "$0: link failed for $user.o on host `hostname`"
+ echo "$0: link failed for $usernoext.o on host `hostname`"
exit 1
}
/bin/rm $userobj
+ /bin/rm $DIRJOB/*.mod
+ /bin/rm $DIRJOB/*.smod
+ /bin/rm $DIRJOB/*_genmod.f90

View File

@ -0,0 +1,49 @@
---
+++
@@ -6,18 +6,27 @@
DIR=$1
user=$3
program=$4
+usernoext=$user
+usernoext=`dirname $usernoext`/`$BASENAME $usernoext .f`
+usernoext=`dirname $usernoext`/`$BASENAME $usernoext .F`
+usernoext=`dirname $usernoext`/`$BASENAME $usernoext .for`
+usernoext=`dirname $usernoext`/`$BASENAME $usernoext .f90`
+
+# add BLAS options for linking
+ BLAS="%BLAS%"
+
. $DIR/tools/include
DIRJOB=$2
cd $DIRJOB
-echo "Compiling and linking user subroutine $user.f on host `hostname`"
+echo "Compiling and linking user subroutine $user on host `hostname`"
echo "program: $program"
- $FORTRAN $user.f || \
+ $DFORTRANLOWMP $user || \
{
- echo "$0: compile failed for $user.f"
+ echo "$0: compile failed for $user"
exit 1
}
/bin/rm $program 2>/dev/null
- userobj=$user.o
+ userobj=$usernoext.o
$LOAD ${program} $DIR/lib/main.o\
@@ -33,9 +42,13 @@
$TKLIBS \
$MRCLIBS \
$METISLIBS \
+ $BLAS \
$SYSLIBS || \
{
- echo "$0: link failed for $user.o on host `hostname`"
+ echo "$0: link failed for $usernoext.o on host `hostname`"
exit 1
}
/bin/rm $userobj
+ /bin/rm $DIRJOB/*.mod
+ /bin/rm $DIRJOB/*.smod
+ /bin/rm $DIRJOB/*_genmod.f90

View File

@ -0,0 +1,49 @@
---
+++
@@ -6,18 +6,27 @@
DIR=$1
user=$3
program=$4
+usernoext=$user
+usernoext=`dirname $usernoext`/`$BASENAME $usernoext .f`
+usernoext=`dirname $usernoext`/`$BASENAME $usernoext .F`
+usernoext=`dirname $usernoext`/`$BASENAME $usernoext .for`
+usernoext=`dirname $usernoext`/`$BASENAME $usernoext .f90`
+
+# add BLAS options for linking
+ BLAS="%BLAS%"
+
. $DIR/tools/include
DIRJOB=$2
cd $DIRJOB
-echo "Compiling and linking user subroutine $user.f on host `hostname`"
+echo "Compiling and linking user subroutine $user on host `hostname`"
echo "program: $program"
- $FORTRAN $user.f || \
+ $DFORTRANMP $user || \
{
- echo "$0: compile failed for $user.f"
+ echo "$0: compile failed for $user"
exit 1
}
/bin/rm $program 2>/dev/null
- userobj=$user.o
+ userobj=$usernoext.o
$LOAD ${program} $DIR/lib/main.o\
@@ -33,9 +42,13 @@
$TKLIBS \
$MRCLIBS \
$METISLIBS \
+ $BLAS \
$SYSLIBS || \
{
- echo "$0: link failed for $user.o on host `hostname`"
+ echo "$0: link failed for $usernoext.o on host `hostname`"
exit 1
}
/bin/rm $userobj
+ /bin/rm $DIRJOB/*.mod
+ /bin/rm $DIRJOB/*.smod
+ /bin/rm $DIRJOB/*_genmod.f90

View File

@ -0,0 +1,75 @@
---
+++
@@ -166,6 +166,15 @@
MARC_COSIM_LIB="$MSCCOSIM_HOME/CoSim$MSCCOSIM_VERSION/Dcosim$MSCCOSIM_VERSION/lib"
fi
+# DAMASK uses the HDF5 compiler wrapper around the Intel compiler
+H5FC=$(h5fc -shlib -show)
+if [[ "$H5FC" == *"$dir is"* ]]; then
+ H5FC=$(echo $(echo "$H5FC" | tail -n1) | sed -e "s/\-shlib/-fPIC -qopenmp/g")
+ H5FC=${H5FC%-lmpifort*}
+fi
+HDF5_LIB=${H5FC//*ifort/}
+FCOMP="$H5FC"
+
# AEM
if test "$MARCDLLOUTDIR" = ""; then
DLLOUTDIR="$MARC_LIB"
@@ -594,7 +603,7 @@
PROFILE=" $PROFILE -pg"
fi
-FORT_OPT="-c -assume byterecl -safe_cray_ptr -mp1 -WB -fp-model source"
+FORT_OPT="-c -implicitnone -stand f18 -standard-semantics -assume nostd_mod_proc_name -safe_cray_ptr -mp1 -WB -fp-model source"
if test "$MTHREAD" = "OPENMP"
then
FORT_OPT=" $FORT_OPT -qopenmp"
@@ -607,7 +616,7 @@
FORT_OPT=" $FORT_OPT -save -zero"
fi
if test "$MARCHDF_HDF" = "HDF"; then
- FORT_OPT="$FORT_OPT -DMARCHDF_HDF=$MARCHDF_HDF $HDF_INCLUDE"
+ FORT_OPT="$FORT_OPT -DMARCHDF=$MARCHDF_HDF"
fi
FORTLOW="$FCOMP $FORT_OPT $PROFILE -O0 $I8FFLAGS -I$MARC_SOURCE/common \
@@ -621,6 +630,29 @@
# for compiling free form f90 files. high opt, integer(4)
FORTF90="$FCOMP -c -O3"
+# determine DAMASK version
+if test -n "$DAMASK_USER"; then
+ DAMASKROOT=`dirname $DAMASK_USER`/../..
+ read DAMASKVERSION < $DAMASKROOT/VERSION
+ DAMASKVERSION="'"$DAMASKVERSION"'"
+else
+ DAMASKVERSION="'N/A'"
+fi
+
+# DAMASK compiler calls
+DFORTLOWMP="$FCOMP -c -O0 -qno-offload -implicitnone -stand f18 -standard-semantics -assume nostd_mod_proc_name -safe_cray_ptr $PROFILE -zero -mp1 -WB $I8FFLAGS -I$MARC_SOURCE/common \
+ -fpp -ftz -diag-disable 5268 -warn declarations -warn general -warn usage -warn interfaces -warn ignore_loc -warn alignments -DMARC4DAMASK=2022.1 -DDAMASKVERSION=$DAMASKVERSION \
+ -qopenmp -qopenmp-threadprivate=compat\
+ $MUMPS_INCLUDE $I8DEFINES -DLinux -DLINUX -DLinux_intel $FDEFINES $DDM $SOLVERFLAGS -I$KDTREE2_MOD -I$MARC_MOD"
+DFORTRANMP="$FCOMP -c -O1 -qno-offload -implicitnone -stand f18 -standard-semantics -assume nostd_mod_proc_name -safe_cray_ptr $PROFILE -zero -mp1 -WB $I8FFLAGS -I$MARC_SOURCE/common \
+ -fpp -ftz -diag-disable 5268 -warn declarations -warn general -warn usage -warn interfaces -warn ignore_loc -warn alignments -DMARC4DAMASK=2022.1 -DDAMASKVERSION=$DAMASKVERSION \
+ -qopenmp -qopenmp-threadprivate=compat\
+ $MUMPS_INCLUDE $I8DEFINES -DLinux -DLINUX -DLinux_intel $FDEFINES $DDM $SOLVERFLAGS -I$KDTREE2_MOD -I$MARC_MOD"
+DFORTHIGHMP="$FCOMP -c -O3 -qno-offload -implicitnone -stand f18 -standard-semantics -assume nostd_mod_proc_name -safe_cray_ptr $PROFILE -zero -mp1 -WB $I8FFLAGS -I$MARC_SOURCE/common \
+ -fpp -ftz -diag-disable 5268 -warn declarations -warn general -warn usage -warn interfaces -warn ignore_loc -warn alignments -DMARC4DAMASK=2022.1 -DDAMASKVERSION=$DAMASKVERSION \
+ -qopenmp -qopenmp-threadprivate=compat\
+ $MUMPS_INCLUDE $I8DEFINES -DLinux -DLINUX -DLinux_intel $FDEFINES $DDM $SOLVERFLAGS -I$KDTREE2_MOD -I$MARC_MOD"
+
if test "$MARCDEBUG" = "ON"
then
FORTLOW="$FCOMP $FORT_OPT $PROFILE $I8FFLAGS -I$MARC_SOURCE/common \
@@ -778,7 +810,7 @@
SOLVERLIBS="${BCSSOLVERLIBS} ${VKISOLVERLIBS} ${CASISOLVERLIBS} ${MF2SOLVERLIBS} \
-L$MARC_MKL \
- $MARC_LIB/blas_src.a ${ACSI_LIB}/ACSI_MarcLib.a $KDTREE2_LIB/libkdtree2.a $MARC_LIB/libtetmeshinterface.a $MARC_LIB/libcaefatigueinterface.a -L$MARC_LIB -lmkl_blacs_intelmpi_ilp64 -lmkl_scalapack_ilp64 -lmkl_intel_ilp64 -lmkl_intel_thread -lmkl_core -liomp5 -ltetmesh -lmeshgems -lmg-tetra -lmeshgems_stubs $HDF_LIBS $SOLVER2LIBS"
+ $MARC_LIB/blas_src.a ${ACSI_LIB}/ACSI_MarcLib.a $KDTREE2_LIB/libkdtree2.a $MARC_LIB/libtetmeshinterface.a $MARC_LIB/libcaefatigueinterface.a -L$MARC_LIB -lmkl_blacs_intelmpi_ilp64 -lmkl_scalapack_ilp64 -lmkl_intel_ilp64 -lmkl_intel_thread -lmkl_core -liomp5 -ltetmesh -lmeshgems -lmg-tetra -lmeshgems_stubs $HDF5_LIB $SOLVER2LIBS"
SOLVERLIBS_DLL=${SOLVERLIBS}
if test "$AEM_DLL" -eq 1

View File

@ -0,0 +1,517 @@
---
+++
@@ -136,6 +136,11 @@
# is created. For job running in the background, the log #
# file is always created. Default is "yes" #
##############################################################################
+# remove all Mentat paths from LD_LIBRARY_PATH
+LD_LIBRARY_PATH=:$LD_LIBRARY_PATH:
+LD_LIBRARY_PATH=${LD_LIBRARY_PATH//+([!(:)])mentat2022.2+([!(:)])/:}
+LD_LIBRARY_PATH=${LD_LIBRARY_PATH//+([(:)])/:}
+LD_LIBRARY_PATH=${LD_LIBRARY_PATH#:}; LD_LIBRARY_PATH=${LD_LIBRARY_PATH%:}
# set DIR to the directory in which this script is
REALCOM="`/bin/ls -l $0 |awk '{ print $NF; }'`"
DIR=`dirname $REALCOM`
@@ -302,7 +307,23 @@
. "$DIR/getarch"
+
+# getting user subroutine file name
+found=0
+for i in "$@"; do
+ if test $found = 1; then
+ DAMASK_USER=$i
+ found=0
+ fi
+ case $i in
+ -u* | -U*)
+ found=1
+ ;;
+ esac
+done
+# sourcing include_linux64 (needs DAMASK_USER to be set)
. $MARC_INCLUDE
+
#
#
@@ -405,7 +426,7 @@
did=
vid=
user=
-usersubname=
+usernoext=
objs=
qid=background
cpu=
@@ -676,50 +697,19 @@
esac
;;
-u* | -U*)
- user=`dirname $value`/`$BASENAME $value .f`
- usersubname=$user
- basefile=`$BASENAME $value`
- if test ${basefile##*.} = f
- then
- user=`dirname $value`/`$BASENAME $value .f`
- usersubname=$user.f
- elif test ${basefile##*.} = F
- then
- user=`dirname $value`/`$BASENAME $value .F`
- usersubname=$user.F
- elif test ${basefile##*.} = f90
- then
- user=`dirname $value`/`$BASENAME $value .f90`
- usersubname=$user.f90
- elif test ${basefile##*.} = F90
- then
- user=`dirname $value`/`$BASENAME $value .F90`
- usersubname=$user.F90
- fi
+ user=$value
case $user in
\/*)
;;
*)
user=`pwd`/$user
- usersubname=`pwd`/$usersubname
;;
esac
- if test ! -f $usersubname
- then
- if test -f $usersubname.f
- then
- usersubname=$usersubname.f
- elif test -f $usersubname.F
- then
- usersubname=$usersubname.F
- elif test -f $usersubname.f90
- then
- usersubname=$usersubname.f90
- elif test -f $usersubname.F90
- then
- usersubname=$usersubname.F90
- fi
- fi
+ usernoext=$user
+ usernoext=`dirname $usernoext`/`$BASENAME $usernoext .f`
+ usernoext=`dirname $usernoext`/`$BASENAME $usernoext .F`
+ usernoext=`dirname $usernoext`/`$BASENAME $usernoext .for`
+ usernoext=`dirname $usernoext`/`$BASENAME $usernoext .f90`
;;
-obj | -OBJ)
objs="$value"
@@ -1207,12 +1197,12 @@
fi
fi
fi
- if test "$usersubname"
+ if test "$user"
then
- if test ! -f $usersubname
+ if test ! -f $user
then
error="$error
-user subroutine file $usersubname not accessible"
+user subroutine file $user not accessible"
fi
fi
if test "$objs"
@@ -1531,7 +1521,7 @@
Marc shared lib : $progdll
Version type : $mode
Job ID : $DIRJID/$jid$extra_job_info
-User subroutine name : $usersubname
+User subroutine name : $user
User objects/libs : $objs
Restart file job ID : $rid
Substructure file ID : $sid
@@ -1564,7 +1554,7 @@
Marc shared lib : $progdll
Version type : $mode
Job ID : $DIRJID/$jid$extra_job_info
-User subroutine name : $usersubname
+User subroutine name : $user
User objects/libs : $objs
Restart file job ID : $rid
Substructure file ID : $sid
@@ -1687,7 +1677,7 @@
;;
esac
fi
- $ECHO "User subroutine name ($usersubname)? $ECHOTXT"
+ $ECHO "User subroutine name ($user)? $ECHOTXT"
read value
if test "$value"
then
@@ -1696,50 +1686,19 @@
user=
;;
*)
- user=`dirname $value`/`$BASENAME $value .f`
- usersubname=$user
- basefile=`$BASENAME $value`
- if test ${basefile##*.} = f
- then
- user=`dirname $value`/`$BASENAME $value .f`
- usersubname=$user.f
- elif test ${basefile##*.} = F
- then
- user=`dirname $value`/`$BASENAME $value .F`
- usersubname=$user.F
- elif test ${basefile##*.} = f90
- then
- user=`dirname $value`/`$BASENAME $value .f90`
- usersubname=$user.f90
- elif test ${basefile##*.} = F90
- then
- user=`dirname $value`/`$BASENAME $value .F90`
- usersubname=$user.F90
- fi
+ user=$value
case $user in
\/*)
;;
*)
user=`pwd`/$user
- usersubname=`pwd`/$usersubname
;;
esac
- if test ! -f $usersubname
- then
- if test -f $usersubname.f
- then
- usersubname=$usersubname.f
- elif test -f $usersubname.F
- then
- usersubname=$usersubname.F
- elif test -f $usersubname.f90
- then
- usersubname=$usersubname.f90
- elif test -f $usersubname.F90
- then
- usersubname=$usersubname.F90
- fi
- fi
+ usernoext=$user
+ usernoext=`dirname $usernoext`/`$BASENAME $usernoext .f`
+ usernoext=`dirname $usernoext`/`$BASENAME $usernoext .F`
+ usernoext=`dirname $usernoext`/`$BASENAME $usernoext .for`
+ usernoext=`dirname $usernoext`/`$BASENAME $usernoext .f90`
;;
esac
fi
@@ -2274,11 +2233,12 @@
#
# user subroutine used
#
+# add DAMASK options for linking
+ DAMASK="-lstdc++"
if test "$user"
then
-# program=$user.marc
- program=$DIRJOB/`$BASENAME $user .f`.marc
+ program=$usernoext.marc
case $program in
\/* | \.\/*)
bd=
@@ -2391,7 +2351,7 @@
fi
if test "$user"
then
- execpath=$DIRJOB/`$BASENAME $user .f`.marc
+ execpath=$usernoext.marc
usersub=1
fi
export execpath
@@ -3274,44 +3234,27 @@
echo
if test "$user"
then
- userobj=$DIRJOB/`$BASENAME $user .f`.o
- basefile=`$BASENAME $usersubname`
- if test ${basefile##*.} = f
- then
- usersub=$DIRJOB/`$BASENAME $user .f`.F
- ln -sf "$user.f" "$usersub"
- else
- usersub=$usersubname
- fi
-
+ userobj=$usernoext.o
fi
cat > $jid.runmarcscript << END4
if test "$user"
then
- if test ${basefile##*.} = f
- then
- ln -sf "$user.f" "$usersub"
- fi
if test $MACHINENAME = "CRAY"
then
- $FORTRAN $usersub || \
+ $DFORTHIGHMP $user || \
{
- echo "$0: compile failed for $user.f"
+ echo "$0: compile failed for $user"
exit 1
}
/bin/rm $program 2>/dev/null
else
- $FORTRAN $usersub -o $userobj || \
+ $DFORTHIGHMP $user -o $userobj || \
{
- echo "$0: compile failed for $user.f"
+ echo "$0: compile failed for $user"
exit 1
}
/bin/rm $program 2>/dev/null
fi
- if test ${basefile##*.} = f
- then
- /bin/rm -f "$usersub"
- fi
fi
@@ -3331,6 +3274,7 @@
$TKLIBS \
$MRCLIBS \
$METISLIBS \
+ $DAMASK \
$SFLIB \
$OPENSSL_LIB \
$SYSLIBS \
@@ -3344,6 +3288,9 @@
prgsav=yes
fi
/bin/rm $userobj 2>/dev/null
+/bin/rm $DIRJOB/*.mod 2>/dev/null
+/bin/rm $DIRJOB/*.smod 2>/dev/null
+/bin/rm $DIRJOB/*_genmod.f90 2>/dev/null
#
# run marc
@@ -3390,7 +3337,7 @@
fi
else
if test $cpdll = yes; then
- filename=`basename $usersubname .f`
+ filename=$usernoext
/bin/cp $DIRJOB/$marcdll $DIRJOB/${filename}_$marcdll 2>/dev/null
fi
if test $rmdll = yes
@@ -3556,7 +3503,7 @@
# first copy over the user sub if local directories
if test ${dirstatus[$counter]} = "local"
then
- $RCP $user.f $i:$DIR1/
+ $RCP $user $i:$DIR1/
fi
# do the compilation on the other machine
if test ${dirstatus[$counter]} = "shared"
@@ -3569,21 +3516,21 @@
remoteuser=$DIR1/`$BASENAME $user`
$RSH $i /bin/rm $remoteprog 2> /dev/null
echo
- $RSH $i $DIR2/tools/comp_user $DIR2 $DIR1 $remoteuser $remoteprog
+ $RSH $i $DIR2/tools/comp_damask_hmp $DIR2 $DIR1 $remoteuser $remoteprog
# check if successful, the new executable should be there
line=`$RSH $i /bin/ls $remoteprog 2> /dev/null`
if test "$line"
then
echo compilation and linking successful on host $i
else
- echo "$0: compile failed for $user.f on host $i"
+ echo "$0: compile failed for $user on host $i"
echo " $PRODUCT Exit number 3"
exit 1
fi
# remove the user subroutine on remote machine
if test ${dirstatus[$counter]} = "local"
then
- $RSH $i /bin/rm $remoteuser.f 2> /dev/null
+ $RSH $i /bin/rm $remoteuser 2> /dev/null
fi
fi
fi
@@ -3593,39 +3540,27 @@
if test "$userhost"
then
echo
- echo "Compiling and linking user subroutine $user.f on host `hostname`"
- fi
- userobj=$DIRJOB/`$BASENAME $user .f`.o
- basefile=`$BASENAME $usersubname`
- if test ${basefile##*.} = f
- then
- usersub=$DIRJOB/`$BASENAME $user .f`.F
- ln -sf "$user.f" "$usersub"
- else
- usersub=$usersubname
+ echo "Compiling and linking user subroutine $user on host `hostname`"
fi
+ userobj=$usernoext.o
if test $MACHINENAME = "CRAY"
then
- $FORTRAN $usersub || \
+ $DFORTHIGHMP $user || \
{
- echo "$0: compile failed for $user.f"
+ echo "$0: compile failed for $user"
echo " $PRODUCT Exit number 3"
exit 1
}
/bin/rm $program 2>/dev/null
else
- $FORTRAN $usersub -o $userobj || \
+ $DFORTHIGHMP $user -o $userobj || \
{
- echo "$0: compile failed for $user.f"
+ echo "$0: compile failed for $user"
echo " $PRODUCT Exit number 3"
exit 1
}
/bin/rm $program 2>/dev/null
fi
- if test ${basefile##*.} = f
- then
- /bin/rm -f "$usersub"
- fi
fi # if test $user
@@ -3645,6 +3580,7 @@
$TKLIBS \
$MRCLIBS \
$METISLIBS \
+ $DAMASK \
$SFLIB \
$OPENSSL_LIB \
$SYSLIBS \
@@ -3686,6 +3622,9 @@
prgsav=yes
fi # if test $link
/bin/rm $userobj 2>/dev/null
+/bin/rm $DIRJOB/*.mod 2>/dev/null
+/bin/rm $DIRJOB/*.smod 2>/dev/null
+/bin/rm $DIRJOB/*_genmod.f90 2>/dev/null
#
# run marc
@@ -3779,7 +3718,7 @@
else
#dllrun >0
if test $cpdll = yes; then
- filename=`basename $usersubname .f`
+ filename=$usernoext
/bin/cp $DIRJOB/$marcdll $DIRJOB/${filename}_$marcdll 2>/dev/null
fi
if test $rmdll = yes;then
@@ -3904,7 +3843,7 @@
# first copy over the user sub if local directories
if test ${dirstatus[$counter]} = "local"
then
- $RCP $user.f $i:$DIR1/
+ $RCP $user $i:$DIR1/
fi
# do the compilation on the other machine
if test ${dirstatus[$counter]} = "shared"
@@ -3917,20 +3856,20 @@
remoteuser=$DIR1/`$BASENAME $user`
$RSH $i /bin/rm $remoteprog 2> /dev/null
echo
- $RSH $i $DIR2/tools/comp_user $DIR2 $DIR1 $remoteuser $remoteprog
+ $RSH $i $DIR2/tools/comp_damask_hmp $DIR2 $DIR1 $remoteuser $remoteprog
# check if successful, the new executable should be there
line=`$RSH $i /bin/ls $remoteprog 2> /dev/null`
if test "$line"
then
echo compilation and linking successful on host $i
else
- echo "$0: compile failed for $user.f on host $i"
+ echo "$0: compile failed for $user on host $i"
exit 1
fi
# remove the user subroutine on remote machine
if test ${dirstatus[$counter]} = "local"
then
- $RSH $i /bin/rm $remoteuser.f 2> /dev/null
+ $RSH $i /bin/rm $remoteuser 2> /dev/null
fi
fi
fi
@@ -3940,37 +3879,25 @@
if test "$userhost"
then
echo
- echo "Compiling and linking user subroutine $user.f on host `hostname`"
- fi
- userobj=$DIRJOB/`$BASENAME $user .f`.o
- basefile=`$BASENAME $usersubname`
- if test ${basefile##*.} = f
- then
- usersub=$DIRJOB/`$BASENAME $user .f`.F
- ln -sf "$user.f" "$usersub"
- else
- usersub=$usersubname
+ echo "Compiling and linking user subroutine $user on host `hostname`"
fi
+ userobj=$usernoext.o
if test $MACHINENAME = "CRAY"
then
- $FORTRAN $usersub || \
+ $DFORTHIGHMP $user || \
{
- echo "$0: compile failed for $user.f"
+ echo "$0: compile failed for $user"
exit 1
}
/bin/rm $program 2>/dev/null
else
- $FORTRAN $usersub -o $userobj || \
+ $DFORTHIGHMP $user -o $userobj || \
{
- echo "$0: compile failed for $user.f"
+ echo "$0: compile failed for $user"
exit 1
}
/bin/rm $program 2>/dev/null
fi
- if test ${basefile##*.} = f
- then
- /bin/rm -f "$usersub"
- fi
fi # if test $user
@@ -3990,6 +3917,7 @@
$TKLIBS \
$MRCLIBS \
$METISLIBS \
+ $DAMASK \
$SFLIB \
$OPENSSL_LIB \
$SYSLIBS \
@@ -4030,7 +3958,9 @@
prgsav=yes
fi # if test $link
/bin/rm $userobj 2>/dev/null
-
+/bin/rm $DIRJOB/*.mod 2>/dev/null
+/bin/rm $DIRJOB/*.smod 2>/dev/null
+/bin/rm $DIRJOB/*_genmod.f90 2>/dev/null
# done if no job id given
if test -z "$jid"
then
@@ -4149,7 +4079,7 @@
else
#dllrun >0
if test $cpdll = yes; then
- filename=`basename $usersubname .f`
+ filename=$usernoext
/bin/cp $DIRJOB/$marcdll $DIRJOB/${filename}_$marcdll 2>/dev/null
fi
if test $rmdll = yes;then

View File

@ -0,0 +1,517 @@
---
+++
@@ -136,6 +136,11 @@
# is created. For job running in the background, the log #
# file is always created. Default is "yes" #
##############################################################################
+# remove all Mentat paths from LD_LIBRARY_PATH
+LD_LIBRARY_PATH=:$LD_LIBRARY_PATH:
+LD_LIBRARY_PATH=${LD_LIBRARY_PATH//+([!(:)])mentat2022.2+([!(:)])/:}
+LD_LIBRARY_PATH=${LD_LIBRARY_PATH//+([(:)])/:}
+LD_LIBRARY_PATH=${LD_LIBRARY_PATH#:}; LD_LIBRARY_PATH=${LD_LIBRARY_PATH%:}
# set DIR to the directory in which this script is
REALCOM="`/bin/ls -l $0 |awk '{ print $NF; }'`"
DIR=`dirname $REALCOM`
@@ -302,7 +307,23 @@
. "$DIR/getarch"
+
+# getting user subroutine file name
+found=0
+for i in "$@"; do
+ if test $found = 1; then
+ DAMASK_USER=$i
+ found=0
+ fi
+ case $i in
+ -u* | -U*)
+ found=1
+ ;;
+ esac
+done
+# sourcing include_linux64 (needs DAMASK_USER to be set)
. $MARC_INCLUDE
+
#
#
@@ -405,7 +426,7 @@
did=
vid=
user=
-usersubname=
+usernoext=
objs=
qid=background
cpu=
@@ -676,50 +697,19 @@
esac
;;
-u* | -U*)
- user=`dirname $value`/`$BASENAME $value .f`
- usersubname=$user
- basefile=`$BASENAME $value`
- if test ${basefile##*.} = f
- then
- user=`dirname $value`/`$BASENAME $value .f`
- usersubname=$user.f
- elif test ${basefile##*.} = F
- then
- user=`dirname $value`/`$BASENAME $value .F`
- usersubname=$user.F
- elif test ${basefile##*.} = f90
- then
- user=`dirname $value`/`$BASENAME $value .f90`
- usersubname=$user.f90
- elif test ${basefile##*.} = F90
- then
- user=`dirname $value`/`$BASENAME $value .F90`
- usersubname=$user.F90
- fi
+ user=$value
case $user in
\/*)
;;
*)
user=`pwd`/$user
- usersubname=`pwd`/$usersubname
;;
esac
- if test ! -f $usersubname
- then
- if test -f $usersubname.f
- then
- usersubname=$usersubname.f
- elif test -f $usersubname.F
- then
- usersubname=$usersubname.F
- elif test -f $usersubname.f90
- then
- usersubname=$usersubname.f90
- elif test -f $usersubname.F90
- then
- usersubname=$usersubname.F90
- fi
- fi
+ usernoext=$user
+ usernoext=`dirname $usernoext`/`$BASENAME $usernoext .f`
+ usernoext=`dirname $usernoext`/`$BASENAME $usernoext .F`
+ usernoext=`dirname $usernoext`/`$BASENAME $usernoext .for`
+ usernoext=`dirname $usernoext`/`$BASENAME $usernoext .f90`
;;
-obj | -OBJ)
objs="$value"
@@ -1207,12 +1197,12 @@
fi
fi
fi
- if test "$usersubname"
+ if test "$user"
then
- if test ! -f $usersubname
+ if test ! -f $user
then
error="$error
-user subroutine file $usersubname not accessible"
+user subroutine file $user not accessible"
fi
fi
if test "$objs"
@@ -1531,7 +1521,7 @@
Marc shared lib : $progdll
Version type : $mode
Job ID : $DIRJID/$jid$extra_job_info
-User subroutine name : $usersubname
+User subroutine name : $user
User objects/libs : $objs
Restart file job ID : $rid
Substructure file ID : $sid
@@ -1564,7 +1554,7 @@
Marc shared lib : $progdll
Version type : $mode
Job ID : $DIRJID/$jid$extra_job_info
-User subroutine name : $usersubname
+User subroutine name : $user
User objects/libs : $objs
Restart file job ID : $rid
Substructure file ID : $sid
@@ -1687,7 +1677,7 @@
;;
esac
fi
- $ECHO "User subroutine name ($usersubname)? $ECHOTXT"
+ $ECHO "User subroutine name ($user)? $ECHOTXT"
read value
if test "$value"
then
@@ -1696,50 +1686,19 @@
user=
;;
*)
- user=`dirname $value`/`$BASENAME $value .f`
- usersubname=$user
- basefile=`$BASENAME $value`
- if test ${basefile##*.} = f
- then
- user=`dirname $value`/`$BASENAME $value .f`
- usersubname=$user.f
- elif test ${basefile##*.} = F
- then
- user=`dirname $value`/`$BASENAME $value .F`
- usersubname=$user.F
- elif test ${basefile##*.} = f90
- then
- user=`dirname $value`/`$BASENAME $value .f90`
- usersubname=$user.f90
- elif test ${basefile##*.} = F90
- then
- user=`dirname $value`/`$BASENAME $value .F90`
- usersubname=$user.F90
- fi
+ user=$value
case $user in
\/*)
;;
*)
user=`pwd`/$user
- usersubname=`pwd`/$usersubname
;;
esac
- if test ! -f $usersubname
- then
- if test -f $usersubname.f
- then
- usersubname=$usersubname.f
- elif test -f $usersubname.F
- then
- usersubname=$usersubname.F
- elif test -f $usersubname.f90
- then
- usersubname=$usersubname.f90
- elif test -f $usersubname.F90
- then
- usersubname=$usersubname.F90
- fi
- fi
+ usernoext=$user
+ usernoext=`dirname $usernoext`/`$BASENAME $usernoext .f`
+ usernoext=`dirname $usernoext`/`$BASENAME $usernoext .F`
+ usernoext=`dirname $usernoext`/`$BASENAME $usernoext .for`
+ usernoext=`dirname $usernoext`/`$BASENAME $usernoext .f90`
;;
esac
fi
@@ -2274,11 +2233,12 @@
#
# user subroutine used
#
+# add DAMASK options for linking
+ DAMASK="-lstdc++"
if test "$user"
then
-# program=$user.marc
- program=$DIRJOB/`$BASENAME $user .f`.marc
+ program=$usernoext.marc
case $program in
\/* | \.\/*)
bd=
@@ -2391,7 +2351,7 @@
fi
if test "$user"
then
- execpath=$DIRJOB/`$BASENAME $user .f`.marc
+ execpath=$usernoext.marc
usersub=1
fi
export execpath
@@ -3274,44 +3234,27 @@
echo
if test "$user"
then
- userobj=$DIRJOB/`$BASENAME $user .f`.o
- basefile=`$BASENAME $usersubname`
- if test ${basefile##*.} = f
- then
- usersub=$DIRJOB/`$BASENAME $user .f`.F
- ln -sf "$user.f" "$usersub"
- else
- usersub=$usersubname
- fi
-
+ userobj=$usernoext.o
fi
cat > $jid.runmarcscript << END4
if test "$user"
then
- if test ${basefile##*.} = f
- then
- ln -sf "$user.f" "$usersub"
- fi
if test $MACHINENAME = "CRAY"
then
- $FORTRAN $usersub || \
+ $DFORTLOWMP $user || \
{
- echo "$0: compile failed for $user.f"
+ echo "$0: compile failed for $user"
exit 1
}
/bin/rm $program 2>/dev/null
else
- $FORTRAN $usersub -o $userobj || \
+ $DFORTLOWMP $user -o $userobj || \
{
- echo "$0: compile failed for $user.f"
+ echo "$0: compile failed for $user"
exit 1
}
/bin/rm $program 2>/dev/null
fi
- if test ${basefile##*.} = f
- then
- /bin/rm -f "$usersub"
- fi
fi
@@ -3331,6 +3274,7 @@
$TKLIBS \
$MRCLIBS \
$METISLIBS \
+ $DAMASK \
$SFLIB \
$OPENSSL_LIB \
$SYSLIBS \
@@ -3344,6 +3288,9 @@
prgsav=yes
fi
/bin/rm $userobj 2>/dev/null
+/bin/rm $DIRJOB/*.mod 2>/dev/null
+/bin/rm $DIRJOB/*.smod 2>/dev/null
+/bin/rm $DIRJOB/*_genmod.f90 2>/dev/null
#
# run marc
@@ -3390,7 +3337,7 @@
fi
else
if test $cpdll = yes; then
- filename=`basename $usersubname .f`
+ filename=$usernoext
/bin/cp $DIRJOB/$marcdll $DIRJOB/${filename}_$marcdll 2>/dev/null
fi
if test $rmdll = yes
@@ -3556,7 +3503,7 @@
# first copy over the user sub if local directories
if test ${dirstatus[$counter]} = "local"
then
- $RCP $user.f $i:$DIR1/
+ $RCP $user $i:$DIR1/
fi
# do the compilation on the other machine
if test ${dirstatus[$counter]} = "shared"
@@ -3569,21 +3516,21 @@
remoteuser=$DIR1/`$BASENAME $user`
$RSH $i /bin/rm $remoteprog 2> /dev/null
echo
- $RSH $i $DIR2/tools/comp_user $DIR2 $DIR1 $remoteuser $remoteprog
+ $RSH $i $DIR2/tools/comp_damask_lmp $DIR2 $DIR1 $remoteuser $remoteprog
# check if successful, the new executable should be there
line=`$RSH $i /bin/ls $remoteprog 2> /dev/null`
if test "$line"
then
echo compilation and linking successful on host $i
else
- echo "$0: compile failed for $user.f on host $i"
+ echo "$0: compile failed for $user on host $i"
echo " $PRODUCT Exit number 3"
exit 1
fi
# remove the user subroutine on remote machine
if test ${dirstatus[$counter]} = "local"
then
- $RSH $i /bin/rm $remoteuser.f 2> /dev/null
+ $RSH $i /bin/rm $remoteuser 2> /dev/null
fi
fi
fi
@@ -3593,39 +3540,27 @@
if test "$userhost"
then
echo
- echo "Compiling and linking user subroutine $user.f on host `hostname`"
- fi
- userobj=$DIRJOB/`$BASENAME $user .f`.o
- basefile=`$BASENAME $usersubname`
- if test ${basefile##*.} = f
- then
- usersub=$DIRJOB/`$BASENAME $user .f`.F
- ln -sf "$user.f" "$usersub"
- else
- usersub=$usersubname
+ echo "Compiling and linking user subroutine $user on host `hostname`"
fi
+ userobj=$usernoext.o
if test $MACHINENAME = "CRAY"
then
- $FORTRAN $usersub || \
+ $DFORTLOWMP $user || \
{
- echo "$0: compile failed for $user.f"
+ echo "$0: compile failed for $user"
echo " $PRODUCT Exit number 3"
exit 1
}
/bin/rm $program 2>/dev/null
else
- $FORTRAN $usersub -o $userobj || \
+ $DFORTLOWMP $user -o $userobj || \
{
- echo "$0: compile failed for $user.f"
+ echo "$0: compile failed for $user"
echo " $PRODUCT Exit number 3"
exit 1
}
/bin/rm $program 2>/dev/null
fi
- if test ${basefile##*.} = f
- then
- /bin/rm -f "$usersub"
- fi
fi # if test $user
@@ -3645,6 +3580,7 @@
$TKLIBS \
$MRCLIBS \
$METISLIBS \
+ $DAMASK \
$SFLIB \
$OPENSSL_LIB \
$SYSLIBS \
@@ -3686,6 +3622,9 @@
prgsav=yes
fi # if test $link
/bin/rm $userobj 2>/dev/null
+/bin/rm $DIRJOB/*.mod 2>/dev/null
+/bin/rm $DIRJOB/*.smod 2>/dev/null
+/bin/rm $DIRJOB/*_genmod.f90 2>/dev/null
#
# run marc
@@ -3779,7 +3718,7 @@
else
#dllrun >0
if test $cpdll = yes; then
- filename=`basename $usersubname .f`
+ filename=$usernoext
/bin/cp $DIRJOB/$marcdll $DIRJOB/${filename}_$marcdll 2>/dev/null
fi
if test $rmdll = yes;then
@@ -3904,7 +3843,7 @@
# first copy over the user sub if local directories
if test ${dirstatus[$counter]} = "local"
then
- $RCP $user.f $i:$DIR1/
+ $RCP $user $i:$DIR1/
fi
# do the compilation on the other machine
if test ${dirstatus[$counter]} = "shared"
@@ -3917,20 +3856,20 @@
remoteuser=$DIR1/`$BASENAME $user`
$RSH $i /bin/rm $remoteprog 2> /dev/null
echo
- $RSH $i $DIR2/tools/comp_user $DIR2 $DIR1 $remoteuser $remoteprog
+ $RSH $i $DIR2/tools/comp_damask_lmp $DIR2 $DIR1 $remoteuser $remoteprog
# check if successful, the new executable should be there
line=`$RSH $i /bin/ls $remoteprog 2> /dev/null`
if test "$line"
then
echo compilation and linking successful on host $i
else
- echo "$0: compile failed for $user.f on host $i"
+ echo "$0: compile failed for $user on host $i"
exit 1
fi
# remove the user subroutine on remote machine
if test ${dirstatus[$counter]} = "local"
then
- $RSH $i /bin/rm $remoteuser.f 2> /dev/null
+ $RSH $i /bin/rm $remoteuser 2> /dev/null
fi
fi
fi
@@ -3940,37 +3879,25 @@
if test "$userhost"
then
echo
- echo "Compiling and linking user subroutine $user.f on host `hostname`"
- fi
- userobj=$DIRJOB/`$BASENAME $user .f`.o
- basefile=`$BASENAME $usersubname`
- if test ${basefile##*.} = f
- then
- usersub=$DIRJOB/`$BASENAME $user .f`.F
- ln -sf "$user.f" "$usersub"
- else
- usersub=$usersubname
+ echo "Compiling and linking user subroutine $user on host `hostname`"
fi
+ userobj=$usernoext.o
if test $MACHINENAME = "CRAY"
then
- $FORTRAN $usersub || \
+ $DFORTLOWMP $user || \
{
- echo "$0: compile failed for $user.f"
+ echo "$0: compile failed for $user"
exit 1
}
/bin/rm $program 2>/dev/null
else
- $FORTRAN $usersub -o $userobj || \
+ $DFORTLOWMP $user -o $userobj || \
{
- echo "$0: compile failed for $user.f"
+ echo "$0: compile failed for $user"
exit 1
}
/bin/rm $program 2>/dev/null
fi
- if test ${basefile##*.} = f
- then
- /bin/rm -f "$usersub"
- fi
fi # if test $user
@@ -3990,6 +3917,7 @@
$TKLIBS \
$MRCLIBS \
$METISLIBS \
+ $DAMASK \
$SFLIB \
$OPENSSL_LIB \
$SYSLIBS \
@@ -4030,7 +3958,9 @@
prgsav=yes
fi # if test $link
/bin/rm $userobj 2>/dev/null
-
+/bin/rm $DIRJOB/*.mod 2>/dev/null
+/bin/rm $DIRJOB/*.smod 2>/dev/null
+/bin/rm $DIRJOB/*_genmod.f90 2>/dev/null
# done if no job id given
if test -z "$jid"
then
@@ -4149,7 +4079,7 @@
else
#dllrun >0
if test $cpdll = yes; then
- filename=`basename $usersubname .f`
+ filename=$usernoext
/bin/cp $DIRJOB/$marcdll $DIRJOB/${filename}_$marcdll 2>/dev/null
fi
if test $rmdll = yes;then

View File

@ -0,0 +1,517 @@
---
+++
@@ -136,6 +136,11 @@
# is created. For job running in the background, the log #
# file is always created. Default is "yes" #
##############################################################################
+# remove all Mentat paths from LD_LIBRARY_PATH
+LD_LIBRARY_PATH=:$LD_LIBRARY_PATH:
+LD_LIBRARY_PATH=${LD_LIBRARY_PATH//+([!(:)])mentat2022.2+([!(:)])/:}
+LD_LIBRARY_PATH=${LD_LIBRARY_PATH//+([(:)])/:}
+LD_LIBRARY_PATH=${LD_LIBRARY_PATH#:}; LD_LIBRARY_PATH=${LD_LIBRARY_PATH%:}
# set DIR to the directory in which this script is
REALCOM="`/bin/ls -l $0 |awk '{ print $NF; }'`"
DIR=`dirname $REALCOM`
@@ -302,7 +307,23 @@
. "$DIR/getarch"
+
+# getting user subroutine file name
+found=0
+for i in "$@"; do
+ if test $found = 1; then
+ DAMASK_USER=$i
+ found=0
+ fi
+ case $i in
+ -u* | -U*)
+ found=1
+ ;;
+ esac
+done
+# sourcing include_linux64 (needs DAMASK_USER to be set)
. $MARC_INCLUDE
+
#
#
@@ -405,7 +426,7 @@
did=
vid=
user=
-usersubname=
+usernoext=
objs=
qid=background
cpu=
@@ -676,50 +697,19 @@
esac
;;
-u* | -U*)
- user=`dirname $value`/`$BASENAME $value .f`
- usersubname=$user
- basefile=`$BASENAME $value`
- if test ${basefile##*.} = f
- then
- user=`dirname $value`/`$BASENAME $value .f`
- usersubname=$user.f
- elif test ${basefile##*.} = F
- then
- user=`dirname $value`/`$BASENAME $value .F`
- usersubname=$user.F
- elif test ${basefile##*.} = f90
- then
- user=`dirname $value`/`$BASENAME $value .f90`
- usersubname=$user.f90
- elif test ${basefile##*.} = F90
- then
- user=`dirname $value`/`$BASENAME $value .F90`
- usersubname=$user.F90
- fi
+ user=$value
case $user in
\/*)
;;
*)
user=`pwd`/$user
- usersubname=`pwd`/$usersubname
;;
esac
- if test ! -f $usersubname
- then
- if test -f $usersubname.f
- then
- usersubname=$usersubname.f
- elif test -f $usersubname.F
- then
- usersubname=$usersubname.F
- elif test -f $usersubname.f90
- then
- usersubname=$usersubname.f90
- elif test -f $usersubname.F90
- then
- usersubname=$usersubname.F90
- fi
- fi
+ usernoext=$user
+ usernoext=`dirname $usernoext`/`$BASENAME $usernoext .f`
+ usernoext=`dirname $usernoext`/`$BASENAME $usernoext .F`
+ usernoext=`dirname $usernoext`/`$BASENAME $usernoext .for`
+ usernoext=`dirname $usernoext`/`$BASENAME $usernoext .f90`
;;
-obj | -OBJ)
objs="$value"
@@ -1207,12 +1197,12 @@
fi
fi
fi
- if test "$usersubname"
+ if test "$user"
then
- if test ! -f $usersubname
+ if test ! -f $user
then
error="$error
-user subroutine file $usersubname not accessible"
+user subroutine file $user not accessible"
fi
fi
if test "$objs"
@@ -1531,7 +1521,7 @@
Marc shared lib : $progdll
Version type : $mode
Job ID : $DIRJID/$jid$extra_job_info
-User subroutine name : $usersubname
+User subroutine name : $user
User objects/libs : $objs
Restart file job ID : $rid
Substructure file ID : $sid
@@ -1564,7 +1554,7 @@
Marc shared lib : $progdll
Version type : $mode
Job ID : $DIRJID/$jid$extra_job_info
-User subroutine name : $usersubname
+User subroutine name : $user
User objects/libs : $objs
Restart file job ID : $rid
Substructure file ID : $sid
@@ -1687,7 +1677,7 @@
;;
esac
fi
- $ECHO "User subroutine name ($usersubname)? $ECHOTXT"
+ $ECHO "User subroutine name ($user)? $ECHOTXT"
read value
if test "$value"
then
@@ -1696,50 +1686,19 @@
user=
;;
*)
- user=`dirname $value`/`$BASENAME $value .f`
- usersubname=$user
- basefile=`$BASENAME $value`
- if test ${basefile##*.} = f
- then
- user=`dirname $value`/`$BASENAME $value .f`
- usersubname=$user.f
- elif test ${basefile##*.} = F
- then
- user=`dirname $value`/`$BASENAME $value .F`
- usersubname=$user.F
- elif test ${basefile##*.} = f90
- then
- user=`dirname $value`/`$BASENAME $value .f90`
- usersubname=$user.f90
- elif test ${basefile##*.} = F90
- then
- user=`dirname $value`/`$BASENAME $value .F90`
- usersubname=$user.F90
- fi
+ user=$value
case $user in
\/*)
;;
*)
user=`pwd`/$user
- usersubname=`pwd`/$usersubname
;;
esac
- if test ! -f $usersubname
- then
- if test -f $usersubname.f
- then
- usersubname=$usersubname.f
- elif test -f $usersubname.F
- then
- usersubname=$usersubname.F
- elif test -f $usersubname.f90
- then
- usersubname=$usersubname.f90
- elif test -f $usersubname.F90
- then
- usersubname=$usersubname.F90
- fi
- fi
+ usernoext=$user
+ usernoext=`dirname $usernoext`/`$BASENAME $usernoext .f`
+ usernoext=`dirname $usernoext`/`$BASENAME $usernoext .F`
+ usernoext=`dirname $usernoext`/`$BASENAME $usernoext .for`
+ usernoext=`dirname $usernoext`/`$BASENAME $usernoext .f90`
;;
esac
fi
@@ -2274,11 +2233,12 @@
#
# user subroutine used
#
+# add DAMASK options for linking
+ DAMASK="-lstdc++"
if test "$user"
then
-# program=$user.marc
- program=$DIRJOB/`$BASENAME $user .f`.marc
+ program=$usernoext.marc
case $program in
\/* | \.\/*)
bd=
@@ -2391,7 +2351,7 @@
fi
if test "$user"
then
- execpath=$DIRJOB/`$BASENAME $user .f`.marc
+ execpath=$usernoext.marc
usersub=1
fi
export execpath
@@ -3274,44 +3234,27 @@
echo
if test "$user"
then
- userobj=$DIRJOB/`$BASENAME $user .f`.o
- basefile=`$BASENAME $usersubname`
- if test ${basefile##*.} = f
- then
- usersub=$DIRJOB/`$BASENAME $user .f`.F
- ln -sf "$user.f" "$usersub"
- else
- usersub=$usersubname
- fi
-
+ userobj=$usernoext.o
fi
cat > $jid.runmarcscript << END4
if test "$user"
then
- if test ${basefile##*.} = f
- then
- ln -sf "$user.f" "$usersub"
- fi
if test $MACHINENAME = "CRAY"
then
- $FORTRAN $usersub || \
+ $DFORTRANMP $user || \
{
- echo "$0: compile failed for $user.f"
+ echo "$0: compile failed for $user"
exit 1
}
/bin/rm $program 2>/dev/null
else
- $FORTRAN $usersub -o $userobj || \
+ $DFORTRANMP $user -o $userobj || \
{
- echo "$0: compile failed for $user.f"
+ echo "$0: compile failed for $user"
exit 1
}
/bin/rm $program 2>/dev/null
fi
- if test ${basefile##*.} = f
- then
- /bin/rm -f "$usersub"
- fi
fi
@@ -3331,6 +3274,7 @@
$TKLIBS \
$MRCLIBS \
$METISLIBS \
+ $DAMASK \
$SFLIB \
$OPENSSL_LIB \
$SYSLIBS \
@@ -3344,6 +3288,9 @@
prgsav=yes
fi
/bin/rm $userobj 2>/dev/null
+/bin/rm $DIRJOB/*.mod 2>/dev/null
+/bin/rm $DIRJOB/*.smod 2>/dev/null
+/bin/rm $DIRJOB/*_genmod.f90 2>/dev/null
#
# run marc
@@ -3390,7 +3337,7 @@
fi
else
if test $cpdll = yes; then
- filename=`basename $usersubname .f`
+ filename=$usernoext
/bin/cp $DIRJOB/$marcdll $DIRJOB/${filename}_$marcdll 2>/dev/null
fi
if test $rmdll = yes
@@ -3556,7 +3503,7 @@
# first copy over the user sub if local directories
if test ${dirstatus[$counter]} = "local"
then
- $RCP $user.f $i:$DIR1/
+ $RCP $user $i:$DIR1/
fi
# do the compilation on the other machine
if test ${dirstatus[$counter]} = "shared"
@@ -3569,21 +3516,21 @@
remoteuser=$DIR1/`$BASENAME $user`
$RSH $i /bin/rm $remoteprog 2> /dev/null
echo
- $RSH $i $DIR2/tools/comp_user $DIR2 $DIR1 $remoteuser $remoteprog
+ $RSH $i $DIR2/tools/comp_damask_mp $DIR2 $DIR1 $remoteuser $remoteprog
# check if successful, the new executable should be there
line=`$RSH $i /bin/ls $remoteprog 2> /dev/null`
if test "$line"
then
echo compilation and linking successful on host $i
else
- echo "$0: compile failed for $user.f on host $i"
+ echo "$0: compile failed for $user on host $i"
echo " $PRODUCT Exit number 3"
exit 1
fi
# remove the user subroutine on remote machine
if test ${dirstatus[$counter]} = "local"
then
- $RSH $i /bin/rm $remoteuser.f 2> /dev/null
+ $RSH $i /bin/rm $remoteuser 2> /dev/null
fi
fi
fi
@@ -3593,39 +3540,27 @@
if test "$userhost"
then
echo
- echo "Compiling and linking user subroutine $user.f on host `hostname`"
- fi
- userobj=$DIRJOB/`$BASENAME $user .f`.o
- basefile=`$BASENAME $usersubname`
- if test ${basefile##*.} = f
- then
- usersub=$DIRJOB/`$BASENAME $user .f`.F
- ln -sf "$user.f" "$usersub"
- else
- usersub=$usersubname
+ echo "Compiling and linking user subroutine $user on host `hostname`"
fi
+ userobj=$usernoext.o
if test $MACHINENAME = "CRAY"
then
- $FORTRAN $usersub || \
+ $DFORTRANMP $user || \
{
- echo "$0: compile failed for $user.f"
+ echo "$0: compile failed for $user"
echo " $PRODUCT Exit number 3"
exit 1
}
/bin/rm $program 2>/dev/null
else
- $FORTRAN $usersub -o $userobj || \
+ $DFORTRANMP $user -o $userobj || \
{
- echo "$0: compile failed for $user.f"
+ echo "$0: compile failed for $user"
echo " $PRODUCT Exit number 3"
exit 1
}
/bin/rm $program 2>/dev/null
fi
- if test ${basefile##*.} = f
- then
- /bin/rm -f "$usersub"
- fi
fi # if test $user
@@ -3645,6 +3580,7 @@
$TKLIBS \
$MRCLIBS \
$METISLIBS \
+ $DAMASK \
$SFLIB \
$OPENSSL_LIB \
$SYSLIBS \
@@ -3686,6 +3622,9 @@
prgsav=yes
fi # if test $link
/bin/rm $userobj 2>/dev/null
+/bin/rm $DIRJOB/*.mod 2>/dev/null
+/bin/rm $DIRJOB/*.smod 2>/dev/null
+/bin/rm $DIRJOB/*_genmod.f90 2>/dev/null
#
# run marc
@@ -3779,7 +3718,7 @@
else
#dllrun >0
if test $cpdll = yes; then
- filename=`basename $usersubname .f`
+ filename=$usernoext
/bin/cp $DIRJOB/$marcdll $DIRJOB/${filename}_$marcdll 2>/dev/null
fi
if test $rmdll = yes;then
@@ -3904,7 +3843,7 @@
# first copy over the user sub if local directories
if test ${dirstatus[$counter]} = "local"
then
- $RCP $user.f $i:$DIR1/
+ $RCP $user $i:$DIR1/
fi
# do the compilation on the other machine
if test ${dirstatus[$counter]} = "shared"
@@ -3917,20 +3856,20 @@
remoteuser=$DIR1/`$BASENAME $user`
$RSH $i /bin/rm $remoteprog 2> /dev/null
echo
- $RSH $i $DIR2/tools/comp_user $DIR2 $DIR1 $remoteuser $remoteprog
+ $RSH $i $DIR2/tools/comp_damask_mp $DIR2 $DIR1 $remoteuser $remoteprog
# check if successful, the new executable should be there
line=`$RSH $i /bin/ls $remoteprog 2> /dev/null`
if test "$line"
then
echo compilation and linking successful on host $i
else
- echo "$0: compile failed for $user.f on host $i"
+ echo "$0: compile failed for $user on host $i"
exit 1
fi
# remove the user subroutine on remote machine
if test ${dirstatus[$counter]} = "local"
then
- $RSH $i /bin/rm $remoteuser.f 2> /dev/null
+ $RSH $i /bin/rm $remoteuser 2> /dev/null
fi
fi
fi
@@ -3940,37 +3879,25 @@
if test "$userhost"
then
echo
- echo "Compiling and linking user subroutine $user.f on host `hostname`"
- fi
- userobj=$DIRJOB/`$BASENAME $user .f`.o
- basefile=`$BASENAME $usersubname`
- if test ${basefile##*.} = f
- then
- usersub=$DIRJOB/`$BASENAME $user .f`.F
- ln -sf "$user.f" "$usersub"
- else
- usersub=$usersubname
+ echo "Compiling and linking user subroutine $user on host `hostname`"
fi
+ userobj=$usernoext.o
if test $MACHINENAME = "CRAY"
then
- $FORTRAN $usersub || \
+ $DFORTRANMP $user || \
{
- echo "$0: compile failed for $user.f"
+ echo "$0: compile failed for $user"
exit 1
}
/bin/rm $program 2>/dev/null
else
- $FORTRAN $usersub -o $userobj || \
+ $DFORTRANMP $user -o $userobj || \
{
- echo "$0: compile failed for $user.f"
+ echo "$0: compile failed for $user"
exit 1
}
/bin/rm $program 2>/dev/null
fi
- if test ${basefile##*.} = f
- then
- /bin/rm -f "$usersub"
- fi
fi # if test $user
@@ -3990,6 +3917,7 @@
$TKLIBS \
$MRCLIBS \
$METISLIBS \
+ $DAMASK \
$SFLIB \
$OPENSSL_LIB \
$SYSLIBS \
@@ -4030,7 +3958,9 @@
prgsav=yes
fi # if test $link
/bin/rm $userobj 2>/dev/null
-
+/bin/rm $DIRJOB/*.mod 2>/dev/null
+/bin/rm $DIRJOB/*.smod 2>/dev/null
+/bin/rm $DIRJOB/*_genmod.f90 2>/dev/null
# done if no job id given
if test -z "$jid"
then
@@ -4149,7 +4079,7 @@
else
#dllrun >0
if test $cpdll = yes; then
- filename=`basename $usersubname .f`
+ filename=$usernoext
/bin/cp $DIRJOB/$marcdll $DIRJOB/${filename}_$marcdll 2>/dev/null
fi
if test $rmdll = yes;then

View File

@ -0,0 +1,24 @@
---
+++
@@ -1,18 +1,5 @@
#!/bin/sh
-# This script opens a window running an editor. The default window is an
-# xterm, and the default editor is vi. These may be customized.
+# This script opens a window running an editor.
+# The command to invoke the editor is specified during DAMASK installation
-dir=
-for d in /usr/bin /usr/bin/X11; do
- if test -x "$d/xterm"; then
- dir="$d"
- break
- fi
-done
-
-if test -z "$dir"; then
- echo "$0: Could not find xterm"
- exit 1
-fi
-
-"$dir/xterm" -T "vi $*" -n "vi $*" -e vi $*
+%EDITOR% $*

View File

View File

View File

View File

@ -0,0 +1,38 @@
---
+++
@@ -63,10 +63,10 @@
if [ "$slv" != "" -a "$slv" != "marc" -a "$slv" != "datfit" ]; then
slv="-iam sfm"
fi
-if [ "$slv" == "marc" ]; then
+if [ "$slv" = "marc" ]; then
slv=""
fi
-if [ "$slv" == "datfit" ]; then
+if [ "$slv" = "datfit" ]; then
slv="-iam datfit"
fi
@@ -91,6 +91,7 @@
srcfile="-u $srcfile -save y"
;;
runsaved)
+ srcfile=${srcfile%.*}".marc"
srcfile="-prog $srcfile"
;;
esac
@@ -189,12 +190,12 @@
unset PYTHONPATH
if [ "$doe_first" = "-" ]; then # submit of regular Marc job
- "${DIR}/tools/run_marc" $slv -j $job -v n -b y $nprocds $nprocd \
+ "${DIR}/tools/run_damask_hmp" $slv -j $job -v n -b y $nprocds $nprocd \
$srcfile $restart $postfile $viewfactorsfile $hostfile \
$compat $copy_datfile $copy_postfile $scr_dir $dcoup \
$assem_recov_nthread $nthread $nsolver $mode $gpu > /dev/null 2>&1
else # submit of a DoE Marc job
- "${DIR}/tools/run_marc" $slv -j $job -v n -b n $nprocds $nprocd \
+ "${DIR}/tools/run_damask_hmp" $slv -j $job -v n -b n $nprocds $nprocd \
$srcfile $restart $postfile $viewfactorsfile $hostfile \
$compat $copy_datfile $copy_postfile $scr_dir $dcoup \
$assem_recov_nthread $nthread $nsolver $mode $gpu

View File

@ -0,0 +1,38 @@
---
+++
@@ -63,10 +63,10 @@
if [ "$slv" != "" -a "$slv" != "marc" -a "$slv" != "datfit" ]; then
slv="-iam sfm"
fi
-if [ "$slv" == "marc" ]; then
+if [ "$slv" = "marc" ]; then
slv=""
fi
-if [ "$slv" == "datfit" ]; then
+if [ "$slv" = "datfit" ]; then
slv="-iam datfit"
fi
@@ -91,6 +91,7 @@
srcfile="-u $srcfile -save y"
;;
runsaved)
+ srcfile=${srcfile%.*}".marc"
srcfile="-prog $srcfile"
;;
esac
@@ -189,12 +190,12 @@
unset PYTHONPATH
if [ "$doe_first" = "-" ]; then # submit of regular Marc job
- "${DIR}/tools/run_marc" $slv -j $job -v n -b y $nprocds $nprocd \
+ "${DIR}/tools/run_damask_mp" $slv -j $job -v n -b y $nprocds $nprocd \
$srcfile $restart $postfile $viewfactorsfile $hostfile \
$compat $copy_datfile $copy_postfile $scr_dir $dcoup \
$assem_recov_nthread $nthread $nsolver $mode $gpu > /dev/null 2>&1
else # submit of a DoE Marc job
- "${DIR}/tools/run_marc" $slv -j $job -v n -b n $nprocds $nprocd \
+ "${DIR}/tools/run_damask_mp" $slv -j $job -v n -b n $nprocds $nprocd \
$srcfile $restart $postfile $viewfactorsfile $hostfile \
$compat $copy_datfile $copy_postfile $scr_dir $dcoup \
$assem_recov_nthread $nthread $nsolver $mode $gpu

View File

@ -0,0 +1,38 @@
---
+++
@@ -63,10 +63,10 @@
if [ "$slv" != "" -a "$slv" != "marc" -a "$slv" != "datfit" ]; then
slv="-iam sfm"
fi
-if [ "$slv" == "marc" ]; then
+if [ "$slv" = "marc" ]; then
slv=""
fi
-if [ "$slv" == "datfit" ]; then
+if [ "$slv" = "datfit" ]; then
slv="-iam datfit"
fi
@@ -91,6 +91,7 @@
srcfile="-u $srcfile -save y"
;;
runsaved)
+ srcfile=${srcfile%.*}".marc"
srcfile="-prog $srcfile"
;;
esac
@@ -189,12 +190,12 @@
unset PYTHONPATH
if [ "$doe_first" = "-" ]; then # submit of regular Marc job
- "${DIR}/tools/run_marc" $slv -j $job -v n -b y $nprocds $nprocd \
+ "${DIR}/tools/run_damask_lmp" $slv -j $job -v n -b y $nprocds $nprocd \
$srcfile $restart $postfile $viewfactorsfile $hostfile \
$compat $copy_datfile $copy_postfile $scr_dir $dcoup \
$assem_recov_nthread $nthread $nsolver $mode $gpu > /dev/null 2>&1
else # submit of a DoE Marc job
- "${DIR}/tools/run_marc" $slv -j $job -v n -b n $nprocds $nprocd \
+ "${DIR}/tools/run_damask_lmp" $slv -j $job -v n -b n $nprocds $nprocd \
$srcfile $restart $postfile $viewfactorsfile $hostfile \
$compat $copy_datfile $copy_postfile $scr_dir $dcoup \
$assem_recov_nthread $nthread $nsolver $mode $gpu

View File

@ -0,0 +1,158 @@
---
+++
@@ -261,11 +261,18 @@
}
button {
position +25 =
- size 25 4
+ size 18 4
text "ADVANCED JOB SUBMISSION"
help "job_run#Job Submission And Control"
popmenu job_submit_adv_pm
}
+ button {
+ position +18 =
+ size 7 4
+ text "DAMASK"
+ help "damask_run#Job Submission And Control"
+ popmenu damask
+ }
button {
position 0 +4
size 16 4
@@ -1202,6 +1209,135 @@
}
+#--------------------------------------------------------------------------------------------------
+popmenu damask {
+
+#ifdef QT_MENTAT
+ text "DAMASK.MPIE.DE"
+#endif
+
+ group {
+#ifndef QT_MENTAT
+ label {
+ position 0 0
+ size 50 4
+ text "DAMASK.MPIE.DE"
+ }
+#endif
+
+ label {
+ position 1 6
+ size 13 6
+ text "Optimzation"
+ border_width 1
+ border_color black
+ }
+
+ label {
+ position +13 =
+ size 20 6
+ text "write Input"
+ border_width 1
+ border_color black
+ }
+
+ label {
+ position +18 =
+ size 30 6
+ text "do not write Inp."
+ border_width 1
+ border_color black
+ }
+
+ label {
+ position -32 +6
+ size 12 6
+ text "O3 / OpenMP"
+ border_width 1
+ border_color black
+ }
+
+ popdown {
+ position +12 =
+ size 20 6
+ text "Submit"
+ command "*submit_job 4 *monitor_job"
+ }
+
+ popdown {
+ position +20 =
+ size 20 6
+ text "Execute"
+ command "*execute_job 4 *monitor_job"
+ }
+
+ label {
+ position -32 +6
+ size 12 6
+ text "O1 / OpenMP"
+ border_width 1
+ border_color black
+ }
+
+ popdown {
+ position +12 =
+ size 20 6
+ text "Submit"
+ command "*submit_job 5 *monitor_job"
+ }
+
+ popdown {
+ position +20 =
+ size 20 6
+ text "Execute"
+ command "*execute_job 5 *monitor_job"
+ }
+
+ label {
+ position -32 +6
+ size 12 6
+ text "O0 / OpenMP"
+ border_width 1
+ border_color black
+ }
+
+ popdown {
+ position +12 =
+ size 20 6
+ text "Submit"
+ command "*submit_job 6 *monitor_job"
+ }
+
+ popdown {
+ position +20 =
+ size 20 6
+ text "Execute"
+ command "*execute_job 6 *monitor_job"
+ }
+
+ popdown {
+ position 19 +8
+ size 12 8
+ text "CANCEL"
+ }
+}
+
+ window {
+ parent mentat
+ origin 38 8
+#ifdef DCOM
+ size 50 100
+#else
+ size 50 94
+#endif
+ background_color body
+ border_width 1
+ border_color border
+ buffering single
+ }
+ mode permanent
+}
+
#--------------------------------------------------------------------------------------------------
popmenu job_exit_msg_pm {

View File

@ -9,9 +9,12 @@ from pathlib import Path
import subprocess import subprocess
import shlex import shlex
sys.path.append(str(Path(__file__).parents[2]/'python/damask')) sys.path.append(str(Path(__file__).resolve().parents[2]/'python/damask'))
import solver import solver
APPLY = 'install'
RESTORE = 'uninstall'
def copy_and_patch(patch,orig,editor): def copy_and_patch(patch,orig,editor):
try: try:
shutil.copyfile(orig,orig.parent/patch.stem) shutil.copyfile(orig,orig.parent/patch.stem)
@ -25,9 +28,11 @@ def copy_and_patch(patch,orig,editor):
parser = argparse.ArgumentParser( parser = argparse.ArgumentParser(
description='Apply DAMASK modification to MSC Marc/Mentat', description=f'{APPLY.capitalize()} or {RESTORE} DAMASK modifications to MSC Marc/Mentat',
formatter_class=argparse.ArgumentDefaultsHelpFormatter) formatter_class=argparse.ArgumentDefaultsHelpFormatter)
parser.add_argument('command', metavar='command', nargs='?', default=APPLY, choices=[APPLY,RESTORE],
help=f'Mode of operation {[APPLY,RESTORE]}')
parser.add_argument('--editor', dest='editor', metavar='string', default='vi', parser.add_argument('--editor', dest='editor', metavar='string', default='vi',
help='Name of the editor (executable) used by Marc Mentat') help='Name of the editor (executable) used by Marc Mentat')
parser.add_argument('--marc-root', dest='marc_root', metavar='string', parser.add_argument('--marc-root', dest='marc_root', metavar='string',
@ -40,10 +45,10 @@ parser.add_argument('--damask-root', dest='damask_root', metavar = 'string',
default=solver._marc._damask_root, default=solver._marc._damask_root,
help='DAMASK root directory') help='DAMASK root directory')
args = parser.parse_args() args = parser.parse_args()
marc_root = Path(args.marc_root).expanduser()
damask_root = Path(args.damask_root).expanduser() damask_root = Path(args.damask_root).expanduser()
marc_root = Path(args.marc_root).expanduser()
marc_version = args.marc_version marc_version = args.marc_version
matches = {'Marc_tools': [['comp_user','comp_damask_*mp'], matches = {'Marc_tools': [['comp_user','comp_damask_*mp'],
@ -54,23 +59,41 @@ matches = {'Marc_tools': [['comp_user','comp_damask_*mp'],
['kill1','kill?']], ['kill1','kill?']],
'Mentat_menus':[['job_run.ms','job_run.ms']]} 'Mentat_menus':[['job_run.ms','job_run.ms']]}
for cmd in ['patch','xvfb-run']: for cmd in ['xvfb-run','patch'] if args.command == APPLY else ['xvfb-run'] if args.command == RESTORE else []:
try: try:
subprocess.run(shlex.split(f'{cmd} --help')) subprocess.run([cmd,'--help'], capture_output=True)
except FileNotFoundError: except FileNotFoundError:
print(f'"{cmd}" not found, please install') print(f'"{cmd}" not found, please install')
sys.exit() sys.exit()
if args.command == APPLY:
print('patching files...') print('patching files...')
for directory in glob.glob(str(damask_root/'install/MarcMentat'/marc_version/'*')): for directory in glob.glob(str(damask_root/'install/MarcMentat'/marc_version/'*')):
for orig, mods in matches[Path(directory).name]: for orig, mods in matches[Path(directory).name]:
product,subfolder = (marc_root/Path(directory)).name.split('_') product,subfolder = (marc_root/directory).name.split('_')
orig = marc_root/f'{product.lower()}{marc_version}/{subfolder}/{orig}' orig = marc_root/f'{product.lower()}{marc_version}/{subfolder}/{orig}'
for patch in glob.glob(f'{directory}/{mods}.patch'): for patch in glob.glob(f'{directory}/{mods}.patch'):
copy_and_patch(Path(patch),orig,args.editor) copy_and_patch(Path(patch),orig,args.editor)
elif args.command == RESTORE:
print('deleting modified files...')
for file in (glob.glob(str(marc_root/f'marc{marc_version}/tools/*_damask*')) +
glob.glob(str(marc_root/f'mentat{marc_version}/bin/kill[4-6]')) +
glob.glob(str(marc_root/f'mentat{marc_version}/bin/submit[4-6]*'))):
os.remove(file)
print('restoring original files...')
for file in (glob.glob(str(marc_root/f'marc{marc_version}/tools/include_linux64.orig')) +
glob.glob(str(marc_root/f'mentat{marc_version}/bin/edit_window.orig')) +
glob.glob(str(marc_root/f'mentat{marc_version}/menus/job_run.ms.orig'))):
shutil.copyfile(file,Path(file).with_suffix(''))
os.remove(file)
else:
print('skipping file modifications...')
print('compiling Mentat menu binaries...') print('compiling Mentat menu binaries...')
executable = marc_root/f'mentat{marc_version}/bin/mentat' executable = marc_root/f'mentat{marc_version}/bin/mentat'
@ -79,8 +102,10 @@ subprocess.run(shlex.split(f'xvfb-run -a {executable} -compile {menu_file}'))
print('setting file access rights...') print('setting file access rights...')
for file in (glob.glob(str(marc_root/f'marc{marc_version}/tools/*_damask*')) + for file in (
glob.glob(str(marc_root/f'mentat{marc_version}/bin/edit_window')) + (glob.glob(str(marc_root/f'marc{marc_version}/tools/*_damask*')) +
glob.glob(str(marc_root/f'mentat{marc_version}/bin/kill[4-6]')) + glob.glob(str(marc_root/f'mentat{marc_version}/bin/kill[4-6]')) +
glob.glob(str(marc_root/f'mentat{marc_version}/bin/submit[4-6]'))): glob.glob(str(marc_root/f'mentat{marc_version}/bin/submit[4-6]')) if args.command == APPLY else []) +
glob.glob(str(marc_root/f'mentat{marc_version}/bin/edit_window'))
):
os.chmod(file , 0o755) os.chmod(file , 0o755)

View File

@ -1,7 +1,12 @@
Install DAMASK modifications to use DAMASK_marc Install or uninstall DAMASK modifications to MSC Marc/Mentat.
This is for the Linux64 version of Marc/Mentat This is for the Linux64 version of Marc/Mentat.
Refer to http://damask.mpie.de for complete installation instructions. usage: MSC_modifications.py [-h] [--editor string] [--marc-root string] [--marc-version string] [--damask-root string]
[command]
where command is either 'install' or 'uninstall'
Refer to https://damask.mpie.de/installation/source_code.html#msc-marc for complete installation instructions.
Usually you will need to be root for this to work! Usually you will need to be root for this to work!
@ -9,6 +14,6 @@ See Marc and Mentat Release Guide for List of Build and Supported Platforms.
The Intel Fortran compiler needs to be installed. The Intel Fortran compiler needs to be installed.
1) Install Marc, Mentat and Documentation as usual 1) Install Marc, Mentat, and Documentation as usual.
Run the test example including subroutines to confirm that the installation of both Marc/Mentat and the Intel Fortran Compiler is ok. Run the test example including subroutines to confirm that the installation of both Marc/Mentat and the Intel Fortran Compiler is ok.
2) Run the apply_DAMASK_modifications.py script from this directory. 2) Run the MSC_modifications.py script from this directory.

View File

@ -2,7 +2,8 @@ import os
import json import json
import functools import functools
import colorsys import colorsys
from typing import Union, TextIO from typing import Optional, Union, TextIO
from itertools import chain
import numpy as np import numpy as np
import scipy.interpolate as interp import scipy.interpolate as interp
@ -248,7 +249,7 @@ class Colormap(mpl.colors.ListedColormap):
Parameters Parameters
---------- ----------
fraction : float or sequence of float fraction : (sequence of) float
Fractional coordinate(s) to evaluate Colormap at. Fractional coordinate(s) to evaluate Colormap at.
Returns Returns
@ -274,8 +275,8 @@ class Colormap(mpl.colors.ListedColormap):
def shade(self, def shade(self,
field: np.ndarray, field: np.ndarray,
bounds: FloatSequence = None, bounds: Optional[FloatSequence] = None,
gap: float = None) -> Image: gap: Optional[float] = None) -> Image:
""" """
Generate PIL image of 2D field using colormap. Generate PIL image of 2D field using colormap.
@ -314,7 +315,7 @@ class Colormap(mpl.colors.ListedColormap):
def reversed(self, def reversed(self,
name: str = None) -> 'Colormap': name: Optional[str] = None) -> 'Colormap':
""" """
Reverse. Reverse.
@ -363,7 +364,7 @@ class Colormap(mpl.colors.ListedColormap):
def save_paraview(self, def save_paraview(self,
fname: FileHandle = None): fname: Optional[FileHandle] = None):
""" """
Save as JSON file for use in Paraview. Save as JSON file for use in Paraview.
@ -373,16 +374,12 @@ class Colormap(mpl.colors.ListedColormap):
File to store results. Defaults to colormap name + '.json'. File to store results. Defaults to colormap name + '.json'.
""" """
colors = []
for i,c in enumerate(np.round(self.colors,6).tolist()):
colors+=[i]+c
out = [{ out = [{
'Creator':util.execution_stamp('Colormap'), 'Creator':util.execution_stamp('Colormap'),
'ColorSpace':'RGB', 'ColorSpace':'RGB',
'Name':self.name, 'Name':self.name,
'DefaultMap':True, 'DefaultMap':True,
'RGBPoints':colors 'RGBPoints':list(chain.from_iterable([(i,*c) for i,c in enumerate(self.colors.round(6))]))
}] }]
fhandle = self._get_file_handle(fname,'.json') fhandle = self._get_file_handle(fname,'.json')
@ -391,7 +388,7 @@ class Colormap(mpl.colors.ListedColormap):
def save_ASCII(self, def save_ASCII(self,
fname: FileHandle = None): fname: Optional[FileHandle] = None):
""" """
Save as ASCII file. Save as ASCII file.
@ -406,7 +403,7 @@ class Colormap(mpl.colors.ListedColormap):
t.save(self._get_file_handle(fname,'.txt')) t.save(self._get_file_handle(fname,'.txt'))
def save_GOM(self, fname: FileHandle = None): def save_GOM(self, fname: Optional[FileHandle] = None):
""" """
Save as ASCII file for use in GOM Aramis. Save as ASCII file for use in GOM Aramis.
@ -427,7 +424,7 @@ class Colormap(mpl.colors.ListedColormap):
def save_gmsh(self, def save_gmsh(self,
fname: FileHandle = None): fname: Optional[FileHandle] = None):
""" """
Save as ASCII file for use in gmsh. Save as ASCII file for use in gmsh.

View File

@ -2,7 +2,7 @@ import copy
from io import StringIO from io import StringIO
from collections.abc import Iterable from collections.abc import Iterable
import abc import abc
from typing import Union, Dict, Any, Type, TypeVar from typing import Optional, Union, Dict, Any, Type, TypeVar
import numpy as np import numpy as np
import yaml import yaml
@ -21,7 +21,7 @@ class NiceDumper(yaml.SafeDumper):
"""Make YAML readable for humans.""" """Make YAML readable for humans."""
def write_line_break(self, def write_line_break(self,
data: str = None): data: Optional[str] = None):
super().write_line_break(data) super().write_line_break(data)
if len(self.indents) == 1: if len(self.indents) == 1:
@ -53,7 +53,7 @@ class Config(dict):
"""YAML-based configuration.""" """YAML-based configuration."""
def __init__(self, def __init__(self,
yml: Union[str, Dict[str, Any]] = None, yml: Union[None, str, Dict[str, Any]] = None,
**kwargs): **kwargs):
"""Initialize from YAML, dict, or key=value pairs.""" """Initialize from YAML, dict, or key=value pairs."""
if isinstance(yml,str): if isinstance(yml,str):

View File

@ -1,6 +1,6 @@
import numpy as np import numpy as np
import h5py import h5py
from typing import Sequence, Dict, Any, Collection from typing import Optional, Union, Sequence, Dict, Any, Collection
from ._typehints import FileHandle from ._typehints import FileHandle
from . import Config from . import Config
@ -22,7 +22,7 @@ class ConfigMaterial(Config):
""" """
def __init__(self, def __init__(self,
d: Dict[str, Any] = None, d: Optional[Dict[str, Any]] = None,
**kwargs): **kwargs):
""" """
New material configuration. New material configuration.
@ -83,13 +83,13 @@ class ConfigMaterial(Config):
@staticmethod @staticmethod
def load_DREAM3D(fname: str, def load_DREAM3D(fname: str,
grain_data: str = None, grain_data: Optional[str] = None,
cell_data: str = None, cell_data: Optional[str] = None,
cell_ensemble_data: str = 'CellEnsembleData', cell_ensemble_data: str = 'CellEnsembleData',
phases: str = 'Phases', phases: str = 'Phases',
Euler_angles: str = 'EulerAngles', Euler_angles: str = 'EulerAngles',
phase_names: str = 'PhaseName', phase_names: str = 'PhaseName',
base_group: str = None) -> 'ConfigMaterial': base_group: Optional[str] = None) -> 'ConfigMaterial':
""" """
Load DREAM.3D (HDF5) file. Load DREAM.3D (HDF5) file.
@ -160,7 +160,7 @@ class ConfigMaterial(Config):
pass pass
base_config = ConfigMaterial({'phase':{k if isinstance(k,int) else str(k):'t.b.d.' for k in np.unique(phase)}, base_config = ConfigMaterial({'phase':{k if isinstance(k,int) else str(k): None for k in np.unique(phase)},
'homogenization':{'direct':{'N_constituents':1}}}) 'homogenization':{'direct':{'N_constituents':1}}})
constituent = {k:np.atleast_1d(v[idx].squeeze()) for k,v in zip(['O','phase'],[O,phase])} constituent = {k:np.atleast_1d(v[idx].squeeze()) for k,v in zip(['O','phase'],[O,phase])}
@ -193,10 +193,10 @@ class ConfigMaterial(Config):
>>> import damask.ConfigMaterial as cm >>> import damask.ConfigMaterial as cm
>>> t = damask.Table.load('small.txt') >>> t = damask.Table.load('small.txt')
>>> t >>> t
pos pos pos qu qu qu qu phase homog 3:pos pos pos 4:qu qu qu qu phase homog
0 0 0 0 0.19 0.8 0.24 -0.51 Aluminum SX 0 0 0 0 0.19 0.8 0.24 -0.51 Aluminum SX
1 1 0 0 0.8 0.19 0.24 -0.51 Steel SX 1 1 0 0 0.8 0.19 0.24 -0.51 Steel SX
1 1 1 0 0.8 0.19 0.24 -0.51 Steel SX 2 1 1 0 0.8 0.19 0.24 -0.51 Steel SX
>>> cm.from_table(t,O='qu',phase='phase',homogenization='homog') >>> cm.from_table(t,O='qu',phase='phase',homogenization='homog')
material: material:
- constituents: - constituents:
@ -209,8 +209,8 @@ class ConfigMaterial(Config):
v: 1.0 v: 1.0
phase: Steel phase: Steel
homogenization: SX homogenization: SX
homogenization: {} homogenization: {SX: null}
phase: {} phase: {Aluminum: null, Steel: null}
>>> cm.from_table(t,O='qu',phase='phase',homogenization='single_crystal') >>> cm.from_table(t,O='qu',phase='phase',homogenization='single_crystal')
material: material:
@ -224,8 +224,8 @@ class ConfigMaterial(Config):
v: 1.0 v: 1.0
phase: Steel phase: Steel
homogenization: single_crystal homogenization: single_crystal
homogenization: {} homogenization: {single_crystal: null}
phase: {} phase: {Aluminum: null, Steel: null}
""" """
kwargs_ = {k:table.get(v) if v in table.labels else np.atleast_2d([v]*len(table)).T for k,v in kwargs.items()} kwargs_ = {k:table.get(v) if v in table.labels else np.atleast_2d([v]*len(table)).T for k,v in kwargs.items()}
@ -233,6 +233,8 @@ class ConfigMaterial(Config):
_,idx = np.unique(np.hstack(list(kwargs_.values())),return_index=True,axis=0) _,idx = np.unique(np.hstack(list(kwargs_.values())),return_index=True,axis=0)
idx = np.sort(idx) idx = np.sort(idx)
kwargs_ = {k:np.atleast_1d(v[idx].squeeze()) for k,v in kwargs_.items()} kwargs_ = {k:np.atleast_1d(v[idx].squeeze()) for k,v in kwargs_.items()}
for what in ['phase','homogenization']:
if what not in kwargs_: kwargs_[what] = what+'_label'
return ConfigMaterial().material_add(**kwargs_) return ConfigMaterial().material_add(**kwargs_)
@ -243,7 +245,7 @@ class ConfigMaterial(Config):
Check for completeness. Check for completeness.
Only the general file layout is considered. Only the general file layout is considered.
This check does not consider whether parameters for This check does not consider whether specific parameters for
a particular phase/homogenization model are missing. a particular phase/homogenization model are missing.
Returns Returns
@ -252,52 +254,56 @@ class ConfigMaterial(Config):
Whether the material.yaml definition is complete. Whether the material.yaml definition is complete.
""" """
def LabeledList(label,items):
return f'{label.capitalize()}{"s" if len(items)>1 else ""} {util.srepr(items,",",quote=True)}'
ok = True ok = True
for top_level in ['homogenization','phase','material']: msg = []
ok &= top_level in self all = set(['homogenization','phase','material'])
if top_level not in self: print(f'{top_level} entry missing') miss = set([item for item in all if item not in self])
empty = set([item for item in all-miss if self[item] is None])
if miss:
msg.append(f'{LabeledList("top-level",miss)} missing')
ok = False
if empty:
msg.append(f'{LabeledList("top-level",empty)} empty')
if ok: if ok:
ok &= len(self['material']) > 0 ok &= len(self['material']) > 0
if len(self['material']) < 1: print('Incomplete material definition') if len(self['material']) < 1: msg.append('No materials defined')
if ok:
homogenization = set() homogenization = set()
phase = set() phase = set()
for i,v in enumerate(self['material']): for i,v in enumerate(self['material']):
if 'homogenization' in v: if 'homogenization' in v:
homogenization.add(v['homogenization']) homogenization.add(v['homogenization'])
else: else:
print(f'No homogenization specified in material {i}') msg.append(f'No homogenization specified for material {i}')
ok = False ok = False
if 'constituents' in v: if 'constituents' in v:
for ii,vv in enumerate(v['constituents']): for ii,vv in enumerate(v['constituents']):
if 'O' not in vv: if 'O' not in vv:
print('No orientation specified in constituent {ii} of material {i}') msg.append(f'No orientation specified for constituent {ii} of material {i}')
ok = False ok = False
if 'phase' in vv: if 'phase' in vv:
phase.add(vv['phase']) phase.add(vv['phase'])
else: else:
print(f'No phase specified in constituent {ii} of material {i}') msg.append(f'No phase specified for constituent {ii} of material {i}')
ok = False ok = False
for k,v in self['phase'].items(): for v,other in {'phase':phase,
if 'lattice' not in v: 'homogenization':homogenization}.items():
print(f'No lattice specified in phase {k}') me = set([] if v in empty else self[v])
if _miss := other - me:
msg.append(f'{LabeledList(v,_miss)} missing')
ok = False
if len(_empty := [item for item in me if self[v][item] is None]) > 0:
msg.append(f'{LabeledList(v,_empty)} undefined')
ok = False ok = False
for k,v in self['homogenization'].items(): print(util.srepr(msg))
if 'N_constituents' not in v:
print(f'No. of constituents not specified in homogenization {k}')
ok = False
if phase - set(self['phase']):
print(f'Phase(s) {phase-set(self["phase"])} missing')
ok = False
if homogenization - set(self['homogenization']):
print(f'Homogenization(s) {homogenization-set(self["homogenization"])} missing')
ok = False
return ok return ok
@ -320,7 +326,7 @@ class ConfigMaterial(Config):
if 'phase' in self: if 'phase' in self:
for k,v in self['phase'].items(): for k,v in self['phase'].items():
if 'lattice' in v: if v is not None and 'lattice' in v:
try: try:
Orientation(lattice=v['lattice']) Orientation(lattice=v['lattice'])
except KeyError: except KeyError:
@ -348,8 +354,8 @@ class ConfigMaterial(Config):
def material_rename_phase(self, def material_rename_phase(self,
mapping: Dict[str, str], mapping: Dict[str, str],
ID: Sequence[int] = None, ID: Optional[Sequence[int]] = None,
constituent: Sequence[int] = None) -> 'ConfigMaterial': constituent: Optional[Sequence[int]] = None) -> 'ConfigMaterial':
""" """
Change phase name in material. Change phase name in material.
@ -382,7 +388,7 @@ class ConfigMaterial(Config):
def material_rename_homogenization(self, def material_rename_homogenization(self,
mapping: Dict[str, str], mapping: Dict[str, str],
ID: Sequence[int] = None) -> 'ConfigMaterial': ID: Optional[Sequence[int]] = None) -> 'ConfigMaterial':
""" """
Change homogenization name in material. Change homogenization name in material.
@ -418,6 +424,8 @@ class ConfigMaterial(Config):
---------- ----------
**kwargs **kwargs
Key-value pairs. Key-value pairs.
First index of array-like values runs over materials,
whereas second index runs over constituents.
Returns Returns
------- -------
@ -426,13 +434,12 @@ class ConfigMaterial(Config):
Examples Examples
-------- --------
Create a dual-phase steel microstructure for micromechanical simulations: Create two grains of ferrite and one grain of martensite, each with random orientation:
>>> import numpy as np
>>> import damask >>> import damask
>>> m = damask.ConfigMaterial() >>> m = damask.ConfigMaterial()
>>> m = m.material_add(phase = ['Ferrite','Martensite'], >>> m = m.material_add(phase = ['Ferrite','Martensite','Ferrite'],
... O = damask.Rotation.from_random(2), ... O = damask.Rotation.from_random(3),
... homogenization = 'SX') ... homogenization = 'SX')
>>> m >>> m
material: material:
@ -446,60 +453,91 @@ class ConfigMaterial(Config):
v: 1.0 v: 1.0
phase: Martensite phase: Martensite
homogenization: SX homogenization: SX
homogenization: {} - constituents:
phase: {} - O: [0.47925185, -0.04294454, 0.78760173, -0.3849116 ]
v: 1.0
phase: Ferrite
homogenization: SX
homogenization: {SX: null}
phase: {Ferrite: null, Martensite: null}
Create a duplex stainless steel microstructure for forming simulations: Create hundred materials that each approximate a duplex stainless steel microstructure
with three austenite and one relatively bigger ferrite grain of random orientation each:
>>> import numpy as np
>>> import damask >>> import damask
>>> m = damask.ConfigMaterial() >>> m = damask.ConfigMaterial()
>>> m = m.material_add(phase = np.array(['Austenite','Ferrite']).reshape(1,2), >>> m = m.material_add(phase = np.array(['Austenite']*3+['Ferrite']),
... O = damask.Rotation.from_random((2,2)), ... O = damask.Rotation.from_random((100,4)),
... v = np.array([0.2,0.8]).reshape(1,2), ... v = np.array([0.2]*3+[0.4]),
... homogenization = 'Taylor') ... homogenization = 'Taylor')
>>> m >>> m
material: material:
- constituents: - constituents:
- phase: Austenite - v: 0.2
O: [0.659802978293224, 0.6953785848195171, 0.22426295326327111, -0.17554139512785227] phase: Austenite
v: 0.2 O: [0.46183665006602664, 0.2215160420973196, -0.5594313187331139, 0.6516702781083836]
- phase: Ferrite - v: 0.2
O: [0.49356745891301596, 0.2841806579193434, -0.7487679215072818, -0.339085707289975] phase: Austenite
v: 0.8 O: [0.11321658382410027, 0.6354079414360444, 0.00562701344273936, 0.7638108992590535]
- v: 0.2
phase: Austenite
O: [0.050991978809077604, 0.8069522034362003, -0.11352928955610851, -0.5773552285027659]
- v: 0.4
phase: Ferrite
O: [0.9460076150721788, 0.15880754622367604, -0.0069841062241482385, -0.28249066842661014]
homogenization: Taylor homogenization: Taylor
.
.
.
- constituents: - constituents:
- phase: Austenite - v: 0.2
O: [0.26542221365204055, 0.7268854930702071, 0.4474726435701472, -0.44828201137283735] phase: Austenite
v: 0.2 O: [0.12531400788494199, -0.18637769037997565, 0.31737548053338394, -0.9213210951197429]
- phase: Ferrite - v: 0.2
O: [0.6545817158479885, -0.08004812803625233, -0.6226561293931374, 0.4212059104577611] phase: Austenite
v: 0.8 O: [0.37453930577161404, -0.33529507696450805, -0.3266564259130028, -0.800370601162502]
- v: 0.2
phase: Austenite
O: [0.035776891752713764, -0.720706371010592, -0.4540438656728926, -0.5226342017569017]
- v: 0.4
phase: Ferrite
O: [0.6782596727966124, -0.20800082041703685, -0.138636083554039, 0.6909989227925536]
homogenization: Taylor homogenization: Taylor
homogenization: {}
phase: {} homogenization: {Taylor: null}
phase: {Austenite: null, Ferrite: null}
""" """
N,n,shaped = 1,1,{} _constituent_properties = ['phase','O','v','V_e']
_dim = {'O':(4,),'V_e':(3,3,)}
_ex = dict((k, -len(v)) for k, v in _dim.items())
N,n = 1,1
shaped : Dict[str, Union[None,np.ndarray]] = \
{'v': None,
'phase': None,
'homogenization': None,
}
map_dim = {'O':-1,'V_e':-2}
for k,v in kwargs.items(): for k,v in kwargs.items():
shaped[k] = np.array(v) shaped[k] = np.array(v)
s = shaped[k].shape[:map_dim.get(k,None)] s = shaped[k].shape[:_ex.get(k,None)] # type: ignore
N = max(N,s[0]) if len(s)>0 else N N = max(N,s[0]) if len(s)>0 else N
n = max(n,s[1]) if len(s)>1 else n n = max(n,s[1]) if len(s)>1 else n
shaped['v'] = np.array(1./n) if shaped['v'] is None else shaped['v']
mat: Sequence[dict] = [{'constituents':[{} for _ in range(n)]} for _ in range(N)] mat: Sequence[dict] = [{'constituents':[{} for _ in range(n)]} for _ in range(N)]
if 'v' not in kwargs:
shaped['v'] = np.broadcast_to(1/n,(N,n))
map_shape = {'O':(N,n,4),'V_e':(N,n,3,3)}
for k,v in shaped.items(): for k,v in shaped.items():
target = map_shape.get(k,(N,n)) target = (N,n) + _dim.get(k,())
obj = np.broadcast_to(v.reshape(util.shapeshifter(v.shape, target, mode = 'right')), target) obj = np.broadcast_to(np.array(v).reshape(util.shapeshifter(() if v is None else v.shape,
target,
mode = 'right')),
target)
for i in range(N): for i in range(N):
if k in ['phase','O','v','V_e']: if k in _constituent_properties:
for j in range(n): for j in range(n):
mat[i]['constituents'][j][k] = obj[i,j].item() if isinstance(obj[i,j],np.generic) else obj[i,j] mat[i]['constituents'][j][k] = obj[i,j].item() if isinstance(obj[i,j],np.generic) else obj[i,j]
else: else:
@ -508,4 +546,8 @@ class ConfigMaterial(Config):
dup = self.copy() dup = self.copy()
dup['material'] = dup['material'] + mat if 'material' in dup else mat dup['material'] = dup['material'] + mat if 'material' in dup else mat
for what in [item for item in ['phase','homogenization'] if shaped[item] is not None]:
for k in np.unique(shaped[what]): # type: ignore
if k not in dup[what]: dup[what][str(k)] = None
return dup return dup

View File

@ -1,4 +1,4 @@
from typing import Union, Dict, List, Tuple from typing import Optional, Union, Dict, List, Tuple
import numpy as np import numpy as np
@ -324,10 +324,10 @@ class Crystal():
""" """
def __init__(self, *, def __init__(self, *,
family: CrystalFamily = None, family: Optional[CrystalFamily] = None,
lattice: CrystalLattice = None, lattice: Optional[CrystalLattice] = None,
a: float = None, b: float = None, c: float = None, a: Optional[float] = None, b: Optional[float] = None, c: Optional[float] = None,
alpha: float = None, beta: float = None, gamma: float = None, alpha: Optional[float] = None, beta: Optional[float] = None, gamma: Optional[float] = None,
degrees: bool = False): degrees: bool = False):
""" """
New representation of a crystal. New representation of a crystal.
@ -690,8 +690,8 @@ class Crystal():
self.lattice[-1],None),dtype=float) self.lattice[-1],None),dtype=float)
def to_lattice(self, *, def to_lattice(self, *,
direction: FloatSequence = None, direction: Optional[FloatSequence] = None,
plane: FloatSequence = None) -> np.ndarray: plane: Optional[FloatSequence] = None) -> np.ndarray:
""" """
Calculate lattice vector corresponding to crystal frame direction or plane normal. Calculate lattice vector corresponding to crystal frame direction or plane normal.
@ -717,8 +717,8 @@ class Crystal():
def to_frame(self, *, def to_frame(self, *,
uvw: FloatSequence = None, uvw: Optional[FloatSequence] = None,
hkl: FloatSequence = None) -> np.ndarray: hkl: Optional[FloatSequence] = None) -> np.ndarray:
""" """
Calculate crystal frame vector corresponding to lattice direction [uvw] or plane normal (hkl). Calculate crystal frame vector corresponding to lattice direction [uvw] or plane normal (hkl).

View File

@ -4,7 +4,7 @@ import warnings
import multiprocessing as mp import multiprocessing as mp
from functools import partial from functools import partial
import typing import typing
from typing import Union, Optional, TextIO, List, Sequence, Dict from typing import Optional, Union, TextIO, List, Sequence, Dict
from pathlib import Path from pathlib import Path
import numpy as np import numpy as np
@ -34,8 +34,8 @@ class Grid:
material: np.ndarray, material: np.ndarray,
size: FloatSequence, size: FloatSequence,
origin: FloatSequence = np.zeros(3), origin: FloatSequence = np.zeros(3),
initial_conditions: Dict[str,np.ndarray] = None, initial_conditions: Optional[Dict[str,np.ndarray]] = None,
comments: Union[str, Sequence[str]] = None): comments: Union[None, str, Sequence[str]] = None):
""" """
New geometry definition for grid solvers. New geometry definition for grid solvers.
@ -50,7 +50,7 @@ class Grid:
Coordinates of grid origin in meter. Defaults to [0.0,0.0,0.0]. Coordinates of grid origin in meter. Defaults to [0.0,0.0,0.0].
initial_conditions : dictionary, optional initial_conditions : dictionary, optional
Labels and values of the inital conditions at each material point. Labels and values of the inital conditions at each material point.
comments : str or sequence of str, optional comments : (sequence of) str, optional
Additional, human-readable information, e.g. history of operations. Additional, human-readable information, e.g. history of operations.
""" """
@ -348,9 +348,11 @@ class Grid:
@staticmethod @staticmethod
def load_DREAM3D(fname: Union[str, Path], def load_DREAM3D(fname: Union[str, Path],
feature_IDs: str = None, cell_data: str = None, feature_IDs: Optional[str] = None,
phases: str = 'Phases', Euler_angles: str = 'EulerAngles', cell_data: Optional[str] = None,
base_group: str = None) -> 'Grid': phases: str = 'Phases',
Euler_angles: str = 'EulerAngles',
base_group: Optional[str] = None) -> 'Grid':
""" """
Load DREAM.3D (HDF5) file. Load DREAM.3D (HDF5) file.
@ -427,7 +429,7 @@ class Grid:
coordinates : str coordinates : str
Label of the vector column containing the spatial coordinates. Label of the vector column containing the spatial coordinates.
Need to be ordered (1./x fast, 3./z slow). Need to be ordered (1./x fast, 3./z slow).
labels : str or sequence of str labels : (sequence of) str
Label(s) of the columns containing the material definition. Label(s) of the columns containing the material definition.
Each unique combination of values results in one material ID. Each unique combination of values results in one material ID.
@ -463,7 +465,7 @@ class Grid:
size: FloatSequence, size: FloatSequence,
seeds: np.ndarray, seeds: np.ndarray,
weights: FloatSequence, weights: FloatSequence,
material: IntSequence = None, material: Optional[IntSequence] = None,
periodic: bool = True): periodic: bool = True):
""" """
Create grid from Laguerre tessellation. Create grid from Laguerre tessellation.
@ -520,7 +522,7 @@ class Grid:
def from_Voronoi_tessellation(cells: IntSequence, def from_Voronoi_tessellation(cells: IntSequence,
size: FloatSequence, size: FloatSequence,
seeds: np.ndarray, seeds: np.ndarray,
material: IntSequence = None, material: Optional[IntSequence] = None,
periodic: bool = True) -> 'Grid': periodic: bool = True) -> 'Grid':
""" """
Create grid from Voronoi tessellation. Create grid from Voronoi tessellation.
@ -763,9 +765,9 @@ class Grid:
def canvas(self, def canvas(self,
cells: IntSequence = None, cells: Optional[IntSequence] = None,
offset: IntSequence = None, offset: Optional[IntSequence] = None,
fill: int = None) -> 'Grid': fill: Optional[int] = None) -> 'Grid':
""" """
Crop or enlarge/pad grid. Crop or enlarge/pad grid.
@ -901,7 +903,7 @@ class Grid:
def rotate(self, def rotate(self,
R: Rotation, R: Rotation,
fill: int = None) -> 'Grid': fill: Optional[int] = None) -> 'Grid':
""" """
Rotate grid (and pad if required). Rotate grid (and pad if required).
@ -972,15 +974,16 @@ class Grid:
# materials: 1 # materials: 1
""" """
options = ('nearest',False,None)
orig = tuple(map(np.linspace,self.origin + self.size/self.cells*.5, orig = tuple(map(np.linspace,self.origin + self.size/self.cells*.5,
self.origin + self.size - self.size/self.cells*.5,self.cells)) self.origin + self.size - self.size/self.cells*.5,self.cells))
interpolator = partial(interpolate.RegularGridInterpolator,
points=orig,method='nearest',bounds_error=False,fill_value=None)
new = grid_filters.coordinates0_point(cells,self.size,self.origin) new = grid_filters.coordinates0_point(cells,self.size,self.origin)
return Grid(material = interpolate.RegularGridInterpolator(orig,self.material,*options)(new).astype(int), return Grid(material = interpolator(values=self.material)(new).astype(int),
size = self.size, size = self.size,
origin = self.origin, origin = self.origin,
initial_conditions = {k: interpolate.RegularGridInterpolator(orig,v,*options)(new) initial_conditions = {k: interpolator(values=v)(new)
for k,v in self.initial_conditions.items()}, for k,v in self.initial_conditions.items()},
comments = self.comments+[util.execution_stamp('Grid','scale')], comments = self.comments+[util.execution_stamp('Grid','scale')],
) )
@ -1043,9 +1046,9 @@ class Grid:
Parameters Parameters
---------- ----------
from_material : int or sequence of int from_material : (sequence of) int
Material indices to be substituted. Material indices to be substituted.
to_material : int or sequence of int to_material : (sequence of) int
New material indices. New material indices.
Returns Returns
@ -1092,10 +1095,10 @@ class Grid:
def clean(self, def clean(self,
distance: float = np.sqrt(3), distance: float = np.sqrt(3),
selection: IntCollection = None, selection: Optional[IntCollection] = None,
invert_selection: bool = False, invert_selection: bool = False,
periodic: bool = True, periodic: bool = True,
rng_seed: NumpyRngSeed = None) -> 'Grid': rng_seed: Optional[NumpyRngSeed] = None) -> 'Grid':
""" """
Smooth grid by selecting most frequent material ID within given stencil at each location. Smooth grid by selecting most frequent material ID within given stencil at each location.
@ -1104,7 +1107,7 @@ class Grid:
distance : float, optional distance : float, optional
Voxel distance checked for presence of other materials. Voxel distance checked for presence of other materials.
Defaults to sqrt(3). Defaults to sqrt(3).
selection : int or collection of int, optional selection : (collection of) int, optional
Material IDs to consider. Defaults to all. Material IDs to consider. Defaults to all.
invert_selection : bool, optional invert_selection : bool, optional
Consider all material IDs except those in selection. Defaults to False. Consider all material IDs except those in selection. Defaults to False.
@ -1162,7 +1165,7 @@ class Grid:
dimension: Union[FloatSequence, IntSequence], dimension: Union[FloatSequence, IntSequence],
center: Union[FloatSequence, IntSequence], center: Union[FloatSequence, IntSequence],
exponent: Union[FloatSequence, float], exponent: Union[FloatSequence, float],
fill: int = None, fill: Optional[int] = None,
R: Rotation = Rotation(), R: Rotation = Rotation(),
inverse: bool = False, inverse: bool = False,
periodic: bool = True) -> 'Grid': periodic: bool = True) -> 'Grid':
@ -1179,7 +1182,7 @@ class Grid:
Center of the primitive. Center of the primitive.
If given as integers, cell centers are addressed. If given as integers, cell centers are addressed.
If given as floats, physical coordinates are addressed. If given as floats, physical coordinates are addressed.
exponent : float or sequence of float, len (3) exponent : (sequence of) float, len (3)
Exponents for the three axes. Exponents for the three axes.
0 gives octahedron (ǀxǀ^(2^0) + ǀyǀ^(2^0) + ǀzǀ^(2^0) < 1) 0 gives octahedron (ǀxǀ^(2^0) + ǀyǀ^(2^0) + ǀzǀ^(2^0) < 1)
1 gives sphere (ǀxǀ^(2^1) + ǀyǀ^(2^1) + ǀzǀ^(2^1) < 1) 1 gives sphere (ǀxǀ^(2^1) + ǀyǀ^(2^1) + ǀzǀ^(2^1) < 1)
@ -1253,8 +1256,8 @@ class Grid:
def vicinity_offset(self, def vicinity_offset(self,
distance: float = np.sqrt(3), distance: float = np.sqrt(3),
offset: int = None, offset: Optional[int] = None,
selection: IntCollection = None, selection: Optional[IntCollection] = None,
invert_selection: bool = False, invert_selection: bool = False,
periodic: bool = True) -> 'Grid': periodic: bool = True) -> 'Grid':
""" """
@ -1271,7 +1274,7 @@ class Grid:
offset : int, optional offset : int, optional
Offset (positive or negative) to tag material IDs. Offset (positive or negative) to tag material IDs.
Defaults to material.max()+1. Defaults to material.max()+1.
selection : int or collection of int, optional selection : (collection of) int, optional
Material IDs that trigger an offset. Material IDs that trigger an offset.
Defaults to any other than own material ID. Defaults to any other than own material ID.
invert_selection : bool, optional invert_selection : bool, optional

View File

@ -1,6 +1,6 @@
import inspect import inspect
import copy import copy
from typing import Union, Callable, Dict, Any, Tuple, TypeVar from typing import Optional, Union, Callable, Dict, Any, Tuple, TypeVar
import numpy as np import numpy as np
@ -94,14 +94,14 @@ class Orientation(Rotation,Crystal):
""" """
@util.extend_docstring(_parameter_doc) @util.extend_docstring(extra_parameters=_parameter_doc)
def __init__(self, def __init__(self,
rotation: Union[FloatSequence, Rotation] = np.array([1.,0.,0.,0.]), rotation: Union[FloatSequence, Rotation] = np.array([1.,0.,0.,0.]),
*, *,
family: CrystalFamily = None, family: Optional[CrystalFamily] = None,
lattice: CrystalLattice = None, lattice: Optional[CrystalLattice] = None,
a: float = None, b: float = None, c: float = None, a: Optional[float] = None, b: Optional[float] = None, c: Optional[float] = None,
alpha: float = None, beta: float = None, gamma: float = None, alpha: Optional[float] = None, beta: Optional[float] = None, gamma: Optional[float] = None,
degrees: bool = False): degrees: bool = False):
""" """
New orientation. New orientation.
@ -131,7 +131,7 @@ class Orientation(Rotation,Crystal):
def __copy__(self: MyType, def __copy__(self: MyType,
rotation: Union[FloatSequence, Rotation] = None) -> MyType: rotation: Union[None, FloatSequence, Rotation] = None) -> MyType:
""" """
Return deepcopy(self). Return deepcopy(self).
@ -300,84 +300,95 @@ class Orientation(Rotation,Crystal):
@classmethod @classmethod
@util.extended_docstring(Rotation.from_random, _parameter_doc) @util.extend_docstring(Rotation.from_random,
extra_parameters=_parameter_doc)
def from_random(cls, **kwargs) -> 'Orientation': def from_random(cls, **kwargs) -> 'Orientation':
kwargs_rot,kwargs_ori = Orientation._split_kwargs(kwargs,Rotation.from_random) kwargs_rot,kwargs_ori = Orientation._split_kwargs(kwargs,Rotation.from_random)
return cls(rotation=Rotation.from_random(**kwargs_rot),**kwargs_ori) return cls(rotation=Rotation.from_random(**kwargs_rot),**kwargs_ori)
@classmethod @classmethod
@util.extended_docstring(Rotation.from_quaternion,_parameter_doc) @util.extend_docstring(Rotation.from_quaternion,
extra_parameters=_parameter_doc)
def from_quaternion(cls, **kwargs) -> 'Orientation': def from_quaternion(cls, **kwargs) -> 'Orientation':
kwargs_rot,kwargs_ori = Orientation._split_kwargs(kwargs,Rotation.from_quaternion) kwargs_rot,kwargs_ori = Orientation._split_kwargs(kwargs,Rotation.from_quaternion)
return cls(rotation=Rotation.from_quaternion(**kwargs_rot),**kwargs_ori) return cls(rotation=Rotation.from_quaternion(**kwargs_rot),**kwargs_ori)
@classmethod @classmethod
@util.extended_docstring(Rotation.from_Euler_angles,_parameter_doc) @util.extend_docstring(Rotation.from_Euler_angles,
extra_parameters=_parameter_doc)
def from_Euler_angles(cls, **kwargs) -> 'Orientation': def from_Euler_angles(cls, **kwargs) -> 'Orientation':
kwargs_rot,kwargs_ori = Orientation._split_kwargs(kwargs,Rotation.from_Euler_angles) kwargs_rot,kwargs_ori = Orientation._split_kwargs(kwargs,Rotation.from_Euler_angles)
return cls(rotation=Rotation.from_Euler_angles(**kwargs_rot),**kwargs_ori) return cls(rotation=Rotation.from_Euler_angles(**kwargs_rot),**kwargs_ori)
@classmethod @classmethod
@util.extended_docstring(Rotation.from_axis_angle,_parameter_doc) @util.extend_docstring(Rotation.from_axis_angle,
extra_parameters=_parameter_doc)
def from_axis_angle(cls, **kwargs) -> 'Orientation': def from_axis_angle(cls, **kwargs) -> 'Orientation':
kwargs_rot,kwargs_ori = Orientation._split_kwargs(kwargs,Rotation.from_axis_angle) kwargs_rot,kwargs_ori = Orientation._split_kwargs(kwargs,Rotation.from_axis_angle)
return cls(rotation=Rotation.from_axis_angle(**kwargs_rot),**kwargs_ori) return cls(rotation=Rotation.from_axis_angle(**kwargs_rot),**kwargs_ori)
@classmethod @classmethod
@util.extended_docstring(Rotation.from_basis,_parameter_doc) @util.extend_docstring(Rotation.from_basis,
extra_parameters=_parameter_doc)
def from_basis(cls, **kwargs) -> 'Orientation': def from_basis(cls, **kwargs) -> 'Orientation':
kwargs_rot,kwargs_ori = Orientation._split_kwargs(kwargs,Rotation.from_basis) kwargs_rot,kwargs_ori = Orientation._split_kwargs(kwargs,Rotation.from_basis)
return cls(rotation=Rotation.from_basis(**kwargs_rot),**kwargs_ori) return cls(rotation=Rotation.from_basis(**kwargs_rot),**kwargs_ori)
@classmethod @classmethod
@util.extended_docstring(Rotation.from_matrix,_parameter_doc) @util.extend_docstring(Rotation.from_matrix,
extra_parameters=_parameter_doc)
def from_matrix(cls, **kwargs) -> 'Orientation': def from_matrix(cls, **kwargs) -> 'Orientation':
kwargs_rot,kwargs_ori = Orientation._split_kwargs(kwargs,Rotation.from_matrix) kwargs_rot,kwargs_ori = Orientation._split_kwargs(kwargs,Rotation.from_matrix)
return cls(rotation=Rotation.from_matrix(**kwargs_rot),**kwargs_ori) return cls(rotation=Rotation.from_matrix(**kwargs_rot),**kwargs_ori)
@classmethod @classmethod
@util.extended_docstring(Rotation.from_Rodrigues_vector,_parameter_doc) @util.extend_docstring(Rotation.from_Rodrigues_vector,
extra_parameters=_parameter_doc)
def from_Rodrigues_vector(cls, **kwargs) -> 'Orientation': def from_Rodrigues_vector(cls, **kwargs) -> 'Orientation':
kwargs_rot,kwargs_ori = Orientation._split_kwargs(kwargs,Rotation.from_Rodrigues_vector) kwargs_rot,kwargs_ori = Orientation._split_kwargs(kwargs,Rotation.from_Rodrigues_vector)
return cls(rotation=Rotation.from_Rodrigues_vector(**kwargs_rot),**kwargs_ori) return cls(rotation=Rotation.from_Rodrigues_vector(**kwargs_rot),**kwargs_ori)
@classmethod @classmethod
@util.extended_docstring(Rotation.from_homochoric,_parameter_doc) @util.extend_docstring(Rotation.from_homochoric,
extra_parameters=_parameter_doc)
def from_homochoric(cls, **kwargs) -> 'Orientation': def from_homochoric(cls, **kwargs) -> 'Orientation':
kwargs_rot,kwargs_ori = Orientation._split_kwargs(kwargs,Rotation.from_homochoric) kwargs_rot,kwargs_ori = Orientation._split_kwargs(kwargs,Rotation.from_homochoric)
return cls(rotation=Rotation.from_homochoric(**kwargs_rot),**kwargs_ori) return cls(rotation=Rotation.from_homochoric(**kwargs_rot),**kwargs_ori)
@classmethod @classmethod
@util.extended_docstring(Rotation.from_cubochoric,_parameter_doc) @util.extend_docstring(Rotation.from_cubochoric,
extra_parameters=_parameter_doc)
def from_cubochoric(cls, **kwargs) -> 'Orientation': def from_cubochoric(cls, **kwargs) -> 'Orientation':
kwargs_rot,kwargs_ori = Orientation._split_kwargs(kwargs,Rotation.from_cubochoric) kwargs_rot,kwargs_ori = Orientation._split_kwargs(kwargs,Rotation.from_cubochoric)
return cls(rotation=Rotation.from_cubochoric(**kwargs_rot),**kwargs_ori) return cls(rotation=Rotation.from_cubochoric(**kwargs_rot),**kwargs_ori)
@classmethod @classmethod
@util.extended_docstring(Rotation.from_spherical_component,_parameter_doc) @util.extend_docstring(Rotation.from_spherical_component,
extra_parameters=_parameter_doc)
def from_spherical_component(cls, **kwargs) -> 'Orientation': def from_spherical_component(cls, **kwargs) -> 'Orientation':
kwargs_rot,kwargs_ori = Orientation._split_kwargs(kwargs,Rotation.from_spherical_component) kwargs_rot,kwargs_ori = Orientation._split_kwargs(kwargs,Rotation.from_spherical_component)
return cls(rotation=Rotation.from_spherical_component(**kwargs_rot),**kwargs_ori) return cls(rotation=Rotation.from_spherical_component(**kwargs_rot),**kwargs_ori)
@classmethod @classmethod
@util.extended_docstring(Rotation.from_fiber_component,_parameter_doc) @util.extend_docstring(Rotation.from_fiber_component,
extra_parameters=_parameter_doc)
def from_fiber_component(cls, **kwargs) -> 'Orientation': def from_fiber_component(cls, **kwargs) -> 'Orientation':
kwargs_rot,kwargs_ori = Orientation._split_kwargs(kwargs,Rotation.from_fiber_component) kwargs_rot,kwargs_ori = Orientation._split_kwargs(kwargs,Rotation.from_fiber_component)
return cls(rotation=Rotation.from_fiber_component(**kwargs_rot),**kwargs_ori) return cls(rotation=Rotation.from_fiber_component(**kwargs_rot),**kwargs_ori)
@classmethod @classmethod
@util.extend_docstring(_parameter_doc) @util.extend_docstring(extra_parameters=_parameter_doc)
def from_directions(cls, def from_directions(cls,
uvw: FloatSequence, uvw: FloatSequence,
hkl: FloatSequence, hkl: FloatSequence,
@ -392,6 +403,10 @@ class Orientation(Rotation,Crystal):
hkl : numpy.ndarray, shape (...,3) hkl : numpy.ndarray, shape (...,3)
Lattice plane normal aligned with lab frame z-direction. Lattice plane normal aligned with lab frame z-direction.
Returns
-------
new : damask.Orientation
""" """
o = cls(**kwargs) o = cls(**kwargs)
x = o.to_frame(uvw=uvw) x = o.to_frame(uvw=uvw)
@ -538,8 +553,7 @@ class Orientation(Rotation,Crystal):
Notes Notes
----- -----
Currently requires same crystal family for both orientations. Requires same crystal family for both orientations.
For extension to cases with differing symmetry see A. Heinz and P. Neumann 1991 and 10.1107/S0021889808016373.
Examples Examples
-------- --------
@ -569,6 +583,8 @@ class Orientation(Rotation,Crystal):
>>> plt.show() >>> plt.show()
""" """
# For extension to cases with differing symmetry see
# https://doi.org/10.1107/S0021889808016373 and https://doi.org/10.1107/S0108767391006864
if self.family != other.family: if self.family != other.family:
raise NotImplementedError('disorientation between different crystal families') raise NotImplementedError('disorientation between different crystal families')
@ -601,7 +617,7 @@ class Orientation(Rotation,Crystal):
def average(self, def average(self,
weights: FloatSequence = None, weights: Optional[FloatSequence] = None,
return_cloud: bool = False): return_cloud: bool = False):
""" """
Return orientation average over last dimension. Return orientation average over last dimension.
@ -803,8 +819,8 @@ class Orientation(Rotation,Crystal):
# functions that require lattice, not just family # functions that require lattice, not just family
def to_pole(self, *, def to_pole(self, *,
uvw: FloatSequence = None, uvw: Optional[FloatSequence] = None,
hkl: FloatSequence = None, hkl: Optional[FloatSequence] = None,
with_symmetry: bool = False, with_symmetry: bool = False,
normalize: bool = True) -> np.ndarray: normalize: bool = True) -> np.ndarray:
""" """
@ -845,8 +861,8 @@ class Orientation(Rotation,Crystal):
def Schmid(self, *, def Schmid(self, *,
N_slip: IntSequence = None, N_slip: Optional[IntSequence] = None,
N_twin: IntSequence = None) -> np.ndarray: N_twin: Optional[IntSequence] = None) -> np.ndarray:
u""" u"""
Calculate Schmid matrix P = d n in the lab frame for selected deformation systems. Calculate Schmid matrix P = d n in the lab frame for selected deformation systems.

View File

@ -11,7 +11,7 @@ from pathlib import Path
from functools import partial from functools import partial
from collections import defaultdict from collections import defaultdict
from collections.abc import Iterable from collections.abc import Iterable
from typing import Union, Callable, Any, Sequence, Literal, Dict, List, Tuple, Optional from typing import Optional, Union, Callable, Any, Sequence, Literal, Dict, List, Tuple
import h5py import h5py
import numpy as np import numpy as np
@ -189,11 +189,11 @@ class Result:
def _manage_view(self, def _manage_view(self,
action: Literal['set', 'add', 'del'], action: Literal['set', 'add', 'del'],
increments: Union[int, Sequence[int], str, Sequence[str], bool] = None, increments: Union[None, int, Sequence[int], str, Sequence[str], bool] = None,
times: Union[float, Sequence[float], str, Sequence[str], bool] = None, times: Union[None, float, Sequence[float], str, Sequence[str], bool] = None,
phases: Union[str, Sequence[str], bool] = None, phases: Union[None, str, Sequence[str], bool] = None,
homogenizations: Union[str, Sequence[str], bool] = None, homogenizations: Union[None, str, Sequence[str], bool] = None,
fields: Union[str, Sequence[str], bool] = None) -> "Result": fields: Union[None, str, Sequence[str], bool] = None) -> "Result":
""" """
Manages the visibility of the groups. Manages the visibility of the groups.
@ -256,8 +256,8 @@ class Result:
def increments_in_range(self, def increments_in_range(self,
start: Union[str, int] = None, start: Union[None, str, int] = None,
end: Union[str, int] = None) -> Sequence[int]: end: Union[None, str, int] = None) -> Sequence[int]:
""" """
Get all increments within a given range. Get all increments within a given range.
@ -280,8 +280,8 @@ class Result:
return [i for i in self.incs if s <= i <= e] return [i for i in self.incs if s <= i <= e]
def times_in_range(self, def times_in_range(self,
start: float = None, start: Optional[float] = None,
end: float = None) -> Sequence[float]: end: Optional[float] = None) -> Sequence[float]:
""" """
Get times of all increments within a given time range. Get times of all increments within a given time range.
@ -304,12 +304,12 @@ class Result:
def view(self,*, def view(self,*,
increments: Union[int, Sequence[int], str, Sequence[str], bool] = None, increments: Union[None, int, Sequence[int], str, Sequence[str], bool] = None,
times: Union[float, Sequence[float], str, Sequence[str], bool] = None, times: Union[None, float, Sequence[float], str, Sequence[str], bool] = None,
phases: Union[str, Sequence[str], bool] = None, phases: Union[None, str, Sequence[str], bool] = None,
homogenizations: Union[str, Sequence[str], bool] = None, homogenizations: Union[None, str, Sequence[str], bool] = None,
fields: Union[str, Sequence[str], bool] = None, fields: Union[None, str, Sequence[str], bool] = None,
protected: bool = None) -> "Result": protected: Optional[bool] = None) -> "Result":
""" """
Set view. Set view.
@ -361,11 +361,11 @@ class Result:
def view_more(self,*, def view_more(self,*,
increments: Union[int, Sequence[int], str, Sequence[str], bool] = None, increments: Union[None, int, Sequence[int], str, Sequence[str], bool] = None,
times: Union[float, Sequence[float], str, Sequence[str], bool] = None, times: Union[None, float, Sequence[float], str, Sequence[str], bool] = None,
phases: Union[str, Sequence[str], bool] = None, phases: Union[None, str, Sequence[str], bool] = None,
homogenizations: Union[str, Sequence[str], bool] = None, homogenizations: Union[None, str, Sequence[str], bool] = None,
fields: Union[str, Sequence[str], bool] = None) -> "Result": fields: Union[None, str, Sequence[str], bool] = None) -> "Result":
""" """
Add to view. Add to view.
@ -404,11 +404,11 @@ class Result:
def view_less(self,*, def view_less(self,*,
increments: Union[int, Sequence[int], str, Sequence[str], bool] = None, increments: Union[None, int, Sequence[int], str, Sequence[str], bool] = None,
times: Union[float, Sequence[float], str, Sequence[str], bool] = None, times: Union[None, float, Sequence[float], str, Sequence[str], bool] = None,
phases: Union[str, Sequence[str], bool] = None, phases: Union[None, str, Sequence[str], bool] = None,
homogenizations: Union[str, Sequence[str], bool] = None, homogenizations: Union[None, str, Sequence[str], bool] = None,
fields: Union[str, Sequence[str], bool] = None) -> "Result": fields: Union[None, str, Sequence[str], bool] = None) -> "Result":
""" """
Remove from view. Remove from view.
@ -650,7 +650,7 @@ class Result:
formula: str, formula: str,
name: str, name: str,
unit: str = 'n/a', unit: str = 'n/a',
description: str = None): description: Optional[str] = None):
""" """
Add result of a general formula. Add result of a general formula.
@ -966,7 +966,7 @@ class Result:
} }
def add_equivalent_Mises(self, def add_equivalent_Mises(self,
T_sym: str, T_sym: str,
kind: str = None): kind: Optional[str] = None):
""" """
Add the equivalent Mises stress or strain of a symmetric tensor. Add the equivalent Mises stress or strain of a symmetric tensor.
@ -1021,7 +1021,7 @@ class Result:
} }
def add_norm(self, def add_norm(self,
x: str, x: str,
ord: Union[int, float, Literal['fro', 'nuc']] = None): ord: Union[None, int, float, Literal['fro', 'nuc']] = None):
""" """
Add the norm of vector or tensor. Add the norm of vector or tensor.
@ -1101,8 +1101,8 @@ class Result:
def add_pole(self, def add_pole(self,
q: str = 'O', q: str = 'O',
*, *,
uvw: FloatSequence = None, uvw: Optional[FloatSequence] = None,
hkl: FloatSequence = None, hkl: Optional[FloatSequence] = None,
with_symmetry: bool = False, with_symmetry: bool = False,
normalize: bool = True): normalize: bool = True):
""" """
@ -1593,7 +1593,7 @@ class Result:
output: Union[str, List[str]] = '*', output: Union[str, List[str]] = '*',
flatten: bool = True, flatten: bool = True,
prune: bool = True, prune: bool = True,
constituents: IntSequence = None, constituents: Optional[IntSequence] = None,
fill_float: float = np.nan, fill_float: float = np.nan,
fill_int: int = 0) -> Optional[Dict[str,Any]]: fill_int: int = 0) -> Optional[Dict[str,Any]]:
""" """
@ -1683,7 +1683,7 @@ class Result:
def export_XDMF(self, def export_XDMF(self,
output: Union[str, List[str]] = '*', output: Union[str, List[str]] = '*',
target_dir: Union[str, Path] = None, target_dir: Union[None, str, Path] = None,
absolute_path: bool = False): absolute_path: bool = False):
""" """
Write XDMF file to directly visualize data from DADF5 file. Write XDMF file to directly visualize data from DADF5 file.
@ -1811,8 +1811,8 @@ class Result:
def export_VTK(self, def export_VTK(self,
output: Union[str,List[str]] = '*', output: Union[str,List[str]] = '*',
mode: str = 'cell', mode: str = 'cell',
constituents: IntSequence = None, constituents: Optional[IntSequence] = None,
target_dir: Union[str, Path] = None, target_dir: Union[None, str, Path] = None,
fill_float: float = np.nan, fill_float: float = np.nan,
fill_int: int = 0, fill_int: int = 0,
parallel: bool = True): parallel: bool = True):
@ -1958,7 +1958,7 @@ class Result:
def export_simulation_setup(self, def export_simulation_setup(self,
output: Union[str, List[str]] = '*', output: Union[str, List[str]] = '*',
target_dir: Union[str, Path] = None, target_dir: Union[None, str, Path] = None,
overwrite: bool = False, overwrite: bool = False,
): ):
""" """

View File

@ -1,5 +1,5 @@
import copy import copy
from typing import Union, Sequence, Tuple, Literal, List, TypeVar from typing import Optional, Union, Sequence, Tuple, Literal, List, TypeVar
import numpy as np import numpy as np
@ -26,11 +26,8 @@ class Rotation:
- Coordinate frames are right-handed. - Coordinate frames are right-handed.
- A rotation angle ω is taken to be positive for a counterclockwise rotation - A rotation angle ω is taken to be positive for a counterclockwise rotation
when viewing from the end point of the rotation axis towards the origin. when viewing from the end point of the rotation axis towards the origin.
- Rotations will be interpreted in the passive sense. - Rotations will be interpreted in the passive sense, i.e. as rotation of
- Euler angle triplets are implemented using the Bunge convention, the coordinate frame.
with angular ranges of [0,2π], [0,π], [0,2π].
- The rotation angle ω is limited to the interval [0,π].
- The real part of a quaternion is positive, Re(q) 0
- P = -1 (as default). - P = -1 (as default).
Examples Examples
@ -66,7 +63,7 @@ class Rotation:
__slots__ = ['quaternion'] __slots__ = ['quaternion']
def __init__(self, def __init__(self,
rotation: Union[FloatSequence, 'Rotation'] = np.array([1.0,0.0,0.0,0.0])): rotation: Union[FloatSequence, 'Rotation'] = np.array([1.,0.,0.,0.])):
""" """
New rotation. New rotation.
@ -82,7 +79,7 @@ class Rotation:
if isinstance(rotation,Rotation): if isinstance(rotation,Rotation):
self.quaternion = rotation.quaternion.copy() self.quaternion = rotation.quaternion.copy()
elif np.array(rotation).shape[-1] == 4: elif np.array(rotation).shape[-1] == 4:
self.quaternion = np.array(rotation) self.quaternion = np.array(rotation,dtype=float)
else: else:
raise TypeError('"rotation" is neither a Rotation nor a quaternion') raise TypeError('"rotation" is neither a Rotation nor a quaternion')
@ -99,7 +96,7 @@ class Rotation:
def __copy__(self: MyType, def __copy__(self: MyType,
rotation: Union[FloatSequence, 'Rotation'] = None) -> MyType: rotation: Union[None, FloatSequence, 'Rotation'] = None) -> MyType:
""" """
Return deepcopy(self). Return deepcopy(self).
@ -141,7 +138,7 @@ class Rotation:
""" """
return NotImplemented if not isinstance(other, Rotation) else \ return NotImplemented if not isinstance(other, Rotation) else \
np.logical_or(np.all(self.quaternion == other.quaternion,axis=-1), np.logical_or(np.all(self.quaternion == other.quaternion,axis=-1),
np.all(self.quaternion == -1.0*other.quaternion,axis=-1)) np.all(self.quaternion == -1.*other.quaternion,axis=-1))
def __ne__(self, def __ne__(self,
@ -161,8 +158,8 @@ class Rotation:
def isclose(self: MyType, def isclose(self: MyType,
other: MyType, other: MyType,
rtol: float = 1e-5, rtol: float = 1.e-5,
atol: float = 1e-8, atol: float = 1.e-8,
equal_nan: bool = True) -> bool: equal_nan: bool = True) -> bool:
""" """
Report where values are approximately equal to corresponding ones of other Rotation. Report where values are approximately equal to corresponding ones of other Rotation.
@ -187,13 +184,13 @@ class Rotation:
s = self.quaternion s = self.quaternion
o = other.quaternion o = other.quaternion
return np.logical_or(np.all(np.isclose(s, o,rtol,atol,equal_nan),axis=-1), return np.logical_or(np.all(np.isclose(s, o,rtol,atol,equal_nan),axis=-1),
np.all(np.isclose(s,-1.0*o,rtol,atol,equal_nan),axis=-1)) np.all(np.isclose(s,-1.*o,rtol,atol,equal_nan),axis=-1))
def allclose(self: MyType, def allclose(self: MyType,
other: MyType, other: MyType,
rtol: float = 1e-5, rtol: float = 1.e-5,
atol: float = 1e-8, atol: float = 1.e-8,
equal_nan: bool = True) -> Union[np.bool_, bool]: equal_nan: bool = True) -> Union[np.bool_, bool]:
""" """
Test whether all values are approximately equal to corresponding ones of other Rotation. Test whether all values are approximately equal to corresponding ones of other Rotation.
@ -250,7 +247,7 @@ class Rotation:
""" """
dup = self.copy() dup = self.copy()
dup.quaternion[...,1:] *= -1 dup.quaternion[...,1:] *= -1.
return dup return dup
@ -393,9 +390,9 @@ class Rotation:
if self.shape + (3,) == other.shape: if self.shape + (3,) == other.shape:
q_m = self.quaternion[...,0] q_m = self.quaternion[...,0]
p_m = self.quaternion[...,1:] p_m = self.quaternion[...,1:]
A = q_m**2.0 - np.einsum('...i,...i',p_m,p_m) A = q_m**2 - np.einsum('...i,...i',p_m,p_m)
B = 2.0 * np.einsum('...i,...i',p_m,other) B = 2. * np.einsum('...i,...i',p_m,other)
C = 2.0 * _P * q_m C = 2. * _P * q_m
return np.block([(A * other[...,i]).reshape(self.shape+(1,)) + return np.block([(A * other[...,i]).reshape(self.shape+(1,)) +
(B * p_m[...,i]).reshape(self.shape+(1,)) + (B * p_m[...,i]).reshape(self.shape+(1,)) +
(C * ( p_m[...,(i+1)%3]*other[...,(i+2)%3]\ (C * ( p_m[...,(i+1)%3]*other[...,(i+2)%3]\
@ -419,7 +416,7 @@ class Rotation:
def _standardize(self: MyType) -> MyType: def _standardize(self: MyType) -> MyType:
"""Standardize quaternion (ensure positive real hemisphere).""" """Standardize quaternion (ensure positive real hemisphere)."""
self.quaternion[self.quaternion[...,0] < 0.0] *= -1 self.quaternion[self.quaternion[...,0] < 0.] *= -1.
return self return self
@ -468,7 +465,7 @@ class Rotation:
Parameters Parameters
---------- ----------
shape : int or sequence of ints shape : (sequence of) int
New shape, number of elements needs to match the original shape. New shape, number of elements needs to match the original shape.
If an integer is supplied, then the result will be a 1-D array of that length. If an integer is supplied, then the result will be a 1-D array of that length.
order : {'C', 'F', 'A'}, optional order : {'C', 'F', 'A'}, optional
@ -496,7 +493,7 @@ class Rotation:
Parameters Parameters
---------- ----------
shape : int or sequence of ints shape : (sequence of) int
Shape of broadcasted array, needs to be compatible with the original shape. Shape of broadcasted array, needs to be compatible with the original shape.
mode : str, optional mode : str, optional
Where to preferentially locate missing dimensions. Where to preferentially locate missing dimensions.
@ -514,7 +511,7 @@ class Rotation:
def average(self: MyType, def average(self: MyType,
weights: FloatSequence = None) -> MyType: weights: Optional[FloatSequence] = None) -> MyType:
""" """
Average along last array dimension. Average along last array dimension.
@ -540,7 +537,7 @@ class Rotation:
weights_ = np.ones(self.shape,dtype=float) if weights is None else np.array(weights,float) weights_ = np.ones(self.shape,dtype=float) if weights is None else np.array(weights,float)
eig, vec = np.linalg.eig(np.sum(_M(self.quaternion) * weights_[...,np.newaxis,np.newaxis],axis=-3) \ eig, vec = np.linalg.eig(np.sum(_M(self.quaternion) * weights_[...,np.newaxis,np.newaxis],axis=-3)
/np.sum( weights_[...,np.newaxis,np.newaxis],axis=-3)) /np.sum( weights_[...,np.newaxis,np.newaxis],axis=-3))
return self.copy(Rotation.from_quaternion(np.real( return self.copy(Rotation.from_quaternion(np.real(
@ -751,6 +748,7 @@ class Rotation:
@staticmethod @staticmethod
def from_quaternion(q: Union[Sequence[FloatSequence], np.ndarray], def from_quaternion(q: Union[Sequence[FloatSequence], np.ndarray],
accept_homomorph: bool = False, accept_homomorph: bool = False,
normalize: bool = False,
P: Literal[1, -1] = -1) -> 'Rotation': P: Literal[1, -1] = -1) -> 'Rotation':
""" """
Initialize from quaternion. Initialize from quaternion.
@ -762,23 +760,29 @@ class Rotation:
accept_homomorph : bool, optional accept_homomorph : bool, optional
Allow homomorphic variants, i.e. q_0 < 0 (negative real hemisphere). Allow homomorphic variants, i.e. q_0 < 0 (negative real hemisphere).
Defaults to False. Defaults to False.
normalize: bool, optional
Allow ǀqǀ 1. Defaults to False.
P : int {-1,1}, optional P : int {-1,1}, optional
Sign convention. Defaults to -1. Sign convention. Defaults to -1.
Returns
-------
new : damask.Rotation
""" """
qu = np.array(q,dtype=float) qu = np.array(q,dtype=float)
if qu.shape[:-2:-1] != (4,): if qu.shape[:-2:-1] != (4,): raise ValueError('invalid shape')
raise ValueError('invalid shape') if abs(P) != 1: raise ValueError('P ∉ {-1,1}')
if abs(P) != 1:
raise ValueError('P ∉ {-1,1}')
qu[...,1:4] *= -P qu[...,1:4] *= -P
if accept_homomorph: if accept_homomorph:
qu[qu[...,0] < 0.0] *= -1 qu[qu[...,0]<0.] *= -1.
else: elif np.any(qu[...,0] < 0.):
if np.any(qu[...,0] < 0.0):
raise ValueError('quaternion with negative first (real) component') raise ValueError('quaternion with negative first (real) component')
if not np.all(np.isclose(np.linalg.norm(qu,axis=-1), 1.0,rtol=0.0)): if normalize:
qu /= np.linalg.norm(qu,axis=-1,keepdims=True)
elif not np.allclose(np.linalg.norm(qu,axis=-1),1.,rtol=1.e-8):
raise ValueError('quaternion is not of unit length') raise ValueError('quaternion is not of unit length')
return Rotation(qu) return Rotation(qu)
@ -797,17 +801,20 @@ class Rotation:
degrees : bool, optional degrees : bool, optional
Euler angles are given in degrees. Defaults to False. Euler angles are given in degrees. Defaults to False.
Returns
-------
new : damask.Rotation
Notes Notes
----- -----
Bunge Euler angles correspond to a rotation axis sequence of zx'z''. Bunge Euler angles correspond to a rotation axis sequence of zx'z''.
""" """
eu = np.array(phi,dtype=float) eu = np.array(phi,dtype=float)
if eu.shape[:-2:-1] != (3,): if eu.shape[:-2:-1] != (3,): raise ValueError('invalid shape')
raise ValueError('invalid shape')
eu = np.radians(eu) if degrees else eu eu = np.radians(eu) if degrees else eu
if np.any(eu < 0.0) or np.any(eu > 2.0*np.pi) or np.any(eu[...,1] > np.pi): # ToDo: No separate check for PHI if np.any(eu < 0.) or np.any(eu > np.pi*np.array([2.,1.,2.])):
raise ValueError('Euler angles outside of [0..2π],[0..π],[0..2π]') raise ValueError('Euler angles outside of [0..2π],[0..π],[0..2π]')
return Rotation(Rotation._eu2qu(eu)) return Rotation(Rotation._eu2qu(eu))
@ -832,20 +839,23 @@ class Rotation:
P : int {-1,1}, optional P : int {-1,1}, optional
Sign convention. Defaults to -1. Sign convention. Defaults to -1.
Returns
-------
new : damask.Rotation
""" """
ax = np.array(axis_angle,dtype=float) ax = np.array(axis_angle,dtype=float)
if ax.shape[:-2:-1] != (4,): if ax.shape[:-2:-1] != (4,): raise ValueError('invalid shape')
raise ValueError('invalid shape') if abs(P) != 1: raise ValueError('P ∉ {-1,1}')
if abs(P) != 1:
raise ValueError('P ∉ {-1,1}')
ax[...,0:3] *= -P ax[...,0:3] *= -P
if degrees: ax[..., 3] = np.radians(ax[...,3]) if degrees: ax[..., 3] = np.radians(ax[...,3])
if normalize: ax[...,0:3] /= np.linalg.norm(ax[...,0:3],axis=-1,keepdims=True) if np.any(ax[...,3] < 0.) or np.any(ax[...,3] > np.pi):
if np.any(ax[...,3] < 0.0) or np.any(ax[...,3] > np.pi):
raise ValueError('axisangle rotation angle outside of [0..π]') raise ValueError('axisangle rotation angle outside of [0..π]')
if not np.all(np.isclose(np.linalg.norm(ax[...,0:3],axis=-1), 1.0)):
print(np.linalg.norm(ax[...,0:3],axis=-1)) if normalize:
ax[...,0:3] /= np.linalg.norm(ax[...,0:3],axis=-1,keepdims=True)
elif not np.allclose(np.linalg.norm(ax[...,0:3],axis=-1),1.):
raise ValueError('axisangle rotation axis is not of unit length') raise ValueError('axisangle rotation axis is not of unit length')
return Rotation(Rotation._ax2qu(ax)) return Rotation(Rotation._ax2qu(ax))
@ -866,24 +876,29 @@ class Rotation:
reciprocal : bool, optional reciprocal : bool, optional
Basis vectors are given in reciprocal (instead of real) space. Defaults to False. Basis vectors are given in reciprocal (instead of real) space. Defaults to False.
Returns
-------
new : damask.Rotation
""" """
om = np.array(basis,dtype=float) om = np.array(basis,dtype=float)
if om.shape[-2:] != (3,3): if om.shape[-2:] != (3,3): raise ValueError('invalid shape')
raise ValueError('invalid shape')
if reciprocal: if reciprocal:
om = np.linalg.inv(tensor.transpose(om)/np.pi) # transform reciprocal basis set om = np.linalg.inv(tensor.transpose(om)/np.pi) # transform reciprocal basis set
orthonormal = False # contains stretch orthonormal = False # contains stretch
if not orthonormal: if not orthonormal:
(U,S,Vh) = np.linalg.svd(om) # singular value decomposition (U,S,Vh) = np.linalg.svd(om) # singular value decomposition
om = np.einsum('...ij,...jl',U,Vh) om = np.einsum('...ij,...jl',U,Vh)
if not np.all(np.isclose(np.linalg.det(om),1.0)): elif not np.allclose(np.einsum('...i,...i',om[...,0],om[...,1]),0.) \
raise ValueError('orientation matrix has determinant ≠ 1') or not np.allclose(np.einsum('...i,...i',om[...,1],om[...,2]),0.) \
if not np.all(np.isclose(np.einsum('...i,...i',om[...,0],om[...,1]), 0.0)) \ or not np.allclose(np.einsum('...i,...i',om[...,2],om[...,0]),0.):
or not np.all(np.isclose(np.einsum('...i,...i',om[...,1],om[...,2]), 0.0)) \
or not np.all(np.isclose(np.einsum('...i,...i',om[...,2],om[...,0]), 0.0)):
raise ValueError('orientation matrix is not orthogonal') raise ValueError('orientation matrix is not orthogonal')
if not np.allclose(np.linalg.det(om),1.):
raise ValueError('orientation matrix has determinant ≠ 1')
return Rotation(Rotation._om2qu(om)) return Rotation(Rotation._om2qu(om))
@staticmethod @staticmethod
@ -896,6 +911,10 @@ class Rotation:
R : numpy.ndarray, shape (...,3,3) R : numpy.ndarray, shape (...,3,3)
Rotation matrix with det(R) = 1 and R.T R = I. Rotation matrix with det(R) = 1 and R.T R = I.
Returns
-------
new : damask.Rotation
""" """
return Rotation.from_basis(R) return Rotation.from_basis(R)
@ -912,9 +931,13 @@ class Rotation:
b : numpy.ndarray, shape (...,2,3) b : numpy.ndarray, shape (...,2,3)
Corresponding three-dimensional vectors of second basis. Corresponding three-dimensional vectors of second basis.
Returns
-------
new : damask.Rotation
""" """
a_ = np.array(a) a_ = np.array(a,dtype=float)
b_ = np.array(b) b_ = np.array(b,dtype=float)
if a_.shape[-2:] != (2,3) or b_.shape[-2:] != (2,3) or a_.shape != b_.shape: if a_.shape[-2:] != (2,3) or b_.shape[-2:] != (2,3) or a_.shape != b_.shape:
raise ValueError('invalid shape') raise ValueError('invalid shape')
am = np.stack([ a_[...,0,:], am = np.stack([ a_[...,0,:],
@ -944,18 +967,21 @@ class Rotation:
P : int {-1,1}, optional P : int {-1,1}, optional
Sign convention. Defaults to -1. Sign convention. Defaults to -1.
Returns
-------
new : damask.Rotation
""" """
ro = np.array(rho,dtype=float) ro = np.array(rho,dtype=float)
if ro.shape[:-2:-1] != (4,): if ro.shape[:-2:-1] != (4,): raise ValueError('invalid shape')
raise ValueError('invalid shape') if abs(P) != 1: raise ValueError('P ∉ {-1,1}')
if abs(P) != 1:
raise ValueError('P ∉ {-1,1}')
ro[...,0:3] *= -P ro[...,0:3] *= -P
if normalize: ro[...,0:3] /= np.linalg.norm(ro[...,0:3],axis=-1,keepdims=True) if np.any(ro[...,3] < 0.): raise ValueError('Rodrigues vector rotation angle is negative')
if np.any(ro[...,3] < 0.0):
raise ValueError('Rodrigues vector rotation angle is negative') if normalize:
if not np.all(np.isclose(np.linalg.norm(ro[...,0:3],axis=-1), 1.0)): ro[...,0:3] /= np.linalg.norm(ro[...,0:3],axis=-1,keepdims=True)
elif not np.allclose(np.linalg.norm(ro[...,0:3],axis=-1),1.):
raise ValueError('Rodrigues vector rotation axis is not of unit length') raise ValueError('Rodrigues vector rotation axis is not of unit length')
return Rotation(Rotation._ro2qu(ro)) return Rotation(Rotation._ro2qu(ro))
@ -973,16 +999,18 @@ class Rotation:
P : int {-1,1}, optional P : int {-1,1}, optional
Sign convention. Defaults to -1. Sign convention. Defaults to -1.
Returns
-------
new : damask.Rotation
""" """
ho = np.array(h,dtype=float) ho = np.array(h,dtype=float)
if ho.shape[:-2:-1] != (3,): if ho.shape[:-2:-1] != (3,): raise ValueError('invalid shape')
raise ValueError('invalid shape') if abs(P) != 1: raise ValueError('P ∉ {-1,1}')
if abs(P) != 1:
raise ValueError('P ∉ {-1,1}')
ho *= -P ho *= -P
if np.any(np.linalg.norm(ho,axis=-1) >_R1+1e-9): if np.any(np.linalg.norm(ho,axis=-1) > _R1+1.e-9):
raise ValueError('homochoric coordinate outside of the sphere') raise ValueError('homochoric coordinate outside of the sphere')
return Rotation(Rotation._ho2qu(ho)) return Rotation(Rotation._ho2qu(ho))
@ -1000,14 +1028,15 @@ class Rotation:
P : int {-1,1}, optional P : int {-1,1}, optional
Sign convention. Defaults to -1. Sign convention. Defaults to -1.
Returns
-------
new : damask.Rotation
""" """
cu = np.array(x,dtype=float) cu = np.array(x,dtype=float)
if cu.shape[:-2:-1] != (3,): if cu.shape[:-2:-1] != (3,): raise ValueError('invalid shape')
raise ValueError('invalid shape') if abs(P) != 1: raise ValueError('P ∉ {-1,1}')
if abs(P) != 1: if np.abs(np.max(cu)) > np.pi**(2./3.) * 0.5+1.e-9:
raise ValueError('P ∉ {-1,1}')
if np.abs(np.max(cu)) > np.pi**(2./3.) * 0.5+1e-9:
raise ValueError('cubochoric coordinate outside of the cube') raise ValueError('cubochoric coordinate outside of the cube')
ho = -P * Rotation._cu2ho(cu) ho = -P * Rotation._cu2ho(cu)
@ -1016,29 +1045,33 @@ class Rotation:
@staticmethod @staticmethod
def from_random(shape: Union[int, IntSequence] = None, def from_random(shape: Union[None, int, IntSequence] = None,
rng_seed: NumpyRngSeed = None) -> 'Rotation': rng_seed: Optional[NumpyRngSeed] = None) -> 'Rotation':
""" """
Initialize with samples from a uniform distribution. Initialize with samples from a uniform distribution.
Parameters Parameters
---------- ----------
shape : int or sequence of ints, optional shape : (sequence of) int, optional
Shape of the returned array. Defaults to None, which gives a scalar. Shape of the returned array. Defaults to None, which gives a scalar.
rng_seed : {None, int, array_like[ints], SeedSequence, BitGenerator, Generator}, optional rng_seed : {None, int, array_like[ints], SeedSequence, BitGenerator, Generator}, optional
A seed to initialize the BitGenerator. A seed to initialize the BitGenerator.
Defaults to None, i.e. unpredictable entropy will be pulled from the OS. Defaults to None, i.e. unpredictable entropy will be pulled from the OS.
Returns
-------
new : damask.Rotation
""" """
rng = np.random.default_rng(rng_seed) rng = np.random.default_rng(rng_seed)
r = rng.random(3 if shape is None else tuple(shape)+(3,) if hasattr(shape, '__iter__') else (shape,3)) # type: ignore r = rng.random(3 if shape is None else tuple(shape)+(3,) if hasattr(shape, '__iter__') else (shape,3)) # type: ignore
A = np.sqrt(r[...,2]) A = np.sqrt(r[...,2])
B = np.sqrt(1.0-r[...,2]) B = np.sqrt(1.-r[...,2])
q = np.stack([np.cos(2.0*np.pi*r[...,0])*A, q = np.stack([np.cos(2.*np.pi*r[...,0])*A,
np.sin(2.0*np.pi*r[...,1])*B, np.sin(2.*np.pi*r[...,1])*B,
np.cos(2.0*np.pi*r[...,1])*B, np.cos(2.*np.pi*r[...,1])*B,
np.sin(2.0*np.pi*r[...,0])*A],axis=-1) np.sin(2.*np.pi*r[...,0])*A],axis=-1)
return Rotation(q if shape is None else q.reshape(r.shape[:-1]+(4,)))._standardize() return Rotation(q if shape is None else q.reshape(r.shape[:-1]+(4,)))._standardize()
@ -1046,10 +1079,10 @@ class Rotation:
@staticmethod @staticmethod
def from_ODF(weights: np.ndarray, def from_ODF(weights: np.ndarray,
phi: np.ndarray, phi: np.ndarray,
shape: Union[int, IntSequence] = None, shape: Union[None, int, IntSequence] = None,
degrees: bool = False, degrees: bool = False,
fractions: bool = True, fractions: bool = True,
rng_seed: NumpyRngSeed = None) -> 'Rotation': rng_seed: Optional[NumpyRngSeed] = None) -> 'Rotation':
""" """
Initialize with samples from a binned orientation distribution function (ODF). Initialize with samples from a binned orientation distribution function (ODF).
@ -1059,7 +1092,7 @@ class Rotation:
Texture intensity values (probability density or volume fraction) at Euler space grid points. Texture intensity values (probability density or volume fraction) at Euler space grid points.
phi : numpy.ndarray, shape (n,3) phi : numpy.ndarray, shape (n,3)
Grid coordinates in Euler space at which weights are defined. Grid coordinates in Euler space at which weights are defined.
shape : int or sequence of ints, optional shape : (sequence of) int, optional
Shape of the returned array. Defaults to None, which gives a scalar. Shape of the returned array. Defaults to None, which gives a scalar.
degrees : bool, optional degrees : bool, optional
Euler space grid coordinates are in degrees. Defaults to True. Euler space grid coordinates are in degrees. Defaults to True.
@ -1070,6 +1103,10 @@ class Rotation:
A seed to initialize the BitGenerator. A seed to initialize the BitGenerator.
Defaults to None, i.e. unpredictable entropy will be pulled from the OS. Defaults to None, i.e. unpredictable entropy will be pulled from the OS.
Returns
-------
new : damask.Rotation
Notes Notes
----- -----
Due to the distortion of Euler space in the vicinity of ϕ = 0, probability densities, p, defined on Due to the distortion of Euler space in the vicinity of ϕ = 0, probability densities, p, defined on
@ -1087,21 +1124,21 @@ class Rotation:
phi_sorted = eu[np.lexsort((eu[:,0],eu[:,1],eu[:,2]))] phi_sorted = eu[np.lexsort((eu[:,0],eu[:,1],eu[:,2]))]
steps,size,_ = grid_filters.cellsSizeOrigin_coordinates0_point(phi_sorted) steps,size,_ = grid_filters.cellsSizeOrigin_coordinates0_point(phi_sorted)
delta = np.radians(size/steps) if deg else size/steps delta = np.radians(size/steps) if deg else size/steps
return delta[0]*2.0*np.sin(delta[1]/2.0)*delta[2] / 8.0 / np.pi**2 * np.sin(np.radians(eu[:,1]) if deg else eu[:,1]) return delta[0]*2.*np.sin(delta[1]/2.)*delta[2] / 8. / np.pi**2 * np.sin(np.radians(eu[:,1]) if deg else eu[:,1])
dg = 1.0 if fractions else _dg(phi,degrees) dg = 1. if fractions else _dg(phi,degrees)
dV_V = dg * np.maximum(0.0,weights.squeeze()) dV_V = dg * np.maximum(0.,weights.squeeze())
N = 1 if shape is None else np.prod(shape) N = 1 if shape is None else np.prod(shape).astype(int)
return Rotation.from_Euler_angles(phi[util.hybrid_IA(dV_V,N,rng_seed)],degrees).reshape(() if shape is None else shape) return Rotation.from_Euler_angles(phi[util.hybrid_IA(dV_V,N,rng_seed)],degrees).reshape(() if shape is None else shape)
@staticmethod @staticmethod
def from_spherical_component(center: 'Rotation', def from_spherical_component(center: 'Rotation',
sigma: float, sigma: float,
shape: Union[int, IntSequence] = None, shape: Union[None, int, IntSequence] = None,
degrees: bool = False, degrees: bool = False,
rng_seed: NumpyRngSeed = None) -> 'Rotation': rng_seed: Optional[NumpyRngSeed] = None) -> 'Rotation':
""" """
Initialize with samples from a Gaussian distribution around a given center. Initialize with samples from a Gaussian distribution around a given center.
@ -1111,7 +1148,7 @@ class Rotation:
Central rotation. Central rotation.
sigma : float sigma : float
Standard deviation of (Gaussian) misorientation distribution. Standard deviation of (Gaussian) misorientation distribution.
shape : int or sequence of ints, optional shape : (sequence of) int, optional
Shape of the returned array. Defaults to None, which gives a scalar. Shape of the returned array. Defaults to None, which gives a scalar.
degrees : bool, optional degrees : bool, optional
sigma is given in degrees. Defaults to False. sigma is given in degrees. Defaults to False.
@ -1125,24 +1162,24 @@ class Rotation:
200 orientations: 200 orientations:
>>> import damask >>> import damask
>>> center = damask.Rotation.from_Euler_angles([35.0,45.0,0.0],degrees=True) >>> center = damask.Rotation.from_Euler_angles([35.,45.,0.],degrees=True)
>>> brass = damask.Rotation.from_spherical_component(center=center,sigma=3.0,shape=200,degrees=True) >>> brass = damask.Rotation.from_spherical_component(center=center,sigma=3.,shape=200,degrees=True)
Create a Goss texture consisting of Create a Goss texture consisting of
100 orientations: 100 orientations:
>>> import damask >>> import damask
>>> center = damask.Rotation.from_Euler_angles([0.0,45.0,0.0],degrees=True) >>> center = damask.Rotation.from_Euler_angles([0.,45.,0.],degrees=True)
>>> goss = damask.Rotation.from_spherical_component(center=center,sigma=3.0,shape=100,degrees=True) >>> goss = damask.Rotation.from_spherical_component(center=center,sigma=3.,shape=100,degrees=True)
""" """
rng = np.random.default_rng(rng_seed) rng = np.random.default_rng(rng_seed)
sigma = np.radians(sigma) if degrees else sigma sigma = np.radians(sigma) if degrees else sigma
N = 1 if shape is None else np.prod(shape) N = 1 if shape is None else np.prod(shape)
u,Theta = (rng.random((N,2)) * 2.0 * np.array([1,np.pi]) - np.array([1.0, 0])).T u,Theta = (rng.random((N,2)) * 2. * np.array([1.,np.pi]) - np.array([1.,0.])).T
omega = abs(rng.normal(scale=sigma,size=N)) omega = abs(rng.normal(scale=sigma,size=N))
p = np.column_stack([np.sqrt(1-u**2)*np.cos(Theta), p = np.column_stack([np.sqrt(1.-u**2)*np.cos(Theta),
np.sqrt(1-u**2)*np.sin(Theta), np.sqrt(1.-u**2)*np.sin(Theta),
u, omega]) u, omega])
return Rotation.from_axis_angle(p).reshape(() if shape is None else shape) * center return Rotation.from_axis_angle(p).reshape(() if shape is None else shape) * center
@ -1151,10 +1188,10 @@ class Rotation:
@staticmethod @staticmethod
def from_fiber_component(crystal: IntSequence, def from_fiber_component(crystal: IntSequence,
sample: IntSequence, sample: IntSequence,
sigma: float = 0.0, sigma: float = 0.,
shape: Union[int, IntSequence] = None, shape: Union[None, int, IntSequence] = None,
degrees: bool = False, degrees: bool = False,
rng_seed: NumpyRngSeed = None): rng_seed: Optional[NumpyRngSeed] = None) -> 'Rotation':
""" """
Initialize with samples from a Gaussian distribution around a given direction. Initialize with samples from a Gaussian distribution around a given direction.
@ -1169,7 +1206,7 @@ class Rotation:
sigma : float, optional sigma : float, optional
Standard deviation of (Gaussian) misorientation distribution. Standard deviation of (Gaussian) misorientation distribution.
Defaults to 0. Defaults to 0.
shape : int or sequence of ints, optional shape : (sequence of) int, optional
Shape of the returned array. Defaults to None, which gives a scalar. Shape of the returned array. Defaults to None, which gives a scalar.
degrees : bool, optional degrees : bool, optional
sigma and polar coordinates are given in degrees. Defaults to False. sigma and polar coordinates are given in degrees. Defaults to False.
@ -1177,6 +1214,10 @@ class Rotation:
A seed to initialize the BitGenerator. A seed to initialize the BitGenerator.
Defaults to None, i.e. unpredictable entropy will be pulled from the OS. Defaults to None, i.e. unpredictable entropy will be pulled from the OS.
Returns
-------
new : damask.Rotation
Notes Notes
----- -----
The crystal direction for (θ=0,φ=0) is [0 0 1], The crystal direction for (θ=0,φ=0) is [0 0 1],
@ -1201,7 +1242,7 @@ class Rotation:
100 orientations: 100 orientations:
>>> import damask >>> import damask
>>> gamma = damask.Rotation.from_fiber_component([54.7,45.0],[0.,0.],shape=100,degrees=True) >>> gamma = damask.Rotation.from_fiber_component([54.7,45.],[0.,0.],shape=100,degrees=True)
""" """
rng = np.random.default_rng(rng_seed) rng = np.random.default_rng(rng_seed)
@ -1211,18 +1252,18 @@ class Rotation:
d_cr = np.array([np.sin(alpha[0])*np.cos(alpha[1]), np.sin(alpha[0])*np.sin(alpha[1]), np.cos(alpha[0])]) d_cr = np.array([np.sin(alpha[0])*np.cos(alpha[1]), np.sin(alpha[0])*np.sin(alpha[1]), np.cos(alpha[0])])
d_lab = np.array([np.sin( beta[0])*np.cos( beta[1]), np.sin( beta[0])*np.sin( beta[1]), np.cos( beta[0])]) d_lab = np.array([np.sin( beta[0])*np.cos( beta[1]), np.sin( beta[0])*np.sin( beta[1]), np.cos( beta[0])])
ax_align = np.append(np.cross(d_lab,d_cr), np.arccos(np.dot(d_lab,d_cr))) ax_align = np.append(np.cross(d_lab,d_cr), np.arccos(np.dot(d_lab,d_cr)))
if np.isclose(ax_align[3],0.0): ax_align[:3] = np.array([1,0,0]) if np.isclose(ax_align[3],0.): ax_align[:3] = np.array([1.,0.,0.])
R_align = Rotation.from_axis_angle(ax_align if ax_align[3] > 0.0 else -ax_align,normalize=True) # rotate fiber axis from sample to crystal frame R_align = Rotation.from_axis_angle(ax_align if ax_align[3] > 0. else -ax_align,normalize=True) # rotate fiber axis from sample to crystal frame
N = 1 if shape is None else np.prod(shape) N = 1 if shape is None else np.prod(shape).astype(int)
u,Theta = (rng.random((N,2)) * 2.0 * np.array([1,np.pi]) - np.array([1.0, 0])).T u,Theta = (rng.random((N,2)) * 2. * np.array([1.,np.pi]) - np.array([1.,0.])).T
omega = abs(rng.normal(scale=sigma_,size=N)) omega = abs(rng.normal(scale=sigma_,size=N))
p = np.column_stack([np.sqrt(1-u**2)*np.cos(Theta), p = np.column_stack([np.sqrt(1.-u**2)*np.cos(Theta),
np.sqrt(1-u**2)*np.sin(Theta), np.sqrt(1.-u**2)*np.sin(Theta),
u, omega]) u, omega])
p[:,:3] = np.einsum('ij,...j',np.eye(3)-np.outer(d_lab,d_lab),p[:,:3]) # remove component along fiber axis p[:,:3] = np.einsum('ij,...j',np.eye(3)-np.outer(d_lab,d_lab),p[:,:3]) # remove component along fiber axis
f = np.column_stack((np.broadcast_to(d_lab,(N,3)),rng.random(N)*np.pi)) f = np.column_stack((np.broadcast_to(d_lab,(N,3)),rng.random(N)*np.pi))
f[::2,:3] *= -1 # flip half the rotation axes to negative sense f[::2,:3] *= -1. # flip half the rotation axes to negative sense
return (R_align.broadcast_to(N) return (R_align.broadcast_to(N)
* Rotation.from_axis_angle(p,normalize=True) * Rotation.from_axis_angle(p,normalize=True)
@ -1263,15 +1304,15 @@ class Rotation:
@staticmethod @staticmethod
def _qu2om(qu: np.ndarray) -> np.ndarray: def _qu2om(qu: np.ndarray) -> np.ndarray:
qq = qu[...,0:1]**2-(qu[...,1:2]**2 + qu[...,2:3]**2 + qu[...,3:4]**2) qq = qu[...,0:1]**2-(qu[...,1:2]**2 + qu[...,2:3]**2 + qu[...,3:4]**2)
om = np.block([qq + 2.0*qu[...,1:2]**2, om = np.block([qq + 2.*qu[...,1:2]**2,
2.0*(qu[...,2:3]*qu[...,1:2]-_P*qu[...,0:1]*qu[...,3:4]), 2.*(qu[...,2:3]*qu[...,1:2]-_P*qu[...,0:1]*qu[...,3:4]),
2.0*(qu[...,3:4]*qu[...,1:2]+_P*qu[...,0:1]*qu[...,2:3]), 2.*(qu[...,3:4]*qu[...,1:2]+_P*qu[...,0:1]*qu[...,2:3]),
2.0*(qu[...,1:2]*qu[...,2:3]+_P*qu[...,0:1]*qu[...,3:4]), 2.*(qu[...,1:2]*qu[...,2:3]+_P*qu[...,0:1]*qu[...,3:4]),
qq + 2.0*qu[...,2:3]**2, qq + 2.*qu[...,2:3]**2,
2.0*(qu[...,3:4]*qu[...,2:3]-_P*qu[...,0:1]*qu[...,1:2]), 2.*(qu[...,3:4]*qu[...,2:3]-_P*qu[...,0:1]*qu[...,1:2]),
2.0*(qu[...,1:2]*qu[...,3:4]-_P*qu[...,0:1]*qu[...,2:3]), 2.*(qu[...,1:2]*qu[...,3:4]-_P*qu[...,0:1]*qu[...,2:3]),
2.0*(qu[...,2:3]*qu[...,3:4]+_P*qu[...,0:1]*qu[...,1:2]), 2.*(qu[...,2:3]*qu[...,3:4]+_P*qu[...,0:1]*qu[...,1:2]),
qq + 2.0*qu[...,3:4]**2, qq + 2.*qu[...,3:4]**2,
]).reshape(qu.shape[:-1]+(3,3)) ]).reshape(qu.shape[:-1]+(3,3))
return om return om
@ -1286,22 +1327,20 @@ class Rotation:
q12_s = qu[...,1:2]**2+qu[...,2:3]**2 q12_s = qu[...,1:2]**2+qu[...,2:3]**2
chi = np.sqrt(q03_s*q12_s) chi = np.sqrt(q03_s*q12_s)
eu = np.where(np.abs(q12_s) < 1.0e-8, eu = np.where(np.abs(q12_s) < 1.e-8,
np.block([np.arctan2(-_P*2.0*qu[...,0:1]*qu[...,3:4],qu[...,0:1]**2-qu[...,3:4]**2), np.block([np.arctan2(-_P*2.*qu[...,0:1]*qu[...,3:4],qu[...,0:1]**2-qu[...,3:4]**2),
np.zeros(qu.shape[:-1]+(2,))]), np.zeros(qu.shape[:-1]+(2,))]),
np.where(np.abs(q03_s) < 1.0e-8, np.where(np.abs(q03_s) < 1.e-8,
np.block([np.arctan2( 2.0*qu[...,1:2]*qu[...,2:3],qu[...,1:2]**2-qu[...,2:3]**2), np.block([np.arctan2( 2.*qu[...,1:2]*qu[...,2:3],qu[...,1:2]**2-qu[...,2:3]**2),
np.broadcast_to(np.pi,qu[...,0:1].shape), np.broadcast_to(np.pi,qu[...,0:1].shape),
np.zeros(qu.shape[:-1]+(1,))]), np.zeros(qu.shape[:-1]+(1,))]),
np.block([np.arctan2((-_P*q02+q13)*chi, (-_P*q01-q23)*chi), np.block([np.arctan2((-_P*q02+q13)*chi, (-_P*q01-q23)*chi),
np.arctan2( 2.0*chi, q03_s-q12_s ), np.arctan2( 2.*chi, q03_s-q12_s ),
np.arctan2(( _P*q02+q13)*chi, (-_P*q01+q23)*chi)]) np.arctan2(( _P*q02+q13)*chi, (-_P*q01+q23)*chi)])
) )
) )
# reduce Euler angles to definition range eu[np.abs(eu) < 1.e-6] = 0.
eu[np.abs(eu)<1.e-6] = 0.0 return np.where(eu < 0., eu%(np.pi*np.array([2.,1.,2.])),eu)
eu = np.where(eu<0, (eu+2.0*np.pi)%np.array([2.0*np.pi,np.pi,2.0*np.pi]),eu) # needed?
return eu
@staticmethod @staticmethod
def _qu2ax(qu: np.ndarray) -> np.ndarray: def _qu2ax(qu: np.ndarray) -> np.ndarray:
@ -1312,11 +1351,11 @@ class Rotation:
""" """
with np.errstate(invalid='ignore',divide='ignore'): with np.errstate(invalid='ignore',divide='ignore'):
s = np.sign(qu[...,0:1])/np.sqrt(qu[...,1:2]**2+qu[...,2:3]**2+qu[...,3:4]**2) s = np.sign(qu[...,0:1])/np.sqrt(qu[...,1:2]**2+qu[...,2:3]**2+qu[...,3:4]**2)
omega = 2.0 * np.arccos(np.clip(qu[...,0:1],-1.0,1.0)) omega = 2. * np.arccos(np.clip(qu[...,0:1],-1.,1.))
ax = np.where(np.broadcast_to(qu[...,0:1] < 1.0e-8,qu.shape), ax = np.where(np.broadcast_to(qu[...,0:1] < 1.e-8,qu.shape),
np.block([qu[...,1:4],np.broadcast_to(np.pi,qu[...,0:1].shape)]), np.block([qu[...,1:4],np.broadcast_to(np.pi,qu[...,0:1].shape)]),
np.block([qu[...,1:4]*s,omega])) np.block([qu[...,1:4]*s,omega]))
ax[np.isclose(qu[...,0],1.,rtol=0.0)] = [0.0, 0.0, 1.0, 0.0] ax[np.isclose(qu[...,0],1.,rtol=0.)] = np.array([0.,0.,1.,0.])
return ax return ax
@staticmethod @staticmethod
@ -1324,23 +1363,23 @@ class Rotation:
"""Quaternion to RodriguesFrank vector.""" """Quaternion to RodriguesFrank vector."""
with np.errstate(invalid='ignore',divide='ignore'): with np.errstate(invalid='ignore',divide='ignore'):
s = np.linalg.norm(qu[...,1:4],axis=-1,keepdims=True) s = np.linalg.norm(qu[...,1:4],axis=-1,keepdims=True)
ro = np.where(np.broadcast_to(np.abs(qu[...,0:1]) < 1.0e-12,qu.shape), ro = np.where(np.broadcast_to(np.abs(qu[...,0:1]) < 1.e-12,qu.shape),
np.block([qu[...,1:2], qu[...,2:3], qu[...,3:4], np.broadcast_to(np.inf,qu[...,0:1].shape)]), np.block([qu[...,1:2], qu[...,2:3], qu[...,3:4], np.broadcast_to(np.inf,qu[...,0:1].shape)]),
np.block([qu[...,1:2]/s,qu[...,2:3]/s,qu[...,3:4]/s, np.block([qu[...,1:2]/s,qu[...,2:3]/s,qu[...,3:4]/s,
np.tan(np.arccos(np.clip(qu[...,0:1],-1.0,1.0))) np.tan(np.arccos(np.clip(qu[...,0:1],-1.,1.)))
]) ])
) )
ro[np.abs(s).squeeze(-1) < 1.0e-12] = [0.0,0.0,_P,0.0] ro[np.abs(s).squeeze(-1) < 1.e-12] = np.array([0.,0.,_P,0.])
return ro return ro
@staticmethod @staticmethod
def _qu2ho(qu: np.ndarray) -> np.ndarray: def _qu2ho(qu: np.ndarray) -> np.ndarray:
"""Quaternion to homochoric vector.""" """Quaternion to homochoric vector."""
with np.errstate(invalid='ignore'): with np.errstate(invalid='ignore'):
omega = 2.0 * np.arccos(np.clip(qu[...,0:1],-1.0,1.0)) omega = 2. * np.arccos(np.clip(qu[...,0:1],-1.,1.))
ho = np.where(np.abs(omega) < 1.0e-12, ho = np.where(np.abs(omega) < 1.e-12,
np.zeros(3), np.zeros(3),
qu[...,1:4]/np.linalg.norm(qu[...,1:4],axis=-1,keepdims=True) \ qu[...,1:4]/np.linalg.norm(qu[...,1:4],axis=-1,keepdims=True)
* (0.75*(omega - np.sin(omega)))**(1./3.)) * (0.75*(omega - np.sin(omega)))**(1./3.))
return ho return ho
@ -1362,12 +1401,12 @@ class Rotation:
trace = om[...,0,0:1] + om[...,1,1:2] + om[...,2,2:3] trace = om[...,0,0:1] + om[...,1,1:2] + om[...,2,2:3]
with np.errstate(invalid='ignore',divide='ignore'): with np.errstate(invalid='ignore',divide='ignore'):
s = [ s = np.array([
0.5 / np.sqrt( 1.0 + trace), 0.5 / np.sqrt( 1. + trace),
2.0 * np.sqrt( 1.0 + om[...,0,0:1] - om[...,1,1:2] - om[...,2,2:3]), 2. * np.sqrt( 1. + om[...,0,0:1] - om[...,1,1:2] - om[...,2,2:3]),
2.0 * np.sqrt( 1.0 + om[...,1,1:2] - om[...,2,2:3] - om[...,0,0:1]), 2. * np.sqrt( 1. + om[...,1,1:2] - om[...,2,2:3] - om[...,0,0:1]),
2.0 * np.sqrt( 1.0 + om[...,2,2:3] - om[...,0,0:1] - om[...,1,1:2] ) 2. * np.sqrt( 1. + om[...,2,2:3] - om[...,0,0:1] - om[...,1,1:2] )
] ])
qu = np.where(trace>0, qu = np.where(trace>0,
np.block([0.25 / s[0], np.block([0.25 / s[0],
(om[...,2,1:2] - om[...,1,2:3] ) * s[0], (om[...,2,1:2] - om[...,1,2:3] ) * s[0],
@ -1389,18 +1428,18 @@ class Rotation:
0.25 * s[3]]), 0.25 * s[3]]),
) )
) )
)*np.array([1,_P,_P,_P]) )*np.array([1.,_P,_P,_P])
qu[qu[...,0]<0] *=-1 qu[qu[...,0] < 0.] *= -1.
return qu return qu
@staticmethod @staticmethod
def _om2eu(om: np.ndarray) -> np.ndarray: def _om2eu(om: np.ndarray) -> np.ndarray:
"""Rotation matrix to Bunge Euler angles.""" """Rotation matrix to Bunge Euler angles."""
with np.errstate(invalid='ignore',divide='ignore'): with np.errstate(invalid='ignore',divide='ignore'):
zeta = 1.0/np.sqrt(1.0-om[...,2,2:3]**2) zeta = 1./np.sqrt(1.-om[...,2,2:3]**2)
eu = np.where(np.isclose(np.abs(om[...,2,2:3]),1.0,0.0), eu = np.where(np.isclose(np.abs(om[...,2,2:3]),1.,0.),
np.block([np.arctan2(om[...,0,1:2],om[...,0,0:1]), np.block([np.arctan2(om[...,0,1:2],om[...,0,0:1]),
np.pi*0.5*(1-om[...,2,2:3]), np.pi*0.5*(1.-om[...,2,2:3]),
np.zeros(om.shape[:-2]+(1,)), np.zeros(om.shape[:-2]+(1,)),
]), ]),
np.block([np.arctan2(om[...,2,0:1]*zeta,-om[...,2,1:2]*zeta), np.block([np.arctan2(om[...,2,0:1]*zeta,-om[...,2,1:2]*zeta),
@ -1409,8 +1448,7 @@ class Rotation:
]) ])
) )
eu[np.abs(eu) < 1.e-8] = 0.0 eu[np.abs(eu) < 1.e-8] = 0.0
eu = np.where(eu<0, (eu+2.0*np.pi)%np.array([2.0*np.pi,np.pi,2.0*np.pi]),eu) return np.where(eu < 0., eu%(np.pi*np.array([2.,1.,2.])),eu)
return eu
@staticmethod @staticmethod
def _om2ax(om: np.ndarray) -> np.ndarray: def _om2ax(om: np.ndarray) -> np.ndarray:
@ -1419,18 +1457,18 @@ class Rotation:
om[...,2,0:1]-om[...,0,2:3], om[...,2,0:1]-om[...,0,2:3],
om[...,0,1:2]-om[...,1,0:1] om[...,0,1:2]-om[...,1,0:1]
]) ])
t = 0.5*(om.trace(axis2=-2,axis1=-1) -1.0).reshape(om.shape[:-2]+(1,)) t = 0.5*(om.trace(axis2=-2,axis1=-1) -1.).reshape(om.shape[:-2]+(1,))
w,vr = np.linalg.eig(om) w,vr = np.linalg.eig(om)
# mask duplicated real eigenvalues # mask duplicated real eigenvalues
w[np.isclose(w[...,0],1.0+0.0j),1:] = 0. w[np.isclose(w[...,0],1.+0.j),1:] = 0.
w[np.isclose(w[...,1],1.0+0.0j),2:] = 0. w[np.isclose(w[...,1],1.+0.j),2:] = 0.
vr = np.swapaxes(vr,-1,-2) vr = np.swapaxes(vr,-1,-2)
ax = np.where(np.abs(diag_delta)<1e-13, ax = np.where(np.abs(diag_delta)<1.e-13,
np.real(vr[np.isclose(w,1.0+0.0j)]).reshape(om.shape[:-2]+(3,)), np.real(vr[np.isclose(w,1.+0.j)]).reshape(om.shape[:-2]+(3,)),
np.abs(np.real(vr[np.isclose(w,1.0+0.0j)]).reshape(om.shape[:-2]+(3,))) \ np.abs(np.real(vr[np.isclose(w,1.+0.j)]).reshape(om.shape[:-2]+(3,)))
*np.sign(diag_delta)) *np.sign(diag_delta))
ax = np.block([ax,np.arccos(np.clip(t,-1.0,1.0))]) ax = np.block([ax,np.arccos(np.clip(t,-1.,1.))])
ax[np.abs(ax[...,3])<1.e-8] = [ 0.0, 0.0, 1.0, 0.0] ax[np.abs(ax[...,3]) < 1.e-8] = np.array([0.,0.,1.,0.])
return ax return ax
@staticmethod @staticmethod
@ -1460,7 +1498,7 @@ class Rotation:
-_P*sPhi*np.cos(ee[...,0:1]-ee[...,2:3]), -_P*sPhi*np.cos(ee[...,0:1]-ee[...,2:3]),
-_P*sPhi*np.sin(ee[...,0:1]-ee[...,2:3]), -_P*sPhi*np.sin(ee[...,0:1]-ee[...,2:3]),
-_P*cPhi*np.sin(ee[...,0:1]+ee[...,2:3])]) -_P*cPhi*np.sin(ee[...,0:1]+ee[...,2:3])])
qu[qu[...,0]<0.0]*=-1 qu[qu[...,0] < 0.] *= -1.
return qu return qu
@staticmethod @staticmethod
@ -1478,7 +1516,7 @@ class Rotation:
-c[...,0:1]*s[...,1:2], -c[...,0:1]*s[...,1:2],
+c[...,1:2] +c[...,1:2]
]).reshape(eu.shape[:-1]+(3,3)) ]).reshape(eu.shape[:-1]+(3,3))
om[np.abs(om)<1.e-12] = 0.0 om[np.abs(om) < 1.e-12] = 0.
return om return om
@staticmethod @staticmethod
@ -1488,16 +1526,16 @@ class Rotation:
sigma = 0.5*(eu[...,0:1]+eu[...,2:3]) sigma = 0.5*(eu[...,0:1]+eu[...,2:3])
delta = 0.5*(eu[...,0:1]-eu[...,2:3]) delta = 0.5*(eu[...,0:1]-eu[...,2:3])
tau = np.linalg.norm(np.block([t,np.sin(sigma)]),axis=-1,keepdims=True) tau = np.linalg.norm(np.block([t,np.sin(sigma)]),axis=-1,keepdims=True)
alpha = np.where(np.abs(np.cos(sigma))<1.e-12,np.pi,2.0*np.arctan(tau/np.cos(sigma))) alpha = np.where(np.abs(np.cos(sigma))<1.e-12,np.pi,2.*np.arctan(tau/np.cos(sigma)))
with np.errstate(invalid='ignore',divide='ignore'): with np.errstate(invalid='ignore',divide='ignore'):
ax = np.where(np.broadcast_to(np.abs(alpha)<1.0e-12,eu.shape[:-1]+(4,)), ax = np.where(np.broadcast_to(np.abs(alpha)<1.e-12,eu.shape[:-1]+(4,)),
[0.0,0.0,1.0,0.0], [0.,0.,1.,0.],
np.block([-_P/tau*t*np.cos(delta), np.block([-_P/tau*t*np.cos(delta),
-_P/tau*t*np.sin(delta), -_P/tau*t*np.sin(delta),
-_P/tau* np.sin(sigma), -_P/tau* np.sin(sigma),
alpha alpha
])) ]))
ax[(alpha<0.0).squeeze()] *=-1 ax[(alpha<0.).squeeze()] *= -1.
return ax return ax
@staticmethod @staticmethod
@ -1506,7 +1544,7 @@ class Rotation:
ax = Rotation._eu2ax(eu) ax = Rotation._eu2ax(eu)
ro = np.block([ax[...,:3],np.tan(ax[...,3:4]*.5)]) ro = np.block([ax[...,:3],np.tan(ax[...,3:4]*.5)])
ro[ax[...,3] >= np.pi,3] = np.inf ro[ax[...,3] >= np.pi,3] = np.inf
ro[np.abs(ax[...,3])<1.e-16] = [ 0.0, 0.0, _P, 0.0 ] ro[np.abs(ax[...,3])<1.e-16] = np.array([0.,0.,_P,0.])
return ro return ro
@staticmethod @staticmethod
@ -1526,7 +1564,7 @@ class Rotation:
"""Axisangle pair to quaternion.""" """Axisangle pair to quaternion."""
c = np.cos(ax[...,3:4]*.5) c = np.cos(ax[...,3:4]*.5)
s = np.sin(ax[...,3:4]*.5) s = np.sin(ax[...,3:4]*.5)
qu = np.where(np.abs(ax[...,3:4])<1.e-6,[1.0, 0.0, 0.0, 0.0],np.block([c, ax[...,:3]*s])) qu = np.where(np.abs(ax[...,3:4]) < 1.e-6,[1.,0.,0.,0.],np.block([c,ax[...,:3]*s]))
return qu return qu
@staticmethod @staticmethod
@ -1544,7 +1582,7 @@ class Rotation:
omc*ax[...,0:1]*ax[...,2:3] + s*ax[...,1:2], omc*ax[...,0:1]*ax[...,2:3] + s*ax[...,1:2],
omc*ax[...,1:2]*ax[...,2:3] - s*ax[...,0:1], omc*ax[...,1:2]*ax[...,2:3] - s*ax[...,0:1],
c+omc*ax[...,2:3]**2]).reshape(ax.shape[:-1]+(3,3)) c+omc*ax[...,2:3]**2]).reshape(ax.shape[:-1]+(3,3))
return om if _P < 0.0 else np.swapaxes(om,-1,-2) return om if _P < 0. else np.swapaxes(om,-1,-2)
@staticmethod @staticmethod
def _ax2eu(ax: np.ndarray) -> np.ndarray: def _ax2eu(ax: np.ndarray) -> np.ndarray:
@ -1559,15 +1597,14 @@ class Rotation:
np.inf, np.inf,
np.tan(ax[...,3:4]*0.5)) np.tan(ax[...,3:4]*0.5))
]) ])
ro[np.abs(ax[...,3])<1.e-6] = [.0,.0,_P,.0] ro[np.abs(ax[...,3]) < 1.e-6] = np.array([.0,.0,_P,.0])
return ro return ro
@staticmethod @staticmethod
def _ax2ho(ax: np.ndarray) -> np.ndarray: def _ax2ho(ax: np.ndarray) -> np.ndarray:
"""Axisangle pair to homochoric vector.""" """Axisangle pair to homochoric vector."""
f = (0.75 * ( ax[...,3:4] - np.sin(ax[...,3:4]) ))**(1.0/3.0) f = (0.75 * ( ax[...,3:4] - np.sin(ax[...,3:4]) ))**(1./3.)
ho = ax[...,:3] * f return ax[...,:3] * f
return ho
@staticmethod @staticmethod
def _ax2cu(ax: np.ndarray) -> np.ndarray: def _ax2cu(ax: np.ndarray) -> np.ndarray:
@ -1598,16 +1635,15 @@ class Rotation:
ax = np.where(np.isfinite(ro[...,3:4]), ax = np.where(np.isfinite(ro[...,3:4]),
np.block([ro[...,0:3]*np.linalg.norm(ro[...,0:3],axis=-1,keepdims=True),2.*np.arctan(ro[...,3:4])]), np.block([ro[...,0:3]*np.linalg.norm(ro[...,0:3],axis=-1,keepdims=True),2.*np.arctan(ro[...,3:4])]),
np.block([ro[...,0:3],np.broadcast_to(np.pi,ro[...,3:4].shape)])) np.block([ro[...,0:3],np.broadcast_to(np.pi,ro[...,3:4].shape)]))
ax[np.abs(ro[...,3]) < 1.e-8] = np.array([ 0.0, 0.0, 1.0, 0.0 ]) ax[np.abs(ro[...,3]) < 1.e-8] = np.array([0.,0.,1.,0.])
return ax return ax
@staticmethod @staticmethod
def _ro2ho(ro: np.ndarray) -> np.ndarray: def _ro2ho(ro: np.ndarray) -> np.ndarray:
"""RodriguesFrank vector to homochoric vector.""" """RodriguesFrank vector to homochoric vector."""
f = np.where(np.isfinite(ro[...,3:4]),2.0*np.arctan(ro[...,3:4]) -np.sin(2.0*np.arctan(ro[...,3:4])),np.pi) f = np.where(np.isfinite(ro[...,3:4]),2.*np.arctan(ro[...,3:4]) -np.sin(2.*np.arctan(ro[...,3:4])),np.pi)
ho = np.where(np.broadcast_to(np.sum(ro[...,0:3]**2.0,axis=-1,keepdims=True) < 1.e-8,ro[...,0:3].shape), return np.where(np.broadcast_to(np.sum(ro[...,0:3]**2,axis=-1,keepdims=True) < 1.e-8,ro[...,0:3].shape),
np.zeros(3), ro[...,0:3]* (0.75*f)**(1.0/3.0)) np.zeros(3), ro[...,0:3]* (0.75*f)**(1./3.))
return ho
@staticmethod @staticmethod
def _ro2cu(ro: np.ndarray) -> np.ndarray: def _ro2cu(ro: np.ndarray) -> np.ndarray:
@ -1641,13 +1677,12 @@ class Rotation:
+9.528014229335313e-6, -5.660288876265125e-6, +1.2844901692764126e-6, +9.528014229335313e-6, -5.660288876265125e-6, +1.2844901692764126e-6,
+1.1255185726258763e-6, -1.3834391419956455e-6, +7.513691751164847e-7, +1.1255185726258763e-6, -1.3834391419956455e-6, +7.513691751164847e-7,
-2.401996891720091e-7, +4.386887017466388e-8, -3.5917775353564864e-9]) -2.401996891720091e-7, +4.386887017466388e-8, -3.5917775353564864e-9])
hmag_squared = np.sum(ho**2.,axis=-1,keepdims=True) hmag_squared = np.sum(ho**2,axis=-1,keepdims=True)
s = np.sum(tfit*hmag_squared**np.arange(len(tfit)),axis=-1,keepdims=True) s = np.sum(tfit*hmag_squared**np.arange(len(tfit)),axis=-1,keepdims=True)
with np.errstate(invalid='ignore'): with np.errstate(invalid='ignore'):
ax = np.where(np.broadcast_to(np.abs(hmag_squared)<1.e-8,ho.shape[:-1]+(4,)), return np.where(np.broadcast_to(np.abs(hmag_squared)<1.e-8,ho.shape[:-1]+(4,)),
[ 0.0, 0.0, 1.0, 0.0 ], [0.,0.,1.,0.],
np.block([ho/np.sqrt(hmag_squared),2.0*np.arccos(np.clip(s,-1.0,1.0))])) np.block([ho/np.sqrt(hmag_squared),2.*np.arccos(np.clip(s,-1.,1.))]))
return ax
@staticmethod @staticmethod
def _ho2ro(ho: np.ndarray) -> np.ndarray: def _ho2ro(ho: np.ndarray) -> np.ndarray:
@ -1671,27 +1706,25 @@ class Rotation:
with np.errstate(invalid='ignore',divide='ignore'): with np.errstate(invalid='ignore',divide='ignore'):
# inverse M_3 # inverse M_3
xyz2 = xyz3[...,0:2] * np.sqrt( 2.0*rs/(rs+np.abs(xyz3[...,2:3])) ) xyz2 = xyz3[...,0:2] * np.sqrt( 2.*rs/(rs+np.abs(xyz3[...,2:3])) )
qxy = np.sum(xyz2**2,axis=-1,keepdims=True) qxy = np.sum(xyz2**2,axis=-1,keepdims=True)
q2 = qxy + np.max(np.abs(xyz2),axis=-1,keepdims=True)**2 q2 = qxy + np.max(np.abs(xyz2),axis=-1,keepdims=True)**2
sq2 = np.sqrt(q2) sq2 = np.sqrt(q2)
q = (_beta/np.sqrt(2.0)/_R1) * np.sqrt(q2*qxy/(q2-np.max(np.abs(xyz2),axis=-1,keepdims=True)*sq2)) q = (_beta/np.sqrt(2.)/_R1) * np.sqrt(q2*qxy/(q2-np.max(np.abs(xyz2),axis=-1,keepdims=True)*sq2))
tt = np.clip((np.min(np.abs(xyz2),axis=-1,keepdims=True)**2\ tt = np.clip((np.min(np.abs(xyz2),axis=-1,keepdims=True)**2\
+np.max(np.abs(xyz2),axis=-1,keepdims=True)*sq2)/np.sqrt(2.0)/qxy,-1.0,1.0) +np.max(np.abs(xyz2),axis=-1,keepdims=True)*sq2)/np.sqrt(2.)/qxy,-1.,1.)
T_inv = np.where(np.abs(xyz2[...,1:2]) <= np.abs(xyz2[...,0:1]), T_inv = np.where(np.abs(xyz2[...,1:2]) <= np.abs(xyz2[...,0:1]),
np.block([np.ones_like(tt),np.arccos(tt)/np.pi*12.0]), np.block([np.ones_like(tt),np.arccos(tt)/np.pi*12.]),
np.block([np.arccos(tt)/np.pi*12.0,np.ones_like(tt)]))*q np.block([np.arccos(tt)/np.pi*12.,np.ones_like(tt)]))*q
T_inv[xyz2<0.0] *= -1.0 T_inv[xyz2<0.] *= -1.
T_inv[np.broadcast_to(np.isclose(qxy,0.0,rtol=0.0,atol=1.0e-12),T_inv.shape)] = 0.0 T_inv[np.broadcast_to(np.isclose(qxy,0.,rtol=0.,atol=1.e-12),T_inv.shape)] = 0.
cu = np.block([T_inv, np.where(xyz3[...,2:3]<0.0,-np.ones_like(xyz3[...,2:3]),np.ones_like(xyz3[...,2:3])) \ cu = np.block([T_inv, np.where(xyz3[...,2:3]<0.,-np.ones_like(xyz3[...,2:3]),np.ones_like(xyz3[...,2:3])) \
* rs/np.sqrt(6.0/np.pi), * rs/np.sqrt(6./np.pi),
])/ _sc ])/ _sc
cu[np.isclose(np.sum(np.abs(ho),axis=-1),0.0,rtol=0.0,atol=1.0e-16)] = 0.0 cu[np.isclose(np.sum(np.abs(ho),axis=-1),0.,rtol=0.,atol=1.e-16)] = 0.
cu = np.take_along_axis(cu,Rotation._get_pyramid_order(ho,'backward'),-1) return np.take_along_axis(cu,Rotation._get_pyramid_order(ho,'backward'),-1)
return cu
#---------- Cubochoric ---------- #---------- Cubochoric ----------
@staticmethod @staticmethod
@ -1734,32 +1767,30 @@ class Rotation:
# get pyramid and scale by grid parameter ratio # get pyramid and scale by grid parameter ratio
XYZ = np.take_along_axis(cu,Rotation._get_pyramid_order(cu,'forward'),-1) * _sc XYZ = np.take_along_axis(cu,Rotation._get_pyramid_order(cu,'forward'),-1) * _sc
order = np.abs(XYZ[...,1:2]) <= np.abs(XYZ[...,0:1]) order = np.abs(XYZ[...,1:2]) <= np.abs(XYZ[...,0:1])
q = np.pi/12.0 * np.where(order,XYZ[...,1:2],XYZ[...,0:1]) \ q = np.pi/12. * np.where(order,XYZ[...,1:2],XYZ[...,0:1]) \
/ np.where(order,XYZ[...,0:1],XYZ[...,1:2]) / np.where(order,XYZ[...,0:1],XYZ[...,1:2])
c = np.cos(q) c = np.cos(q)
s = np.sin(q) s = np.sin(q)
q = _R1*2.0**0.25/_beta/ np.sqrt(np.sqrt(2.0)-c) \ q = _R1*2.**0.25/_beta/ np.sqrt(np.sqrt(2.)-c) \
* np.where(order,XYZ[...,0:1],XYZ[...,1:2]) * np.where(order,XYZ[...,0:1],XYZ[...,1:2])
T = np.block([ (np.sqrt(2.0)*c - 1.0), np.sqrt(2.0) * s]) * q T = np.block([(np.sqrt(2.)*c - 1.), np.sqrt(2.) * s]) * q
# transform to sphere grid (inverse Lambert) # transform to sphere grid (inverse Lambert)
c = np.sum(T**2,axis=-1,keepdims=True) c = np.sum(T**2,axis=-1,keepdims=True)
s = c * np.pi/24.0 /XYZ[...,2:3]**2 s = c * np.pi/24. /XYZ[...,2:3]**2
c = c * np.sqrt(np.pi/24.0)/XYZ[...,2:3] c = c * np.sqrt(np.pi/24.)/XYZ[...,2:3]
q = np.sqrt( 1.0 - s) q = np.sqrt( 1. - s)
ho = np.where(np.isclose(np.sum(np.abs(XYZ[...,0:2]),axis=-1,keepdims=True),0.0,rtol=0.0,atol=1.0e-16), ho = np.where(np.isclose(np.sum(np.abs(XYZ[...,0:2]),axis=-1,keepdims=True),0.,rtol=0.,atol=1.e-16),
np.block([np.zeros_like(XYZ[...,0:2]),np.sqrt(6.0/np.pi) *XYZ[...,2:3]]), np.block([np.zeros_like(XYZ[...,0:2]),np.sqrt(6./np.pi)*XYZ[...,2:3]]),
np.block([np.where(order,T[...,0:1],T[...,1:2])*q, np.block([np.where(order,T[...,0:1],T[...,1:2])*q,
np.where(order,T[...,1:2],T[...,0:1])*q, np.where(order,T[...,1:2],T[...,0:1])*q,
np.sqrt(6.0/np.pi) * XYZ[...,2:3] - c]) np.sqrt(6./np.pi) * XYZ[...,2:3] - c])
) )
ho[np.isclose(np.sum(np.abs(cu),axis=-1),0.0,rtol=0.0,atol=1.0e-16)] = 0.0 ho[np.isclose(np.sum(np.abs(cu),axis=-1),0.,rtol=0.,atol=1.e-16)] = 0.
ho = np.take_along_axis(ho,Rotation._get_pyramid_order(cu,'backward'),-1) return np.take_along_axis(ho,Rotation._get_pyramid_order(cu,'backward'),-1)
return ho
@staticmethod @staticmethod

View File

@ -1,6 +1,6 @@
import re import re
import copy import copy
from typing import Union, Tuple, List, Iterable from typing import Optional, Union, Tuple, List, Iterable
import pandas as pd import pandas as pd
import numpy as np import numpy as np
@ -13,8 +13,8 @@ class Table:
def __init__(self, def __init__(self,
shapes: dict = {}, shapes: dict = {},
data: np.ndarray = None, data: Optional[np.ndarray] = None,
comments: Union[str, Iterable[str]] = None): comments: Union[None, str, Iterable[str]] = None):
""" """
New spreadsheet. New spreadsheet.
@ -25,7 +25,7 @@ class Table:
For instance, 'F':(3,3) for a deformation gradient, or 'r':(1,) for a scalar. For instance, 'F':(3,3) for a deformation gradient, or 'r':(1,) for a scalar.
data : numpy.ndarray or pandas.DataFrame, optional data : numpy.ndarray or pandas.DataFrame, optional
Data. Existing column labels of a pandas.DataFrame will be replaced. Data. Existing column labels of a pandas.DataFrame will be replaced.
comments : str or iterable of str, optional comments : (iterable of) str, optional
Additional, human-readable information. Additional, human-readable information.
""" """
@ -188,7 +188,7 @@ class Table:
def _add_comment(self, def _add_comment(self,
label: str, label: str,
shape: Tuple[int, ...], shape: Tuple[int, ...],
info: str = None): info: Optional[str] = None):
if info is not None: if info is not None:
specific = f'{label}{" "+str(shape) if np.prod(shape,dtype=np.int64) > 1 else ""}: {info}' specific = f'{label}{" "+str(shape) if np.prod(shape,dtype=np.int64) > 1 else ""}: {info}'
general = util.execution_stamp('Table') general = util.execution_stamp('Table')
@ -383,7 +383,7 @@ class Table:
def set(self, def set(self,
label: str, label: str,
data: np.ndarray, data: np.ndarray,
info: str = None) -> 'Table': info: Optional[str] = None) -> 'Table':
""" """
Add new or replace existing column data. Add new or replace existing column data.
@ -458,15 +458,15 @@ class Table:
def rename(self, def rename(self,
old: Union[str, Iterable[str]], old: Union[str, Iterable[str]],
new: Union[str, Iterable[str]], new: Union[str, Iterable[str]],
info: str = None) -> 'Table': info: Optional[str] = None) -> 'Table':
""" """
Rename column data. Rename column data.
Parameters Parameters
---------- ----------
label_old : str or iterable of str label_old : (iterable of) str
Old column label(s). Old column label(s).
label_new : str or iterable of str label_new : (iterable of) str
New column label(s). New column label(s).
Returns Returns

View File

@ -1,7 +1,7 @@
import os import os
import multiprocessing as mp import multiprocessing as mp
from pathlib import Path from pathlib import Path
from typing import Union, Literal, List, Sequence from typing import Optional, Union, Literal, List, Sequence
import numpy as np import numpy as np
import vtk import vtk
@ -110,13 +110,16 @@ class VTK:
Parameters Parameters
---------- ----------
comments : str or sequence of str comments : (sequence of) str
Comments. Comments.
""" """
s = vtk.vtkStringArray() s = vtk.vtkStringArray()
s.SetName('comments') s.SetName('comments')
for c in util.tail_repack(comments,self.comments): comments_ = util.tail_repack(comments,self.comments) if comments[:len(self.comments)] == self.comments else \
[comments] if isinstance(comments,str) else \
comments
for c in comments_:
s.InsertNextValue(c) s.InsertNextValue(c)
self.vtk_data.GetFieldData().AddArray(s) self.vtk_data.GetFieldData().AddArray(s)
@ -286,7 +289,7 @@ class VTK:
@staticmethod @staticmethod
def load(fname: Union[str, Path], def load(fname: Union[str, Path],
dataset_type: Literal['ImageData', 'UnstructuredGrid', 'PolyData', 'RectilinearGrid'] = None) -> 'VTK': dataset_type: Literal[None, 'ImageData', 'UnstructuredGrid', 'PolyData', 'RectilinearGrid'] = None) -> 'VTK':
""" """
Load from VTK file. Load from VTK file.
@ -409,11 +412,11 @@ class VTK:
# Check https://blog.kitware.com/ghost-and-blanking-visibility-changes/ for missing data # Check https://blog.kitware.com/ghost-and-blanking-visibility-changes/ for missing data
def set(self, def set(self,
label: str = None, label: Optional[str] = None,
data: Union[np.ndarray, np.ma.MaskedArray] = None, data: Union[None, np.ndarray, np.ma.MaskedArray] = None,
info: str = None, info: Optional[str] = None,
*, *,
table: 'Table' = None): table: Optional['Table'] = None):
""" """
Add new or replace existing point or cell data. Add new or replace existing point or cell data.
@ -533,7 +536,7 @@ class VTK:
def show(self, def show(self,
label: str = None, label: Optional[str] = None,
colormap: Union[Colormap, str] = 'cividis'): colormap: Union[Colormap, str] = 'cividis'):
""" """
Render. Render.
@ -547,9 +550,11 @@ class VTK:
Notes Notes
----- -----
See http://compilatrix.com/article/vtk-1 for further ideas. The first component is shown when visualizing vector datasets
(this includes tensor datasets because they are flattened).
""" """
# See http://compilatrix.com/article/vtk-1 for possible improvements.
try: try:
import wx import wx
_ = wx.App(False) # noqa _ = wx.App(False) # noqa

View File

@ -1,7 +1,6 @@
"""Functionality for generation of seed points for Voronoi or Laguerre tessellation.""" """Functionality for generation of seed points for Voronoi or Laguerre tessellation."""
from typing import Tuple as _Tuple from typing import Optional as _Optional, Tuple as _Tuple
from scipy import spatial as _spatial from scipy import spatial as _spatial
import numpy as _np import numpy as _np
@ -14,8 +13,8 @@ from . import grid_filters as _grid_filters
def from_random(size: _FloatSequence, def from_random(size: _FloatSequence,
N_seeds: int, N_seeds: int,
cells: _IntSequence = None, cells: _Optional[_IntSequence] = None,
rng_seed: _NumpyRngSeed = None) -> _np.ndarray: rng_seed: _Optional[_NumpyRngSeed] = None) -> _np.ndarray:
""" """
Place seeds randomly in space. Place seeds randomly in space.
@ -55,7 +54,7 @@ def from_Poisson_disc(size: _FloatSequence,
N_candidates: int, N_candidates: int,
distance: float, distance: float,
periodic: bool = True, periodic: bool = True,
rng_seed: _NumpyRngSeed = None) -> _np.ndarray: rng_seed: _Optional[_NumpyRngSeed] = None) -> _np.ndarray:
""" """
Place seeds according to a Poisson disc distribution. Place seeds according to a Poisson disc distribution.
@ -107,7 +106,7 @@ def from_Poisson_disc(size: _FloatSequence,
def from_grid(grid, def from_grid(grid,
selection: _IntCollection = None, selection: _Optional[_IntCollection] = None,
invert_selection: bool = False, invert_selection: bool = False,
average: bool = False, average: bool = False,
periodic: bool = True) -> _Tuple[_np.ndarray, _np.ndarray]: periodic: bool = True) -> _Tuple[_np.ndarray, _np.ndarray]:
@ -118,7 +117,7 @@ def from_grid(grid,
---------- ----------
grid : damask.Grid grid : damask.Grid
Grid from which the material IDs are used as seeds. Grid from which the material IDs are used as seeds.
selection : int or collection of int, optional selection : (collection of) int, optional
Material IDs to consider. Material IDs to consider.
invert_selection : bool, optional invert_selection : bool, optional
Consider all material IDs except those in selection. Defaults to False. Consider all material IDs except those in selection. Defaults to False.

View File

@ -3,7 +3,7 @@ import shlex
import re import re
from pathlib import Path from pathlib import Path
_marc_version = '2022.1' _marc_version = '2022.2'
_marc_root = '/opt/msc' _marc_root = '/opt/msc'
_damask_root = str(Path(__file__).parents[3]) _damask_root = str(Path(__file__).parents[3])

View File

@ -10,8 +10,9 @@ import signal as _signal
import fractions as _fractions import fractions as _fractions
from collections import abc as _abc from collections import abc as _abc
from functools import reduce as _reduce, partial as _partial from functools import reduce as _reduce, partial as _partial
from typing import Callable as _Callable, Union as _Union, Iterable as _Iterable, Sequence as _Sequence, Dict as _Dict, \ from typing import Optional as _Optional, Callable as _Callable, Union as _Union, Iterable as _Iterable, \
List as _List, Tuple as _Tuple, Literal as _Literal, Any as _Any, Collection as _Collection, TextIO as _TextIO Sequence as _Sequence, Dict as _Dict, List as _List, Tuple as _Tuple, Literal as _Literal, \
Any as _Any, Collection as _Collection, TextIO as _TextIO
from pathlib import Path as _Path from pathlib import Path as _Path
import numpy as _np import numpy as _np
@ -40,29 +41,33 @@ _colors = {
# Functions # Functions
#################################################################################################### ####################################################################################################
def srepr(msg, def srepr(msg,
glue: str = '\n') -> str: glue: str = '\n',
quote: bool = False) -> str:
r""" r"""
Join items with glue string. Join (quoted) items with glue string.
Parameters Parameters
---------- ----------
msg : object with __repr__ or sequence of objects with __repr__ msg : (sequence of) object with __repr__
Items to join. Items to join.
glue : str, optional glue : str, optional
Glue used for joining operation. Defaults to '\n'. Glue used for joining operation. Defaults to '\n'.
quote : bool, optional
Quote items. Defaults to False.
Returns Returns
------- -------
joined : str joined : str
String representation of the joined items. String representation of the joined and quoted items.
""" """
q = '"' if quote else ''
if (not hasattr(msg, 'strip') and if (not hasattr(msg, 'strip') and
(hasattr(msg, '__getitem__') or (hasattr(msg, '__getitem__') or
hasattr(msg, '__iter__'))): hasattr(msg, '__iter__'))):
return glue.join(str(x) for x in msg) return glue.join(q+str(x)+q for x in msg)
else: else:
return msg if isinstance(msg,str) else repr(msg) return q+(msg if isinstance(msg,str) else repr(msg))+q
def emph(msg) -> str: def emph(msg) -> str:
@ -71,7 +76,7 @@ def emph(msg) -> str:
Parameters Parameters
---------- ----------
msg : object with __repr__ or sequence of objects with __repr__ msg : (sequence of) object with __repr__
Message to format. Message to format.
Returns Returns
@ -88,7 +93,7 @@ def deemph(msg) -> str:
Parameters Parameters
---------- ----------
msg : object with __repr__ or sequence of objects with __repr__ msg : (sequence of) object with __repr__
Message to format. Message to format.
Returns Returns
@ -105,7 +110,7 @@ def warn(msg) -> str:
Parameters Parameters
---------- ----------
msg : object with __repr__ or sequence of objects with __repr__ msg : (sequence of) object with __repr__
Message to format. Message to format.
Returns Returns
@ -122,7 +127,7 @@ def strikeout(msg) -> str:
Parameters Parameters
---------- ----------
msg : object with __repr__ or iterable of objects with __repr__ msg : (iterable of) object with __repr__
Message to format. Message to format.
Returns Returns
@ -136,8 +141,8 @@ def strikeout(msg) -> str:
def run(cmd: str, def run(cmd: str,
wd: str = './', wd: str = './',
env: _Dict[str, str] = None, env: _Optional[_Dict[str, str]] = None,
timeout: int = None) -> _Tuple[str, str]: timeout: _Optional[int] = None) -> _Tuple[str, str]:
""" """
Run a command. Run a command.
@ -210,6 +215,14 @@ def open_text(fname: _FileHandle,
open(_Path(fname).expanduser(),mode,newline=('\n' if mode == 'w' else None)) open(_Path(fname).expanduser(),mode,newline=('\n' if mode == 'w' else None))
def execution_stamp(class_name: str,
function_name: _Optional[str] = None) -> str:
"""Timestamp the execution of a (function within a) class."""
now = _datetime.datetime.now().astimezone().strftime('%Y-%m-%d %H:%M:%S%z')
_function_name = '' if function_name is None else f'.{function_name}'
return f'damask.{class_name}{_function_name} v{_version} ({now})'
def natural_sort(key: str) -> _List[_Union[int, str]]: def natural_sort(key: str) -> _List[_Union[int, str]]:
""" """
Natural sort. Natural sort.
@ -226,7 +239,7 @@ def natural_sort(key: str) -> _List[_Union[int, str]]:
def show_progress(iterable: _Iterable, def show_progress(iterable: _Iterable,
N_iter: int = None, N_iter: _Optional[int] = None,
prefix: str = '', prefix: str = '',
bar_length: int = 50) -> _Any: bar_length: int = 50) -> _Any:
""" """
@ -403,36 +416,35 @@ def project_equal_area(vector: _np.ndarray,
return _np.roll(_np.block([v[...,:2]/_np.sqrt(1.0+_np.abs(v[...,2:3])),_np.zeros_like(v[...,2:3])]), return _np.roll(_np.block([v[...,:2]/_np.sqrt(1.0+_np.abs(v[...,2:3])),_np.zeros_like(v[...,2:3])]),
-shift if keepdims else 0,axis=-1)[...,:3 if keepdims else 2] -shift if keepdims else 0,axis=-1)[...,:3 if keepdims else 2]
def execution_stamp(class_name: str,
function_name: str = None) -> str:
"""Timestamp the execution of a (function within a) class."""
now = _datetime.datetime.now().astimezone().strftime('%Y-%m-%d %H:%M:%S%z')
_function_name = '' if function_name is None else f'.{function_name}'
return f'damask.{class_name}{_function_name} v{_version} ({now})'
def hybrid_IA(dist: _FloatSequence,
def hybrid_IA(dist: _np.ndarray,
N: int, N: int,
rng_seed: _NumpyRngSeed = None) -> _np.ndarray: rng_seed: _Optional[_NumpyRngSeed] = None) -> _np.ndarray:
""" """
Hybrid integer approximation. Hybrid integer approximation.
Parameters Parameters
---------- ----------
dist : numpy.ndarray dist : numpy.ndarray
Distribution to be approximated Distribution to be approximated.
N : int N : int
Number of samples to draw. Number of samples to draw.
rng_seed : {None, int, array_like[ints], SeedSequence, BitGenerator, Generator}, optional rng_seed : {None, int, array_like[ints], SeedSequence, BitGenerator, Generator}, optional
A seed to initialize the BitGenerator. Defaults to None. A seed to initialize the BitGenerator. Defaults to None.
If None, then fresh, unpredictable entropy will be pulled from the OS. If None, then fresh, unpredictable entropy will be pulled from the OS.
Returns
-------
hist : numpy.ndarray, shape (N)
Integer approximation of the distribution.
""" """
N_opt_samples,N_inv_samples = (max(_np.count_nonzero(dist),N),0) # random subsampling if too little samples requested N_opt_samples = max(_np.count_nonzero(dist),N) # random subsampling if too little samples requested
N_inv_samples = 0
scale_,scale,inc_factor = (0.0,float(N_opt_samples),1.0) scale_,scale,inc_factor = (0.0,float(N_opt_samples),1.0)
while (not _np.isclose(scale, scale_)) and (N_inv_samples != N_opt_samples): while (not _np.isclose(scale, scale_)) and (N_inv_samples != N_opt_samples):
repeats = _np.rint(scale*dist).astype(_np.int64) repeats = _np.rint(scale*_np.array(dist)).astype(_np.int64)
N_inv_samples = _np.sum(repeats) N_inv_samples = _np.sum(repeats)
scale_,scale,inc_factor = (scale,scale+inc_factor*0.5*(scale - scale_), inc_factor*2.0) \ scale_,scale,inc_factor = (scale,scale+inc_factor*0.5*(scale - scale_), inc_factor*2.0) \
if N_inv_samples < N_opt_samples else \ if N_inv_samples < N_opt_samples else \
@ -528,37 +540,82 @@ def shapeblender(a: _Tuple[int, ...],
return a + b[i:] return a + b[i:]
def extend_docstring(extra_docstring: str) -> _Callable: def _docstringer(docstring: _Union[str, _Callable],
extra_parameters: _Optional[str] = None,
# extra_examples: _Optional[str] = None,
# extra_notes: _Optional[str] = None,
return_type: _Union[None, str, _Callable] = None) -> str:
""" """
Decorator: Append to function's docstring. Extend a docstring.
Parameters Parameters
---------- ----------
extra_docstring : str docstring : str or callable, optional
Docstring to append. Docstring (of callable) to extend.
extra_parameters : str, optional
Additional information to append to Parameters section.
return_type : str or callable, optional
Type of return variable.
""" """
def _decorator(func): docstring_ = str( docstring if isinstance(docstring,str)
func.__doc__ += extra_docstring else docstring.__doc__ if hasattr(docstring,'__doc__')
return func else '')
return _decorator d = dict(Parameters=extra_parameters,
# Examples=extra_examples,
# Notes=extra_notes,
)
for key,extra in [(k,v) for (k,v) in d.items() if v is not None]:
if not (heading := _re.search(fr'^([ ]*){key}\s*\n\1{"-"*len(key)}',
docstring_,flags=_re.MULTILINE)):
raise RuntimeError(f"Docstring {docstring_} lacks a correctly formatted {key} section to insert values into")
content = [line for line in extra.split('\n') if line.strip()]
indent = len(heading.group(1))
shift = min([len(line)-len(line.lstrip(' '))-indent for line in content])
extra = '\n'.join([(line[shift:] if shift > 0 else
f'{" "*-shift}{line}') for line in content])
docstring_ = _re.sub(fr'(^([ ]*){key}\s*\n\2{"-"*len(key)}[\n ]*[A-Za-z0-9_ ]*: ([^\n]+\n)*)',
fr'\1{extra}\n',
docstring_,flags=_re.MULTILINE)
if return_type is None:
return docstring_
else:
if isinstance(return_type,str):
return_type_ = return_type
else:
return_class = return_type.__annotations__.get('return','')
return_type_ = (_sys.modules[return_type.__module__].__name__.split('.')[0]
+'.'
+(return_class.__name__ if not isinstance(return_class,str) else return_class)
)
def extended_docstring(f: _Callable, return _re.sub(r'(^([ ]*)Returns\s*\n\2-------\s*\n[ ]*[A-Za-z0-9_ ]*: )(.*)\n',
extra_docstring: str) -> _Callable: fr'\1{return_type_}\n',
docstring_,flags=_re.MULTILINE)
def extend_docstring(docstring: _Union[None, str, _Callable] = None,
extra_parameters: _Optional[str] = None) -> _Callable:
""" """
Decorator: Combine another function's docstring with a given docstring. Decorator: Extend the function's docstring.
Parameters Parameters
---------- ----------
f : function docstring : str or callable, optional
Function of which the docstring is taken. Docstring to extend. Defaults to that of decorated function.
extra_docstring : str extra_parameters : str, optional
Docstring to append. Additional information to append to Parameters section.
Notes
-----
Return type will become own type if docstring is callable.
""" """
def _decorator(func): def _decorator(func):
func.__doc__ = f.__doc__ + extra_docstring func.__doc__ = _docstringer(func.__doc__ if docstring is None else docstring,
extra_parameters,
func if isinstance(docstring,_Callable) else None,
)
return func return func
return _decorator return _decorator
@ -622,8 +679,8 @@ def DREAM3D_cell_data_group(fname: _Union[str, _Path]) -> str:
def Bravais_to_Miller(*, def Bravais_to_Miller(*,
uvtw: _np.ndarray = None, uvtw: _Optional[_np.ndarray] = None,
hkil: _np.ndarray = None) -> _np.ndarray: hkil: _Optional[_np.ndarray] = None) -> _np.ndarray:
""" """
Transform 4 MillerBravais indices to 3 Miller indices of crystal direction [uvw] or plane normal (hkl). Transform 4 MillerBravais indices to 3 Miller indices of crystal direction [uvw] or plane normal (hkl).
@ -649,10 +706,9 @@ def Bravais_to_Miller(*,
[0,0,0,1]])) [0,0,0,1]]))
return _np.einsum('il,...l',basis,axis) return _np.einsum('il,...l',basis,axis)
def Miller_to_Bravais(*, def Miller_to_Bravais(*,
uvw: _np.ndarray = None, uvw: _Optional[_np.ndarray] = None,
hkl: _np.ndarray = None) -> _np.ndarray: hkl: _Optional[_np.ndarray] = None) -> _np.ndarray:
""" """
Transform 3 Miller indices to 4 MillerBravais indices of crystal direction [uvtw] or plane normal (hkil). Transform 3 Miller indices to 4 MillerBravais indices of crystal direction [uvtw] or plane normal (hkil).
@ -706,7 +762,6 @@ def dict_prune(d: _Dict) -> _Dict:
return new return new
def dict_flatten(d: _Dict) -> _Dict: def dict_flatten(d: _Dict) -> _Dict:
""" """
Recursively remove keys of single-entry dictionaries. Recursively remove keys of single-entry dictionaries.
@ -738,7 +793,7 @@ def tail_repack(extended: _Union[str, _Sequence[str]],
Parameters Parameters
---------- ----------
extended : str or list of str extended : (sequence of) str
Extended string list with potentially autosplitted tailing string relative to `existing`. Extended string list with potentially autosplitted tailing string relative to `existing`.
existing : list of str existing : list of str
Base string list. Base string list.
@ -756,9 +811,9 @@ def tail_repack(extended: _Union[str, _Sequence[str]],
['a','new','shiny','e','n','t','r','y'] ['a','new','shiny','e','n','t','r','y']
""" """
return [extended] if isinstance(extended,str) else existing + \ new = extended[len(existing):]
([''.join(extended[len(existing):])] if _np.prod([len(i) for i in extended[len(existing):]]) == 1 else return [extended] if isinstance(extended,str) else \
list(extended[len(existing):])) existing + list([''.join(new)] if _np.prod([len(i) for i in new]) == 1 else new)
def aslist(arg: _Union[_IntCollection, int, None]) -> _List: def aslist(arg: _Union[_IntCollection, int, None]) -> _List:
@ -767,7 +822,7 @@ def aslist(arg: _Union[_IntCollection, int, None]) -> _List:
Parameters Parameters
---------- ----------
arg : int or collection of int or None arg : (collection of) int or None
Entity to transform into list. Entity to transform into list.
Returns Returns

View File

@ -1,4 +1,4 @@
phase: {'1': t.b.d., '2': t.b.d.} phase: {'1': null, '2': null}
homogenization: homogenization:
direct: {N_constituents: 1} direct: {N_constituents: 1}

View File

@ -65,17 +65,6 @@ class TestConfigMaterial:
del material_config['material'][0]['homogenization'] del material_config['material'][0]['homogenization']
assert not material_config.is_complete assert not material_config.is_complete
def test_incomplete_homogenization_N_constituents(self,ref_path):
material_config = ConfigMaterial.load(ref_path/'material.yaml')
for h in material_config['homogenization'].keys():
del material_config['homogenization'][h]['N_constituents']
assert not material_config.is_complete
def test_incomplete_phase_lattice(self,ref_path):
material_config = ConfigMaterial.load(ref_path/'material.yaml')
del material_config['phase']['Aluminum']['lattice']
assert not material_config.is_complete
def test_incomplete_wrong_phase(self,ref_path): def test_incomplete_wrong_phase(self,ref_path):
material_config = ConfigMaterial.load(ref_path/'material.yaml') material_config = ConfigMaterial.load(ref_path/'material.yaml')
new = material_config.material_rename_phase({'Steel':'FeNbC'}) new = material_config.material_rename_phase({'Steel':'FeNbC'})
@ -86,6 +75,16 @@ class TestConfigMaterial:
new = material_config.material_rename_homogenization({'Taylor':'isostrain'}) new = material_config.material_rename_homogenization({'Taylor':'isostrain'})
assert not new.is_complete assert not new.is_complete
def test_empty_phase(self,ref_path):
material_config = ConfigMaterial.load(ref_path/'material.yaml')
material_config['phase'] = None
assert not material_config.is_complete
def test_empty_homogenization(self,ref_path):
material_config = ConfigMaterial.load(ref_path/'material.yaml')
material_config['homogenization'] = None
assert not material_config.is_complete
def test_from_table(self): def test_from_table(self):
N = np.random.randint(3,10) N = np.random.randint(3,10)
a = np.vstack((np.hstack((np.arange(N),np.arange(N)[::-1])), a = np.vstack((np.hstack((np.arange(N),np.arange(N)[::-1])),
@ -98,6 +97,15 @@ class TestConfigMaterial:
for i,m in enumerate(c['material']): for i,m in enumerate(c['material']):
assert m['homogenization'] == 1 and (m['constituents'][0]['O'] == [1,0,1,1]).all() assert m['homogenization'] == 1 and (m['constituents'][0]['O'] == [1,0,1,1]).all()
def test_updated_dicts(self,ref_path):
m1 = ConfigMaterial().material_add(phase=['Aluminum'],O=[1.0,0.0,0.0,0.0],homogenization='SX')
m2 = ConfigMaterial.load(ref_path/'material.yaml')
for k in m2['phase']:
m2 = m2.material_add(phase=[k],O=[1.0,0.0,0.0,0.0],homogenization='SX')
assert not m2['phase'].get(k) is None
assert m1['phase'].get('Aluminum') is None
assert m1['homogenization'].get('SX') is None
def test_from_table_with_constant(self): def test_from_table_with_constant(self):
N = np.random.randint(3,10) N = np.random.randint(3,10)
a = np.vstack((np.hstack((np.arange(N),np.arange(N)[::-1])), a = np.vstack((np.hstack((np.arange(N),np.arange(N)[::-1])),

View File

@ -708,6 +708,7 @@ class TestRotation:
@pytest.mark.parametrize('degrees',[True,False]) @pytest.mark.parametrize('degrees',[True,False])
def test_axis_angle(self,set_of_rotations,degrees,normalize,P): def test_axis_angle(self,set_of_rotations,degrees,normalize,P):
c = np.array([P*-1,P*-1,P*-1,1.]) c = np.array([P*-1,P*-1,P*-1,1.])
c[:3] *= 0.9 if normalize else 1.0
for rot in set_of_rotations: for rot in set_of_rotations:
m = rot.as_Euler_angles() m = rot.as_Euler_angles()
o = Rotation.from_axis_angle(rot.as_axis_angle(degrees)*c,degrees,normalize,P).as_Euler_angles() o = Rotation.from_axis_angle(rot.as_axis_angle(degrees)*c,degrees,normalize,P).as_Euler_angles()
@ -730,16 +731,30 @@ class TestRotation:
assert ok and np.isclose(np.linalg.norm(o[:3]),1.0) \ assert ok and np.isclose(np.linalg.norm(o[:3]),1.0) \
and o[3]<=np.pi+1.e-9, f'{m},{o},{rot.as_quaternion()}' and o[3]<=np.pi+1.e-9, f'{m},{o},{rot.as_quaternion()}'
def test_parallel(self,set_of_rotations):
a = np.array([[1.0,0.0,0.0],
[0.0,1.0,0.0]])
for rot in set_of_rotations:
assert rot.allclose(Rotation.from_parallel(a,rot.broadcast_to((2,))@a))
@pytest.mark.parametrize('P',[1,-1]) @pytest.mark.parametrize('P',[1,-1])
@pytest.mark.parametrize('normalize',[True,False]) @pytest.mark.parametrize('normalize',[True,False])
def test_Rodrigues(self,set_of_rotations,normalize,P): def test_Rodrigues(self,set_of_rotations,normalize,P):
c = np.array([P*-1,P*-1,P*-1,1.]) c = np.array([P*-1,P*-1,P*-1,1.])
c[:3] *= 0.9 if normalize else 1.0
for rot in set_of_rotations: for rot in set_of_rotations:
m = rot.as_matrix() m = rot.as_matrix()
o = Rotation.from_Rodrigues_vector(rot.as_Rodrigues_vector()*c,normalize,P).as_matrix() o = Rotation.from_Rodrigues_vector(rot.as_Rodrigues_vector()*c,normalize,P).as_matrix()
ok = np.allclose(m,o,atol=atol) ok = np.allclose(m,o,atol=atol)
assert ok and np.isclose(np.linalg.det(o),1.0), f'{m},{o}' assert ok and np.isclose(np.linalg.det(o),1.0), f'{m},{o}'
def test_Rodrigues_compact(self,set_of_rotations):
for rot in set_of_rotations:
c = rot.as_Rodrigues_vector(compact=True)
r = rot.as_Rodrigues_vector(compact=False)
assert np.allclose(r[:3]*r[3], c, equal_nan=True)
@pytest.mark.parametrize('P',[1,-1]) @pytest.mark.parametrize('P',[1,-1])
def test_homochoric(self,set_of_rotations,P): def test_homochoric(self,set_of_rotations,P):
cutoff = np.tan(np.pi*.5*(1.-1e-4)) cutoff = np.tan(np.pi*.5*(1.-1e-4))
@ -760,11 +775,12 @@ class TestRotation:
@pytest.mark.parametrize('P',[1,-1]) @pytest.mark.parametrize('P',[1,-1])
@pytest.mark.parametrize('accept_homomorph',[True,False]) @pytest.mark.parametrize('accept_homomorph',[True,False])
def test_quaternion(self,set_of_rotations,P,accept_homomorph): @pytest.mark.parametrize('normalize',[True,False])
c = np.array([1,P*-1,P*-1,P*-1]) * (-1 if accept_homomorph else 1) def test_quaternion(self,set_of_rotations,P,accept_homomorph,normalize):
c = np.array([1,P*-1,P*-1,P*-1]) * (-1 if accept_homomorph else 1) * (0.9 if normalize else 1.0)
for rot in set_of_rotations: for rot in set_of_rotations:
m = rot.as_cubochoric() m = rot.as_cubochoric()
o = Rotation.from_quaternion(rot.as_quaternion()*c,accept_homomorph,P).as_cubochoric() o = Rotation.from_quaternion(rot.as_quaternion()*c,accept_homomorph,normalize,P).as_cubochoric()
ok = np.allclose(m,o,atol=atol) ok = np.allclose(m,o,atol=atol)
if np.count_nonzero(np.isclose(np.abs(o),np.pi**(2./3.)*.5)): if np.count_nonzero(np.isclose(np.abs(o),np.pi**(2./3.)*.5)):
ok |= np.allclose(m*-1.,o,atol=atol) ok |= np.allclose(m*-1.,o,atol=atol)
@ -889,6 +905,15 @@ class TestRotation:
with pytest.raises(ValueError): with pytest.raises(ValueError):
fr(eval(f'R.{to}()'),P=-30) fr(eval(f'R.{to}()'),P=-30)
def test_invalid_multiplication(self):
rot = Rotation.from_random()
with pytest.raises(TypeError):
rot@Rotation.from_random()
with pytest.raises(TypeError):
rot@[1,2,3,4]
@pytest.mark.parametrize('shape',[None,(3,),(4,2)]) @pytest.mark.parametrize('shape',[None,(3,),(4,2)])
def test_broadcast(self,shape): def test_broadcast(self,shape):
rot = Rotation.from_random(shape) rot = Rotation.from_random(shape)
@ -902,6 +927,7 @@ class TestRotation:
@pytest.mark.parametrize('function,invalid',[(Rotation.from_quaternion, np.array([-1,0,0,0])), @pytest.mark.parametrize('function,invalid',[(Rotation.from_quaternion, np.array([-1,0,0,0])),
(Rotation.from_quaternion, np.array([1,1,1,0])), (Rotation.from_quaternion, np.array([1,1,1,0])),
(Rotation.from_Euler_angles, np.array([1,4,0])), (Rotation.from_Euler_angles, np.array([1,4,0])),
(Rotation.from_Euler_angles, np.array([-1,0,0])),
(Rotation.from_axis_angle, np.array([1,0,0,4])), (Rotation.from_axis_angle, np.array([1,0,0,4])),
(Rotation.from_axis_angle, np.array([1,1,0,1])), (Rotation.from_axis_angle, np.array([1,1,0,1])),
(Rotation.from_matrix, np.random.rand(3,3)), (Rotation.from_matrix, np.random.rand(3,3)),
@ -909,7 +935,8 @@ class TestRotation:
(Rotation.from_Rodrigues_vector, np.array([1,0,0,-1])), (Rotation.from_Rodrigues_vector, np.array([1,0,0,-1])),
(Rotation.from_Rodrigues_vector, np.array([1,1,0,1])), (Rotation.from_Rodrigues_vector, np.array([1,1,0,1])),
(Rotation.from_homochoric, np.array([2,2,2])), (Rotation.from_homochoric, np.array([2,2,2])),
(Rotation.from_cubochoric, np.array([1.1,0,0])) ]) (Rotation.from_cubochoric, np.array([1.1,0,0])),
])
def test_invalid_value(self,function,invalid): def test_invalid_value(self,function,invalid):
with pytest.raises(ValueError): with pytest.raises(ValueError):
function(invalid) function(invalid)

View File

@ -8,7 +8,6 @@ import h5py
from damask import util from damask import util
class TestUtil: class TestUtil:
@pytest.mark.xfail(sys.platform == 'win32', reason='echo is not a Windows command') @pytest.mark.xfail(sys.platform == 'win32', reason='echo is not a Windows command')
@ -44,7 +43,7 @@ class TestUtil:
@pytest.mark.parametrize('rv',[stats.rayleigh(),stats.weibull_min(1.2),stats.halfnorm(),stats.pareto(2.62)]) @pytest.mark.parametrize('rv',[stats.rayleigh(),stats.weibull_min(1.2),stats.halfnorm(),stats.pareto(2.62)])
def test_hybridIA(self,rv): def test_hybridIA_distribution(self,rv):
bins = np.linspace(0,10,100000) bins = np.linspace(0,10,100000)
centers = (bins[1:]+bins[:-1])/2 centers = (bins[1:]+bins[:-1])/2
N_samples = bins.shape[0]-1000 N_samples = bins.shape[0]-1000
@ -53,6 +52,21 @@ class TestUtil:
dist_sampled = np.histogram(centers[selected],bins)[0]/N_samples*np.sum(dist) dist_sampled = np.histogram(centers[selected],bins)[0]/N_samples*np.sum(dist)
assert np.sqrt(((dist - dist_sampled) ** 2).mean()) < .025 and selected.shape[0]==N_samples assert np.sqrt(((dist - dist_sampled) ** 2).mean()) < .025 and selected.shape[0]==N_samples
def test_hybridIA_constant(self):
N_bins = np.random.randint(20,400)
m = np.random.randint(1,20)
N_samples = m * N_bins
dist = np.ones(N_bins)*np.random.rand()
assert np.all(np.sort(util.hybrid_IA(dist,N_samples))==np.arange(N_samples).astype(int)//m)
def test_hybridIA_linear(self):
N_points = np.random.randint(10,200)
m = np.random.randint(1,20)
dist = np.arange(N_points)
N_samples = m * np.sum(dist)
assert np.all(np.bincount(util.hybrid_IA(dist*np.random.rand(),N_samples)) == dist*m)
@pytest.mark.parametrize('point,direction,normalize,keepdims,answer', @pytest.mark.parametrize('point,direction,normalize,keepdims,answer',
[ [
([1,0,0],'z',False,True, [1,0,0]), ([1,0,0],'z',False,True, [1,0,0]),
@ -208,3 +222,128 @@ class TestUtil:
@pytest.mark.parametrize('kw_Miller,kw_Bravais',[('uvw','uvtw'),('hkl','hkil')]) @pytest.mark.parametrize('kw_Miller,kw_Bravais',[('uvw','uvtw'),('hkl','hkil')])
def test_Bravais_Miller_Bravais(self,vector,kw_Miller,kw_Bravais): def test_Bravais_Miller_Bravais(self,vector,kw_Miller,kw_Bravais):
assert np.all(vector == util.Miller_to_Bravais(**{kw_Miller:util.Bravais_to_Miller(**{kw_Bravais:vector})})) assert np.all(vector == util.Miller_to_Bravais(**{kw_Miller:util.Bravais_to_Miller(**{kw_Bravais:vector})}))
@pytest.mark.parametrize('extra_parameters',["""
p2 : str, optional
p2 description 1
p2 description 2
""",
"""
p2 : str, optional
p2 description 1
p2 description 2
""",
"""
p2 : str, optional
p2 description 1
p2 description 2
"""])
@pytest.mark.parametrize('invalid_docstring',["""
Function description
Parameters ----------
p0 : numpy.ndarray, shape (...,4)
p0 description 1
p0 description 2
p1 : int, optional
p1 description
Remaining description
""",
"""
Function description
Parameters
----------
p0 : numpy.ndarray, shape (...,4)
p0 description 1
p0 description 2
p1 : int, optional
p1 description
Remaining description
""",])
def test_extend_docstring_parameters(self,extra_parameters,invalid_docstring):
test_docstring = """
Function description
Parameters
----------
p0 : numpy.ndarray, shape (...,4)
p0 description 1
p0 description 2
p1 : int, optional
p1 description
Remaining description
"""
invalid_docstring = """
Function description
Parameters ----------
p0 : numpy.ndarray, shape (...,4)
p0 description 1
p0 description 2
p1 : int, optional
p1 description
Remaining description
"""
expected = """
Function description
Parameters
----------
p0 : numpy.ndarray, shape (...,4)
p0 description 1
p0 description 2
p1 : int, optional
p1 description
p2 : str, optional
p2 description 1
p2 description 2
Remaining description
""".split("\n")
assert expected == util._docstringer(test_docstring,extra_parameters).split('\n')
with pytest.raises(RuntimeError):
util._docstringer(invalid_docstring,extra_parameters)
def test_replace_docstring_return_type(self):
class TestClassOriginal:
pass
def original_func() -> TestClassOriginal:
pass
class TestClassDecorated:
def decorated_func_bound(self) -> 'TestClassDecorated':
pass
def decorated_func() -> TestClassDecorated:
pass
original_func.__doc__ = """
Function description/Parameters
Returns
-------
Return value : test_util.TestClassOriginal
Remaining description
"""
expected = """
Function description/Parameters
Returns
-------
Return value : test_util.TestClassDecorated
Remaining description
"""
assert expected == util._docstringer(original_func,return_type=decorated_func)
assert expected == util._docstringer(original_func,return_type=TestClassDecorated.decorated_func_bound)

View File

@ -413,6 +413,8 @@ subroutine uedinc(inc,incsub)
use discretization_Marc use discretization_Marc
implicit none(type,external) implicit none(type,external)
external :: nodvar
integer(pI64), intent(in) :: inc, incsub integer(pI64), intent(in) :: inc, incsub
integer :: n, nqncomp, nqdatatype integer :: n, nqncomp, nqdatatype

466
src/Marc/include/concom2022.2 vendored Normal file
View File

@ -0,0 +1,466 @@
! common block definition file taken from respective MSC.Marc release and reformated to free format
!***********************************************************************
!
! File: concom.cmn
!
! MSC.Marc include file
!
integer &
iacous, iasmbl, iautth, ibear, icompl, iconj, icreep, ideva, idyn, idynt,&
ielas, ielcma, ielect, iform, ifour, iharm, ihcps, iheat, iheatt, ihresp,&
ijoule, ilem, ilnmom, iloren, inc, incext, incsub, ipass, iplres, ipois,&
ipoist, irpflo, ismall, ismalt, isoil, ispect, ispnow, istore, iswep, ithcrp,&
itherm, iupblg, iupdat, jacflg, jel, jparks, largst, lfond, loadup, loaduq,&
lodcor, lovl, lsub, magnet, ncycle, newtnt, newton, noshr, linear, ivscpl,&
icrpim, iradrt, ipshft, itshr, iangin, iupmdr, iconjf, jincfl, jpermg, jhour,&
isolvr, jritz, jtable, jshell, jdoubl, jform, jcentr, imini, kautth, iautof,&
ibukty, iassum, icnstd, icnstt, kmakmas, imethvp, iradrte, iradrtp, iupdate, iupdatp,&
ncycnt, marmen , idynme, ihavca, ispf, kmini, imixex, largtt, kdoela, iautofg,&
ipshftp, idntrc, ipore, jtablm, jtablc, isnecma, itrnspo, imsdif, jtrnspo, mcnear,&
imech, imecht, ielcmat, ielectt, magnett, imsdift, noplas, jtabls, jactch, jtablth,&
kgmsto , jpzo, ifricsh, iremkin, iremfor, ishearp, jspf, machining, jlshell, icompsol,&
iupblgfo, jcondir, nstcrp, nactive, ipassref, nstspnt, ibeart, icheckmpc, noline, icuring,&
ishrink, ioffsflg, isetoff, ioffsetm,iharmt, inc_incdat, iautspc, ibrake, icbush, istream_input,&
iprsinp, ivlsinp, ifirst_time,ipin_m, jgnstr_glb, imarc_return,iqvcinp, nqvceid, istpnx, imicro1,&
iaxisymm, jbreakglue,iglstif, jfastasm,iwear, iwearcf, imixmeth, ielcmadyn, idinout, igena_meth,&
magf_meth, non_assumed, iredoboudry, ioffsz0,icomplt, mesh_dual, iactrp, mgnewton, iusedens,igsigd0,&
iaem, icosim, inodels, nlharm, iampini, iphasetr, inonlcl, inonlct, iforminp,ispecerror,&
icsprg, imol, imolt, idatafit,iharmpar, inclcase, imultifreq,init_elas, ifatig, iftgmat,&
nchybrid, ibuckle, iexpande
dimension :: ideva(60)
integer num_concom
parameter(num_concom=263)
common/marc_concom/&
iacous, iasmbl, iautth, ibear, icompl, iconj, icreep, ideva, idyn, idynt,&
ielas, ielcma, ielect, iform, ifour, iharm, ihcps, iheat, iheatt, ihresp,&
ijoule, ilem, ilnmom, iloren, inc, incext, incsub, ipass, iplres, ipois,&
ipoist, irpflo, ismall, ismalt, isoil, ispect, ispnow, istore, iswep, ithcrp,&
itherm, iupblg, iupdat, jacflg, jel, jparks, largst, lfond, loadup, loaduq,&
lodcor, lovl, lsub, magnet, ncycle, newtnt, newton, noshr, linear, ivscpl,&
icrpim, iradrt, ipshft, itshr, iangin, iupmdr, iconjf, jincfl, jpermg, jhour,&
isolvr, jritz, jtable, jshell, jdoubl, jform, jcentr, imini, kautth, iautof,&
ibukty, iassum, icnstd, icnstt, kmakmas, imethvp, iradrte, iradrtp, iupdate, iupdatp,&
ncycnt, marmen, idynme, ihavca, ispf, kmini, imixex, largtt, kdoela, iautofg,&
ipshftp, idntrc, ipore, jtablm, jtablc, isnecma, itrnspo, imsdif, jtrnspo, mcnear,&
imech, imecht, ielcmat, ielectt, magnett, imsdift, noplas, jtabls, jactch, jtablth,&
kgmsto , jpzo, ifricsh, iremkin, iremfor, ishearp, jspf, machining, jlshell, icompsol,&
iupblgfo, jcondir, nstcrp, nactive, ipassref, nstspnt, ibeart, icheckmpc, noline, icuring,&
ishrink, ioffsflg, isetoff, ioffsetm,iharmt, inc_incdat, iautspc, ibrake, icbush, istream_input,&
iprsinp, ivlsinp, ifirst_time,ipin_m, jgnstr_glb, imarc_return,iqvcinp, nqvceid, istpnx, imicro1,&
iaxisymm, jbreakglue,iglstif, jfastasm,iwear, iwearcf, imixmeth, ielcmadyn, idinout, igena_meth,&
magf_meth, non_assumed, iredoboudry, ioffsz0,icomplt, mesh_dual, iactrp, mgnewton, iusedens,igsigd0,&
iaem, icosim, inodels, nlharm, iampini, iphasetr, inonlcl, inonlct, iforminp,ispecerror,&
icsprg, imol, imolt, idatafit,iharmpar, inclcase, imultifreq,init_elas, ifatig, iftgmat,&
nchybrid, ibuckle, iexpande
!
! comments of variables:
!
! iacous Control flag for acoustic analysis. Input data.
! iacous=1 modal acoustic analysis.
! iacous=2 harmonic acoustic-structural analysis.
! iasmbl Control flag to indicate that operator matrix should be
! recalculated.
! iautth Control flag for AUTO THERM option.
! ibear Control flag for bearing analysis. Input data.
! icompl Control variable to indicate that a complex analysis is
! being performed. Either a Harmonic analysis with damping,
! or a harmonic electro-magnetic analysis. Input data.
! iconj Flag for EBE conjugate gradient solver (=solver 1, retired)
! Also used for VKI iterative solver.
! icreep Control flag for creep analysis. Input data.
! ideva(60) - debug print out flag
! 1 print element stiffness matrices, mass matrix
! 2 output matrices used in tying
! 3 force the solution of a nonpositive definite matrix
! 4 print info of connections to each node
! 5 info of gap convergence, internal heat generated, contact
! touching and separation
! 6 nodal value array during rezoning
! 7 tying info in CONRAD GAP option, fluid element numbers in
! CHANNEL option
! 8 output incremental displacements in local coord. system
! 9 latent heat output
! 10 stress-strain in local coord. system
! 11 additional info on interlaminar stress
! 12 output right hand side and solution vector
! 13 info of CPU resources used and memory available on NT
! 14 info of mesh adaption process, 2D outline information
! info of penetration checking for remeshing
! save .fem files after afmesh3d meshing
! print local adaptivity info
! 15 surface energy balance flag
! 16 print info regarding pyrolysis
! 17 print info of "streamline topology"
! 18 print mesh data changes after remeshing
! 19 print material flow stress data read in from *.mat file
! if unit flag is on, print out flow stress after conversion
! 20 print information on table input
! 21 print out information regarding kinematic boundary conditions
! 22 print out information regarding dist loads, point loads, film
! and foundations
! 23 print out information about automatic domain decomposition
! 24 print out iteration information in SuperForm status report file
! 25 print out information for ablation
! 26 print out information for films - Table input
! 27 print out the tying forces
! 28 print out for CASI solver, convection,
! 29 DDM single file debug printout
! 30 print out cavity debug info
! 31 print out welding related info
! 32 prints categorized DDM memory usage
! 33 print out the cutting info regarding machining feature
! 34 print out the list of quantities which can be defined via a table
! and for each quantity the supported independent variables
! 35 print out detailed coupling region info
! 36 print out solver debug info level 1 (Least Detailed)
! 37 print out solver debug info level 1 (Medium Detailed)
! 38 print out solver debug info level 1 (Very Detailed)
! 39 print detailed memory allocation info
! 40 print out marc-adams debug info
! 41 output rezone mapping post file for debugging
! 42 output post file after calling oprofos() for debugging
! 43 debug printout for vcct
! 44 debug printout for progressive failure
! 45 print out automatically generated midside node coordinates (arecrd)
! 46 print out message about routine and location, where the ibort is raised (ibort_inc)
! 47 print out summary message of element variables on a
! group-basis after all the automatic changes have been
! made (em_ellibp)
! 48 Automatically generate check results based on max and min vals.
! These vals are stored in the checkr file, which is inserted
! into the *dat file by the generate_check_results script from /marc/tools
! 49 Automatically generate check results based on the real calculated values
! at the sppecified check result locations.
! These vals are stored in the checkr file, which is inserted
! into the *dat file by the update_check_results script from /marc/tools
! 50 generate a file containing the resistance or capacity matrix;
! this file can be used to compare results with a reference file
! 51 print out detailed information for segment-to-segment contact
! 52 print out detailed relative displacement information
! for uniaxial sliding contact
! 53 print out detailed sliding direction information for
! uniaxial sliding contact
! 54 print out detailed information for edges attached to a curve
! 55 print information related to viscoelasticity calculations
! 56 print out detailed information for element coloring for multithreading
! 57 print out extra overheads due to multi-threading.
! These overhead includes (i) time and (ii) memory.
! The memory report will be summed over all the children.
! 58 debug output for ELSTO usage
! 59 print out contact body forces and nodes in contact
!
! idyn Control flag for dynamics. Input data.
! 1 = eigenvalue extraction and / or modal superposition
! 2 = Newmark Beta and Single Step Houbolt (ssh with idynme=1)
! 3 = Houbolt
! 4 = Central difference
! 5 = Newer central difference
! idynt Copy of idyn at begining of increment
! ielas Control flag for ELASTIC analysis. Input data.
! Set by user or automatically turned on by Fourier option.
! Implies that each load case is treated separately.
! In Adaptive meshing analysis , forces re-analysis until
! convergence obtained.
! Also seriously misused to indicate no convergence.
! = 1 elastic option with fourier analysis
! = 2 elastic option without fourier analysis
! =-1 no convergence in recycles or max # increments reached
! Set to 1 if ELASTIC or SUBSTRUC parameter cards are used,
! or if fourier option is used.
! Then set to 2 if not fourier analysis.
! ielcma Control flag for electromagnetic analysis. Input data.
! ielcma = 1 Harmonic formulation
! ielcma = 2 Transient formulation
! ielect Control flag for electrostatic option. Input data.
! iform Control flag indicating that contact will be performed.
! ifour Control flag for Fourier analysis.
! 0 = Odd and even terms.
! 1 = symmetric (cosine) terms
! 2 = antisymmetric (sine) terms.
! iharm Control flag to indicate that a harmonic analysis will
! be performed. May change between passes.
! ihcps Control flag for coupled thermal - stress analysis.
! iheat Control flag for heat transfer analysis. Input data.
! iheatt Permanent control flag for heat transfer analysis.
! Note in coupled analysis iheatt will remain as one,
! but iheat will be zero in stress pass.
! ihresp Control flag to indicate to perform a harmonic subincrement.
! ijoule Control flag for Joule heating.
! ilem Control flag to determin which vector is to be transformed.
! Control flag to see where one is:
! ilem = 1 - elem.f
! ilem = 2 - initst.f
! ilem = 3 - pressr.f
! ilem = 3 - fstif.f
! ilem = 4 - jflux.f
! ilem = 4 - strass.f
! ilem = 5 - mass.f
! ilem = 5 - osolty.f
! ilnmom Control flag for soil - pore pressure calculation. Input data.
! ilnmom = 0 - perform only pore pressure calculation.
! = 1 - couples pore pressure - displacement analysis
! iloren Control flag for DeLorenzi J-Integral evaluation. Input data.
! inc Increment number.
! incext Control flag indicating that currently working on a
! subincrement.
! Could be due to harmonics , damping component (bearing),
! stiffness component (bearing), auto therm creep or
! old viscoplaticity
! incsub Sub-increment number.
! inonlcl control flag for nonlocal pass
! inonlct permanent control flag for nonlocal pass
! ipass Control flag for which part of coupled analysis.
! ipass = -1 - reset to base values
! ipass = 0 - do nothing
! ipass = 1 - stress part
! ipass = 2 - heat transfer part
! 3 - fluid pass
! 4 - joule heating pass
! 5 - pore pressure pass
! 6 - electrostatic pass
! 7 - magnetostatic pass
! 8 - electromagnetic pass
! 9 - diffusion pass
! ipass = 10 - nonlocal part
! iplres Flag indicating that either second matrix is stored.
! dynamic analysis - mass matrix
! heat transfer - specific heat matrix
! buckle - initial stress stiffness
! ipois Control flag indicating Poisson type analysis
! ipois = 1 for heat transfer
! = 1 for heat transfer part of coupled
! = 1 for bearing
! = 1 for electrostatic
! = 1 for magnetostatic
! = 1 for nonlocal part
! ipoist Permanent copy of ipois. In coupled analysis , ipois = 0
! in stress portion, yet ipoist will still =1.
! irpflo global flag for rigid plastic flow analysis
! = 1 eularian formulation
! = 2 regular formulation; rigid material present in the analysis
! ismall control flag to indicate small displacement analysis. input data.
! ismall = 0 - large disp included.
! ismall = 1 - small displacement.
! the flag is changing between passes.
! ismalt permanent copy of ismall . in heat transfer portion of
! coupled analysis ismall =0 , but ismalt remains the same.
! isoil control flag indicating that soil / pore pressure
! calculation . input data.
! ispect control flag for response spectrum calculation. input data.
! ispnow control flag to indicate to perform a spectrum response
! calculation now.
! istore store stresses flag.
! istore = 0 in elem.f and if first pass of creep
! convergence checking in ogetst.f
! or harmonic analysis or thruc.f if not
! converged.
! iswep control flag for eigenvalue analysis.
! iswep=1 - go do extraction process
! ithcrp control flag for auto therm creep option. input data.
! itherm control flag for either temperature dependent material
! properties and/or thermal loads.
! iupblg control flag for follower force option. input data.
! iupdat control flag for update lagrange option for current element.
! jacflg control flag for lanczos iteration method. input data.
! jel control flag indicating that total load applied in
! increment, ignore previous solution.
! jel = 1 in increment 0
! = 1 if elastic or fourier
! = 1 in subincrements with elastic and adaptive
! jparks control flag for j integral by parks method. input data.
! largst control flag for finite strain plasticity. input data.
! lfond control variable that indicates if doing elastic
! foundation or film calculation. influences whether
! this is volumetric or surface integration.
! loadup control flag that indicates that nonlinearity occurred
! during previous increment.
! loaduq control flag that indicates that nonlinearity occurred.
! lodcor control flag for switching on the residual load correction.
! notice in input stage lodcor=0 means no loadcor,
! after omarc lodcor=1 means no loadcor
! lovl control flag for determining which "overlay" is to
! be called from ellib.
! lovl = 1 omarc
! = 2 oaread
! = 3 opress
! = 4 oasemb
! = 5 osolty
! = 6 ogetst
! = 7 oscinc
! = 8 odynam
! = 9 opmesh
! = 10 omesh2
! = 11 osetz
! = 12 oass
! = 13 oincdt
! = 14 oasmas
! = 15 ofluas
! = 16 ofluso
! = 17 oshtra
! = 18 ocass
! = 19 osoltc
! = 20 orezon
! = 21 otest
! = 22 oeigen
! lsub control variable to determine which part of element
! assembly function is being done.
! lsub = 1 - no longer used
! = 2 - beta*
! = 3 - cons*
! = 4 - ldef*
! = 5 - posw*
! = 6 - theta*
! = 7 - tmarx*
! = 8 - geom*
! magnet control flag for magnetostatic analysis. input data.
! ncycle cycle number. accumulated in osolty.f
! note first time through oasemb.f , ncycle = 0.
! newtnt control flag for permanent copy of newton.
! newton iteration type. input data.
! newton : = 1 full newton raphson
! 2 modified newton raphson
! 3 newton raphson with strain correct.
! 4 direct substitution
! 5 direct substitution followed by n.r.
! 6 direct substitution with line search
! 7 full newton raphson with secant initial stress
! 8 secant method
! 9 full newton raphson with line search
! noshr control flag for calculation interlaminar shears for
! elements 22,45, and 75. input data.
!ees
!
! jactch = 1 or 2 if elements are activated or deactivated
! = 3 if elements are adaptively remeshed or rezoned
! = 0 normally / reset to 0 when assembly is done
! ifricsh = 0 call to fricsh in otest not needed
! = 1 call to fricsh (nodal friction) in otest needed
! iremkin = 0 remove deactivated kinematic boundary conditions
! immediately - only in new input format (this is default)
! = 1 remove deactivated kinematic boundary conditions
! gradually - only in new input format
! iremfor = 0 remove force boundary conditions immediately -
! only in new input format (this is default)
! = 1 remove force boundary conditions gradually -
! only in new input format (this is default)
! ishearp set to 1 if shear panel elements are present in the model
!
! jspf = 0 not in spf loadcase
! > 0 in spf loadcase (jspf=1 during first increment)
! machining = 1 if the metal cutting feature is used, for memory allocation purpose
! = 0 (default) if no metal cutting feature required
!
! jlshell = 1 if there is a shell element in the mesh
! icompsol = 1 if there is a composite solid element in the mesh
! iupblgfo = 1 if follower force for point loads
! jcondir = 1 if contact priority option is used
! nstcrp = 0 (default) steady state creep flag (undocumented feature.
! if not 0, turns off special ncycle = 0 code in radial.f)
! nactive = number of active passes, if =1 then it's not a coupled analysis
! ipassref = reference ipass, if not in a multiphysics pass ipass=ipassref
! icheckmpc = value of mpc-check parameter option
! noline = set to 1 in osolty if no line seacrh should be done in ogetst
! icuring = set to 1 if the curing is included for the heat transfer analysis.
! ishrink = set to 1 if shrinkage strain is included for mechancial analysis.
! ioffsflg = 1 for small displacement beam/shell offsets
! = 2 for large displacement beam/shell offsets
! isetoff = 0 - do not apply beam/shell offsets
! = 1 - apply beam/shell offsets
! ioffsetm = min. value of offset flag
! iharmt = 1 global flag if a coupled analysis contains an harmonic pass
! inc_incdat = flag to record increment number of a new loadcase in incdat.f
! iautspc = flag for AutoSPC option
! ibrake = brake squeal in this increment
! icbush = set to 1 if cbush elements present in model
! istream_input = set to 1 for streaming input calling Marc as library
! iprsinp = set to 1 if pressure input, introduced so other variables
! such as h could be a function of pressure
! ivlsinp = set to 1 if velocity input, introduced so other variables
! such as h could be a function of velocity
! ipin_m = # of beam element with PIN flag
! jgnstr_glb = global control over pre or fast integrated composite shells
! imarc_return = Marc return flag for streaming input control
! iqvcimp = if non-zero, then the number of QVECT boundary conditions
! nqvceid = number of QVECT boundary conditions, where emisivity/absorbtion id entered
! istpnx = 1 if to stop at end of increment
! imicro1 = 1 if micro1 interface is used
! iaxisymm = set to 1 if axisymmetric analysis
! jbreakglue = set to 1 if breaking glued option is used
! iglstif = 1 if ddm and global stiffness matrix formed (sgi solver 6 or solver9)
! jfastasm = 1 do fast assembly using SuperForm code
! iwear = set to 1 if wear model, set to 2 if wear model and coordinates updated
! iwearcf = set to 1 to store nodal coefficient of friction for wear calculation
! imixmeth = set=1 then use nonlinear mixture material - allocate memory
! ielcmadyn = flag for magnetodynamics
! 0 - electromagnetics using newmark beta
! 1 - transient magnetics using backward euler
! idinout = flag to control if inside out elements should be deactivated
! igena_meth = 0 - generalized alpha parameters depend on whether or not contact
! is flagged (dynamic,7)
! 10 - generalized alpha parameters are optimized for a contact
! analysis (dynamic,8)
! 11 - generalized alpha parameters are optimized for an analysis
! without contact (dynamic,8)
! magf_meth = - Method to compute force in magnetostatic - structural
! = 1 - Virtual work method based on finite difference for the force computation
! = 2 - Maxwell stress tensor
! = 3 - Virtual work method based on local derivative for the force computation
! non_assumed = 1 no assumed strain formulation (forced)
! iredoboudry set to 1 if contact boundary needs to be recalculated
! ioffsz0 = 1 if composite are used with reference position.ne.0
! icomplt = 1 global flag if a coupled analysis contains an complex pass
! mesh_dual = 1 two independent meshes are used in magnetodynamic/thermal/structural
! one for magnetodynamic and the other for the remaining passes
! iactrp = 1 in an analysis with global remeshing, include inactive
! rigid bodies on post file
! mgnewton = 1 Use full Newton Raphson iteration for magnetostatic pass
!
! iusedens > 0 if mass density is used in the analysis (dynamics, mass dependent loading)
! igsigd0 = 1 set varselem(igsigd) to zero in next oasemb
! iaem = 1 if marc is called from aem (0 - off - default)
! icosim = 1 if marc is used in co-simulation analysis with ADAMS using the CosimEngine
! = 2 if marc is used in co-simulation analysis with ADAMS using the ACSI interface
! = 3 if marc is used in co-simulation analysis with scFLOW using the CosimEngine
! = 4 if marc is used in co-simulation analysis with scFLOW and ADAMS using the CosimEngine
! inodels = 1 nodal integration elements 239/240/241 present
! nlharm = 0 harmonic subincrements are linear
! = 1 harmonic subincrements are nonlinear
! iampini = 0 amplitude of previous harmonic subinc is initial estimate (default)
! = 1 zero amplitude is initial estimate
! iphasetr = 1 phase transformation material model is used
! iforminp flag indicating that contact is switched on via the CONTACT
! option in the input file (as opposed to the case that contact
! is switched on internally due to cyclic symmetry or model
! section creation)
! ispecerror = a+10*b (only for spectrum response analysis with missing mass option)
! a=0 or a=1 (modal shape with non-zero shift)
! b=0 or b=1 (recover with new assembly of stiffness matrix)
! icsprg = set to 1 if spring elements present in model
! imol Control flag for molecualr diffusion pass
! imolt Permanent control flag for molecualr diffusion pass
! Note in coupled analysis imolt will remain as one,
! but imol will be zero in stress pass or thermal pass.
! idatafit = run Marc to fit parameters
! iharmpar = 1 if harmonic parameter option is used
! inclcase load case increment use for cyclic plasticity data fitting
! imultifreq flag to indicate how many harmonic magnetodynamic passes are computed in coupled
! magnetodynamic/thermal(/structural) analyses.
! 0 or 1 one pass 2 two passes 3 or more is not supported
! init_elas use elastic stress-strain law as the material tangent for
! the first cycle of an increment
! ifatig packed integer telling which fatigue mode is active
! 1 = elastomer
! 10 = stress-life
! 100 = strain-life
! = 2 strain-life fatigue
! iftgmat = 0 no fatigue material properties in the dat file
! = 1 fatigue material properties in the dat file
! nchybrid cycle count used for hybrid contact; meant to force an extra iteration
! if the overlap for a node in hybrid contact is too large
! ibuckle buckle parameter option is active
! iexpande set to 1 if expanded elements (248, 249, 250 or 251) are
! present, 0 otherwise
!
!***********************************************************************
!$omp threadprivate(/marc_concom/)
!!

73
src/Marc/include/creeps2022.2 vendored Normal file
View File

@ -0,0 +1,73 @@
! common block definition file taken from respective MSC.Marc release and reformated to free format
!***********************************************************************
!
! File: creeps.cmn
!
! MSC.Marc include file
!
real(pReal) cptim,timinc,timinc_p,timinc_s,timincm,timinc_a,timinc_b
integer icfte,icfst,icfeq,icftm,icetem,mcreep,jcreep,icpa,icftmp,icfstr,&
icfqcp,icfcpm,icrppr,icrcha,icpb,iicpmt,iicpa
real(pReal) time_beg_lcase,time_beg_inc,fractol,time_beg_pst
real(pReal) fraction_donn,timinc_ol2
!
integer num_creepsr,num_creepsi,num_creeps2r,ncrp_arry
parameter(num_creepsr=7)
parameter(num_creepsi=17)
parameter(num_creeps2r=6)
parameter(ncrp_arry=7)
common/marc_creeps/cptim,timinc,timinc_p,timinc_s,timincm,timinc_a,timinc_b,icfte,icfst,&
icfeq,icftm,icetem,mcreep,jcreep,icpa,icftmp,icfstr,icfqcp,icfcpm,icrppr,icrcha,icpb,iicpmt,iicpa
common/marc_creeps2/time_beg_lcase,time_beg_inc,fractol,time_beg_pst,fraction_donn,timinc_ol2
!
! cptim Total time at begining of increment.
! timinc Incremental time for this step.
! icfte Local copy number of slopes of creep strain rate function
! versus temperature. Is -1 if exponent law used.
! icfst Local copy number of slopes of creep strain rate function
! versus equivalent stress. Is -1 if exponent law used.
! icfeq Local copy number of slopes of creep strain rate function
! versus equivalent strain. Is -1 if exponent law used.
! icftm Local copy number of slopes of creep strain rate function
! versus time. Is -1 if exponent law used.
! icetem Element number that needs to be checked for creep convergence
! or, if negative, the number of elements that need to
! be checked. In the latter case the elements to check
! are stored in ielcp.
! mcreep Maximum nuber of iterations for explicit creep.
! jcreep Counter of number of iterations for explicit creep
! procedure. jcreep must be .le. mcreep
! icpa(1-6) Pointer to constants in creep strain rate expression.
! icftmp Pointer to temperature dependent creep strain rate data.
! icfstr Pointer to equivalent stress dependent creep strain rate data.
! icfqcp Pointer to equivalent creep strain dependent creep strain
! rate data.
! icfcpm Pointer to equivalent creep strain rate dependent
! creep strain rate data.
! icrppr Permanent copy of icreep
! icrcha Control flag for creep convergence checking , if set to
! 1 then testing on absolute change in stress and creep
! strain, not relative testing. Input data.
! icpb(1-4) Pointer to storage of material id cross reference numbers.
! iicpmt creep law type ID
! =1 - power law
! =2 - solder
! =3 - steady-creep
! =4 - hyperbolic steady-creep
! iicpa Pointer to table IDs for constants in creep strain rate
! expression
!
!
! time_beg_lcase time at the beginning of the current load case
! time_beg_inc time at the beginning of the current increment
! fractol fraction of loadcase or increment time when we
! consider it to be finished
! time_beg_pst time corresponding to first increment to be
! read in from thermal post file for auto step
!
! timinc_old Time step of the previous increment
!
!***********************************************************************
!!$omp threadprivate(/marc_creeps/)
!!$omp threadprivate(/marc_creeps2/)
!!

View File

@ -196,6 +196,7 @@ subroutine selfTest
s1 = '1' s1 = '1'
s2 = '2' s2 = '2'
allocate(l) allocate(l)
if (l%contains('1')) error stop 'empty tList_contains'
call l%append(s1) call l%append(s1)
call l%append(s2) call l%append(s2)
if (any(l%as1dInt() /= [1,2])) error stop 'tList_as1dInt' if (any(l%as1dInt() /= [1,2])) error stop 'tList_as1dInt'
@ -204,7 +205,9 @@ subroutine selfTest
s2 = 'false' s2 = 'false'
if (any(l%as1dBool() .neqv. [.true.,.false.])) error stop 'tList_as1dBool' if (any(l%as1dBool() .neqv. [.true.,.false.])) error stop 'tList_as1dBool'
if (any(l%as1dString() /= ['true ','false'])) error stop 'tList_as1dString' if (any(l%as1dString() /= ['true ','false'])) error stop 'tList_as1dString'
if (l%asFormattedString() /= '[true, false]') error stop 'tScalar_asFormattedString' if (l%asFormattedString() /= '[true, false]') error stop 'tList_asFormattedString'
if ( .not. l%contains('true') &
.or. .not. l%contains('false')) error stop 'tList_contains'
end block list end block list
@ -226,6 +229,8 @@ subroutine selfTest
s3 = '3' s3 = '3'
s4 = '4' s4 = '4'
allocate(d) allocate(d)
if (d%contains('one-two')) error stop 'empty tDict_contains'
if (d%get_asInt('one-two',defaultVal=-1) /= -1) error stop 'empty tDict_get'
call d%set('one-two',l) call d%set('one-two',l)
call d%set('three',s3) call d%set('three',s3)
call d%set('four',s4) call d%set('four',s4)
@ -233,6 +238,13 @@ subroutine selfTest
error stop 'tDict_asFormattedString' error stop 'tDict_asFormattedString'
if (d%get_asInt('three') /= 3) error stop 'tDict_get_asInt' if (d%get_asInt('three') /= 3) error stop 'tDict_get_asInt'
if (any(d%get_as1dInt('one-two') /= [1,2])) error stop 'tDict_get_as1dInt' if (any(d%get_as1dInt('one-two') /= [1,2])) error stop 'tDict_get_as1dInt'
call d%set('one-two',s4)
if (d%asFormattedString() /= '{one-two: 4, three: 3, four: 4}') &
error stop 'tDict_set overwrite'
if ( .not. d%contains('one-two') &
.or. .not. d%contains('three') &
.or. .not. d%contains('four') &
) error stop 'tDict_contains'
end block dict end block dict
@ -407,7 +419,7 @@ recursive function tList_asFormattedString(self) result(str)
str = '[' str = '['
item => self%first item => self%first
do i = 1, self%length -1 do i = 2, self%length
str = str//item%node%asFormattedString()//', ' str = str//item%node%asFormattedString()//', '
item => item%next item => item%next
end do end do
@ -593,15 +605,14 @@ function tList_contains(self,k) result(exists)
type(tScalar), pointer :: scalar type(tScalar), pointer :: scalar
exists = .false.
item => self%first item => self%first
do j = 1, self%length exists = .false.
j = 1
do while (j <= self%length .and. .not. exists)
scalar => item%node%asScalar() scalar => item%node%asScalar()
if (scalar%value == k) then exists = scalar%value == k
exists = .true.
exit
endif
item => item%next item => item%next
j = j + 1
end do end do
end function tList_contains end function tList_contains
@ -620,7 +631,8 @@ function tList_get(self,i) result(node)
integer :: j integer :: j
if (i < 1 .or. i > self%length) call IO_error(150,ext_msg='tList_get @ '//IO_intAsString(i)) if (i < 1 .or. i > self%length) call IO_error(150,ext_msg='tList_get @ '//IO_intAsString(i) &
//' of '//IO_intAsString(self%length) )
item => self%first item => self%first
do j = 2, i do j = 2, i
item => item%next item => item%next
@ -854,7 +866,7 @@ recursive function tDict_asFormattedString(self) result(str)
str = '{' str = '{'
item => self%first item => self%first
do i = 1, self%length -1 do i = 2, self%length
str = str//trim(item%key)//': '//item%node%asFormattedString()//', ' str = str//trim(item%key)//': '//item%node%asFormattedString()//', '
item => item%next item => item%next
end do end do
@ -881,8 +893,7 @@ subroutine tDict_set(self,key,node)
self%length = 1 self%length = 1
else else
item => self%first item => self%first
searchExisting: do while (associated(item%next)) searchExisting: do while (associated(item%next) .and. item%key /= key)
if (item%key == key) exit
item => item%next item => item%next
end do searchExisting end do searchExisting
if (item%key /= key) then if (item%key /= key) then
@ -935,9 +946,10 @@ function tDict_key(self,i) result(key)
type(tItem), pointer :: item type(tItem), pointer :: item
if (i < 1 .or. i > self%length) call IO_error(150,ext_msg='tDict_key @ '//IO_intAsString(i)) if (i < 1 .or. i > self%length) call IO_error(150,ext_msg='tDict_key @ '//IO_intAsString(i) &
//' of '//IO_intAsString(self%length) )
item => self%first item => self%first
do j = 1, i-1 do j = 2, i
item => item%next item => item%next
end do end do
@ -986,11 +998,10 @@ function tDict_contains(self,k) result(exists)
exists = .false. exists = .false.
do j=1, self%length j = 1
if (self%key(j) == k) then do while(j <= self%length .and. .not. exists)
exists = .true. exists = self%key(j) == k
return j = j + 1
end if
end do end do
end function tDict_contains end function tDict_contains
@ -1008,27 +1019,21 @@ function tDict_get(self,k,defaultVal) result(node)
type(tItem), pointer :: item type(tItem), pointer :: item
integer :: j integer :: j
logical :: found
found = present(defaultVal)
if (found) node => defaultVal
j = 1
item => self%first item => self%first
do while(j <= self%length)
do j=1, self%length
if (item%key == k) then if (item%key == k) then
found = .true. node => item%node
exit return
end if end if
item => item%next item => item%next
j = j + 1
end do end do
if (.not. found) then if (present(defaultVal)) then
call IO_error(143,ext_msg=k) node => defaultVal
else else
if (associated(item)) node => item%node call IO_error(143,ext_msg=k)
end if end if
end function tDict_get end function tDict_get

View File

@ -106,8 +106,6 @@ program DAMASK_grid
external :: & external :: &
quit quit
class(tNode), pointer :: &
tmp
type(tDict), pointer :: & type(tDict), pointer :: &
config_load, & config_load, &
num_grid, & num_grid, &

View File

@ -33,7 +33,7 @@ module grid_damage_spectral
integer :: & integer :: &
itmax !< maximum number of iterations itmax !< maximum number of iterations
real(pReal) :: & real(pReal) :: &
residualStiffness, & !< non-zero residual damage phi_min, & !< non-zero residual damage
eps_damage_atol, & !< absolute tolerance for damage evolution eps_damage_atol, & !< absolute tolerance for damage evolution
eps_damage_rtol !< relative tolerance for damage evolution eps_damage_rtol !< relative tolerance for damage evolution
end type tNumerics end type tNumerics
@ -95,9 +95,9 @@ subroutine grid_damage_spectral_init()
num%eps_damage_rtol = num_grid%get_asFloat ('eps_damage_rtol',defaultVal=1.0e-6_pReal) num%eps_damage_rtol = num_grid%get_asFloat ('eps_damage_rtol',defaultVal=1.0e-6_pReal)
num_generic => config_numerics%get_dict('generic',defaultVal=emptyDict) num_generic => config_numerics%get_dict('generic',defaultVal=emptyDict)
num%residualStiffness = num_generic%get_asFloat('residualStiffness', defaultVal=1.0e-6_pReal) num%phi_min = num_generic%get_asFloat('phi_min', defaultVal=1.0e-6_pReal)
if (num%residualStiffness < 0.0_pReal) call IO_error(301,ext_msg='residualStiffness') if (num%phi_min < 0.0_pReal) call IO_error(301,ext_msg='phi_min')
if (num%itmax <= 1) call IO_error(301,ext_msg='itmax') if (num%itmax <= 1) call IO_error(301,ext_msg='itmax')
if (num%eps_damage_atol <= 0.0_pReal) call IO_error(301,ext_msg='eps_damage_atol') if (num%eps_damage_atol <= 0.0_pReal) call IO_error(301,ext_msg='eps_damage_atol')
if (num%eps_damage_rtol <= 0.0_pReal) call IO_error(301,ext_msg='eps_damage_rtol') if (num%eps_damage_rtol <= 0.0_pReal) call IO_error(301,ext_msg='eps_damage_rtol')
@ -253,11 +253,13 @@ end function grid_damage_spectral_solution
subroutine grid_damage_spectral_forward(cutBack) subroutine grid_damage_spectral_forward(cutBack)
logical, intent(in) :: cutBack logical, intent(in) :: cutBack
integer :: i, j, k, ce integer :: i, j, k, ce
DM :: dm_local DM :: dm_local
PetscScalar, dimension(:,:,:), pointer :: phi_PETSc PetscScalar, dimension(:,:,:), pointer :: phi_PETSc
PetscErrorCode :: err_PETSc PetscErrorCode :: err_PETSc
if (cutBack) then if (cutBack) then
phi_current = phi_lastInc phi_current = phi_lastInc
phi_stagInc = phi_lastInc phi_stagInc = phi_lastInc
@ -284,7 +286,7 @@ end subroutine grid_damage_spectral_forward
!-------------------------------------------------------------------------------------------------- !--------------------------------------------------------------------------------------------------
!> @brief forms the spectral damage residual vector !> @brief Construct the residual vector.
!-------------------------------------------------------------------------------------------------- !--------------------------------------------------------------------------------------------------
subroutine formResidual(in,x_scal,r,dummy,err_PETSc) subroutine formResidual(in,x_scal,r,dummy,err_PETSc)
@ -297,48 +299,34 @@ subroutine formResidual(in,x_scal,r,dummy,err_PETSc)
X_RANGE,Y_RANGE,Z_RANGE), intent(out) :: & X_RANGE,Y_RANGE,Z_RANGE), intent(out) :: &
r r
PetscObject :: dummy PetscObject :: dummy
PetscErrorCode :: err_PETSc PetscErrorCode, intent(out) :: err_PETSc
integer :: i, j, k, ce integer :: i, j, k, ce
real(pReal), dimension(3,cells(1),cells(2),cells3) :: vectorField
phi_current = x_scal phi_current = x_scal
!-------------------------------------------------------------------------------------------------- !--------------------------------------------------------------------------------------------------
! evaluate polarization field ! evaluate polarization field
scalarField_real = 0.0_pReal vectorField = utilities_ScalarGradient(phi_current)
scalarField_real(1:cells(1),1:cells(2),1:cells3) = phi_current
call utilities_FFTscalarForward
call utilities_fourierScalarGradient !< calculate gradient of damage field
call utilities_FFTvectorBackward
ce = 0 ce = 0
do k = 1, cells3; do j = 1, cells(2); do i = 1,cells(1) do k = 1, cells3; do j = 1, cells(2); do i = 1,cells(1)
ce = ce + 1 ce = ce + 1
vectorField_real(1:3,i,j,k) = matmul(homogenization_K_phi(ce) - K_ref, vectorField_real(1:3,i,j,k)) vectorField(1:3,i,j,k) = matmul(homogenization_K_phi(ce) - K_ref, vectorField(1:3,i,j,k))
end do; end do; end do end do; end do; end do
call utilities_FFTvectorForward r = utilities_VectorDivergence(vectorField)
call utilities_fourierVectorDivergence !< calculate damage divergence in fourier field
call utilities_FFTscalarBackward
ce = 0 ce = 0
do k = 1, cells3; do j = 1, cells(2); do i = 1,cells(1) do k = 1, cells3; do j = 1, cells(2); do i = 1,cells(1)
ce = ce + 1 ce = ce + 1
scalarField_real(i,j,k) = params%Delta_t*(scalarField_real(i,j,k) + homogenization_f_phi(phi_current(i,j,k),ce)) & r(i,j,k) = params%Delta_t*(r(i,j,k) + homogenization_f_phi(phi_current(i,j,k),ce)) &
+ homogenization_mu_phi(ce)*(phi_lastInc(i,j,k) - phi_current(i,j,k)) & + homogenization_mu_phi(ce)*(phi_lastInc(i,j,k) - phi_current(i,j,k)) &
+ mu_ref*phi_current(i,j,k) + mu_ref*phi_current(i,j,k)
end do; end do; end do end do; end do; end do
!--------------------------------------------------------------------------------------------------
! convolution of damage field with green operator
call utilities_FFTscalarForward
call utilities_fourierGreenConvolution(K_ref, mu_ref, params%Delta_t)
call utilities_FFTscalarBackward
where(scalarField_real(1:cells(1),1:cells(2),1:cells3) > phi_lastInc) &
scalarField_real(1:cells(1),1:cells(2),1:cells3) = phi_lastInc
where(scalarField_real(1:cells(1),1:cells(2),1:cells3) < num%residualStiffness) &
scalarField_real(1:cells(1),1:cells(2),1:cells3) = num%residualStiffness
!-------------------------------------------------------------------------------------------------- !--------------------------------------------------------------------------------------------------
! constructing residual ! constructing residual
r = scalarField_real(1:cells(1),1:cells(2),1:cells3) - phi_current r = max(min(utilities_GreenConvolution(r, K_ref, mu_ref, params%Delta_t),phi_lastInc),num%phi_min) &
- phi_current
err_PETSc = 0 err_PETSc = 0
end subroutine formResidual end subroutine formResidual

View File

@ -491,7 +491,7 @@ end subroutine converged
!-------------------------------------------------------------------------------------------------- !--------------------------------------------------------------------------------------------------
!> @brief forms the residual vector !> @brief Construct the residual vector.
!-------------------------------------------------------------------------------------------------- !--------------------------------------------------------------------------------------------------
subroutine formResidual(in, F, & subroutine formResidual(in, F, &
r, dummy, err_PETSc) r, dummy, err_PETSc)
@ -501,15 +501,17 @@ subroutine formResidual(in, F, &
intent(in) :: F !< deformation gradient field intent(in) :: F !< deformation gradient field
PetscScalar, dimension(3,3,X_RANGE,Y_RANGE,Z_RANGE), & PetscScalar, dimension(3,3,X_RANGE,Y_RANGE,Z_RANGE), &
intent(out) :: r !< residuum field intent(out) :: r !< residuum field
PetscObject :: dummy
PetscErrorCode :: err_PETSc
real(pReal), dimension(3,3) :: & real(pReal), dimension(3,3) :: &
deltaF_aim deltaF_aim
PetscInt :: & PetscInt :: &
PETScIter, & PETScIter, &
nfuncs nfuncs
PetscObject :: dummy
PetscErrorCode :: err_PETSc
integer(MPI_INTEGER_KIND) :: err_MPI integer(MPI_INTEGER_KIND) :: err_MPI
call SNESGetNumberFunctionEvals(SNES_mechanical,nfuncs,err_PETSc) call SNESGetNumberFunctionEvals(SNES_mechanical,nfuncs,err_PETSc)
CHKERRQ(err_PETSc) CHKERRQ(err_PETSc)
call SNESGetIterationNumber(SNES_mechanical,PETScIter,err_PETSc) call SNESGetIterationNumber(SNES_mechanical,PETScIter,err_PETSc)
@ -517,8 +519,6 @@ subroutine formResidual(in, F, &
if (nfuncs == 0 .and. PETScIter == 0) totalIter = -1 ! new increment if (nfuncs == 0 .and. PETScIter == 0) totalIter = -1 ! new increment
!--------------------------------------------------------------------------------------------------
! begin of new iteration
newIteration: if (totalIter <= PETScIter) then newIteration: if (totalIter <= PETScIter) then
totalIter = totalIter + 1 totalIter = totalIter + 1
print'(1x,a,3(a,i0))', trim(incInfo), ' @ Iteration ', num%itmin, '≤',totalIter, '≤', num%itmax print'(1x,a,3(a,i0))', trim(incInfo), ' @ Iteration ', num%itmin, '≤',totalIter, '≤', num%itmax
@ -529,32 +529,20 @@ subroutine formResidual(in, F, &
flush(IO_STDOUT) flush(IO_STDOUT)
end if newIteration end if newIteration
!-------------------------------------------------------------------------------------------------- associate (P => r)
! evaluate constitutive response call utilities_constitutiveResponse(P, &
call utilities_constitutiveResponse(r, & ! residuum gets field of first PK stress (to save memory)
P_av,C_volAvg,C_minMaxAvg, & P_av,C_volAvg,C_minMaxAvg, &
F,params%Delta_t,params%rotation_BC) F,params%Delta_t,params%rotation_BC)
call MPI_Allreduce(MPI_IN_PLACE,terminallyIll,1_MPI_INTEGER_KIND,MPI_LOGICAL,MPI_LOR,MPI_COMM_WORLD,err_MPI) call MPI_Allreduce(MPI_IN_PLACE,terminallyIll,1_MPI_INTEGER_KIND,MPI_LOGICAL,MPI_LOR,MPI_COMM_WORLD,err_MPI)
if (err_MPI /= 0_MPI_INTEGER_KIND) error stop 'MPI error' if (err_MPI /= 0_MPI_INTEGER_KIND) error stop 'MPI error'
err_div = utilities_divergenceRMS(P)
end associate
!--------------------------------------------------------------------------------------------------
! stress BC handling
deltaF_aim = math_mul3333xx33(S, P_av - P_aim) ! S = 0.0 for no bc deltaF_aim = math_mul3333xx33(S, P_av - P_aim) ! S = 0.0 for no bc
F_aim = F_aim - deltaF_aim F_aim = F_aim - deltaF_aim
err_BC = maxval(abs(merge(.0_pReal,P_av - P_aim,params%stress_mask))) err_BC = maxval(abs(merge(.0_pReal,P_av - P_aim,params%stress_mask)))
!-------------------------------------------------------------------------------------------------- r = utilities_GammaConvolution(r,params%rotation_BC%rotate(deltaF_aim,active=.true.))
! updated deformation gradient using fix point algorithm of basic scheme
tensorField_real = 0.0_pReal
tensorField_real(1:3,1:3,1:cells(1),1:cells(2),1:cells3) = r ! store fPK field for subsequent FFT forward transform
call utilities_FFTtensorForward ! FFT forward of global "tensorField_real"
err_div = utilities_divergenceRMS() ! divRMS of tensorField_fourier for later use
call utilities_fourierGammaConvolution(params%rotation_BC%rotate(deltaF_aim,active=.true.)) ! convolution of Gamma and tensorField_fourier
call utilities_FFTtensorBackward ! FFT backward of global tensorField_fourier
!--------------------------------------------------------------------------------------------------
! constructing residual
r = tensorField_real(1:3,1:3,1:cells(1),1:cells(2),1:cells3) ! Gamma*P gives correction towards div(P) = 0, so needs to be zero, too
end subroutine formResidual end subroutine formResidual

View File

@ -541,7 +541,7 @@ subroutine converged(snes_local,PETScIter,devNull1,devNull2,devNull3,reason,dumm
err_div/divTol, ' (',err_div, ' / m, tol = ',divTol,')' err_div/divTol, ' (',err_div, ' / m, tol = ',divTol,')'
print '(1x,a,f12.2,a,es8.2,a,es9.2,a)', 'error curl = ', & print '(1x,a,f12.2,a,es8.2,a,es9.2,a)', 'error curl = ', &
err_curl/curlTol,' (',err_curl,' -, tol = ',curlTol,')' err_curl/curlTol,' (',err_curl,' -, tol = ',curlTol,')'
print '(1x,a,f12.2,a,es8.2,a,es9.2,a)', 'error stress BC = ', & print '(1x,a,f12.2,a,es8.2,a,es9.2,a)', 'error mech BC = ', &
err_BC/BCTol, ' (',err_BC, ' Pa, tol = ',BCTol,')' err_BC/BCTol, ' (',err_BC, ' Pa, tol = ',BCTol,')'
print'(/,1x,a)', '===========================================================================' print'(/,1x,a)', '==========================================================================='
flush(IO_STDOUT) flush(IO_STDOUT)
@ -551,7 +551,7 @@ end subroutine converged
!-------------------------------------------------------------------------------------------------- !--------------------------------------------------------------------------------------------------
!> @brief forms the residual vector !> @brief Construct the residual vector.
!-------------------------------------------------------------------------------------------------- !--------------------------------------------------------------------------------------------------
subroutine formResidual(in, FandF_tau, & subroutine formResidual(in, FandF_tau, &
r, dummy,err_PETSc) r, dummy,err_PETSc)
@ -561,6 +561,9 @@ subroutine formResidual(in, FandF_tau, &
target, intent(in) :: FandF_tau target, intent(in) :: FandF_tau
PetscScalar, dimension(3,3,2,X_RANGE,Y_RANGE,Z_RANGE),& PetscScalar, dimension(3,3,2,X_RANGE,Y_RANGE,Z_RANGE),&
target, intent(out) :: r !< residuum field target, intent(out) :: r !< residuum field
PetscObject :: dummy
PetscErrorCode :: err_PETSc
PetscScalar, pointer, dimension(:,:,:,:,:) :: & PetscScalar, pointer, dimension(:,:,:,:,:) :: &
F, & F, &
F_tau, & F_tau, &
@ -569,13 +572,10 @@ subroutine formResidual(in, FandF_tau, &
PetscInt :: & PetscInt :: &
PETScIter, & PETScIter, &
nfuncs nfuncs
PetscObject :: dummy
PetscErrorCode :: err_PETSc
integer(MPI_INTEGER_KIND) :: err_MPI integer(MPI_INTEGER_KIND) :: err_MPI
integer :: & integer :: &
i, j, k, e i, j, k, e
!---------------------------------------------------------------------------------------------------
F => FandF_tau(1:3,1:3,1,& F => FandF_tau(1:3,1:3,1,&
XG_RANGE,YG_RANGE,ZG_RANGE) XG_RANGE,YG_RANGE,ZG_RANGE)
@ -597,8 +597,6 @@ subroutine formResidual(in, FandF_tau, &
if (nfuncs == 0 .and. PETScIter == 0) totalIter = -1 ! new increment if (nfuncs == 0 .and. PETScIter == 0) totalIter = -1 ! new increment
!--------------------------------------------------------------------------------------------------
! begin of new iteration
newIteration: if (totalIter <= PETScIter) then newIteration: if (totalIter <= PETScIter) then
totalIter = totalIter + 1 totalIter = totalIter + 1
print'(1x,a,3(a,i0))', trim(incInfo), ' @ Iteration ', num%itmin, '≤',totalIter, '≤', num%itmax print'(1x,a,3(a,i0))', trim(incInfo), ' @ Iteration ', num%itmin, '≤',totalIter, '≤', num%itmax
@ -609,63 +607,53 @@ subroutine formResidual(in, FandF_tau, &
flush(IO_STDOUT) flush(IO_STDOUT)
end if newIteration end if newIteration
!--------------------------------------------------------------------------------------------------
!
tensorField_real = 0.0_pReal
do k = 1, cells3; do j = 1, cells(2); do i = 1, cells(1) do k = 1, cells3; do j = 1, cells(2); do i = 1, cells(1)
tensorField_real(1:3,1:3,i,j,k) = & r_F_tau(1:3,1:3,i,j,k) = &
num%beta*math_mul3333xx33(C_scale,F(1:3,1:3,i,j,k) - math_I3) -& num%beta*math_mul3333xx33(C_scale,F(1:3,1:3,i,j,k) - math_I3) -&
num%alpha*matmul(F(1:3,1:3,i,j,k), & num%alpha*matmul(F(1:3,1:3,i,j,k), &
math_mul3333xx33(C_scale,F_tau(1:3,1:3,i,j,k) - F(1:3,1:3,i,j,k) - math_I3)) math_mul3333xx33(C_scale,F_tau(1:3,1:3,i,j,k) - F(1:3,1:3,i,j,k) - math_I3))
end do; end do; end do end do; end do; end do
r_F_tau = num%beta*F &
- utilities_GammaConvolution(r_F_tau,params%rotation_BC%rotate(num%beta*F_aim,active=.true.))
!-------------------------------------------------------------------------------------------------- err_curl = utilities_curlRMS(F)
! doing convolution in Fourier space
call utilities_FFTtensorForward
call utilities_fourierGammaConvolution(params%rotation_BC%rotate(num%beta*F_aim,active=.true.))
call utilities_FFTtensorBackward
!-------------------------------------------------------------------------------------------------- #ifdef __GFORTRAN__
! constructing residual call utilities_constitutiveResponse(r_F, &
r_F_tau = num%beta*F - tensorField_real(1:3,1:3,1:cells(1),1:cells(2),1:cells3) #else
associate (P => r_F)
!-------------------------------------------------------------------------------------------------- call utilities_constitutiveResponse(P, &
! evaluate constitutive response #endif
call utilities_constitutiveResponse(r_F, & ! "residuum" gets field of first PK stress (to save memory)
P_av,C_volAvg,C_minMaxAvg, & P_av,C_volAvg,C_minMaxAvg, &
F - r_F_tau/num%beta,params%Delta_t,params%rotation_BC) F - r_F_tau/num%beta,params%Delta_t,params%rotation_BC)
call MPI_Allreduce(MPI_IN_PLACE,terminallyIll,1_MPI_INTEGER_KIND,MPI_LOGICAL,MPI_LOR,MPI_COMM_WORLD,err_MPI) call MPI_Allreduce(MPI_IN_PLACE,terminallyIll,1_MPI_INTEGER_KIND,MPI_LOGICAL,MPI_LOR,MPI_COMM_WORLD,err_MPI)
#ifdef __GFORTRAN__
!-------------------------------------------------------------------------------------------------- err_div = utilities_divergenceRMS(r_F)
! stress BC handling #else
F_aim = F_aim - math_mul3333xx33(S, P_av - P_aim) ! S = 0.0 for no bc err_div = utilities_divergenceRMS(P)
err_BC = maxval(abs(merge(math_mul3333xx33(C_scale,F_aim-params%rotation_BC%rotate(F_av)), & #endif
P_av-P_aim, &
params%stress_mask)))
! calculate divergence
tensorField_real = 0.0_pReal
tensorField_real(1:3,1:3,1:cells(1),1:cells(2),1:cells3) = r_F !< stress field in disguise
call utilities_FFTtensorForward
err_div = utilities_divergenceRMS() !< root mean squared error in divergence of stress
!--------------------------------------------------------------------------------------------------
! constructing residual
e = 0 e = 0
do k = 1, cells3; do j = 1, cells(2); do i = 1, cells(1) do k = 1, cells3; do j = 1, cells(2); do i = 1, cells(1)
e = e + 1 e = e + 1
r_F(1:3,1:3,i,j,k) = & r_F(1:3,1:3,i,j,k) = &
math_mul3333xx33(math_invSym3333(homogenization_dPdF(1:3,1:3,1:3,1:3,e) + C_scale), & math_mul3333xx33(math_invSym3333(homogenization_dPdF(1:3,1:3,1:3,1:3,e) + C_scale), &
#ifdef __GFORTRAN__
r_F(1:3,1:3,i,j,k) - matmul(F(1:3,1:3,i,j,k), & r_F(1:3,1:3,i,j,k) - matmul(F(1:3,1:3,i,j,k), &
#else
P(1:3,1:3,i,j,k) - matmul(F(1:3,1:3,i,j,k), &
#endif
math_mul3333xx33(C_scale,F_tau(1:3,1:3,i,j,k) - F(1:3,1:3,i,j,k) - math_I3))) & math_mul3333xx33(C_scale,F_tau(1:3,1:3,i,j,k) - F(1:3,1:3,i,j,k) - math_I3))) &
+ r_F_tau(1:3,1:3,i,j,k) + r_F_tau(1:3,1:3,i,j,k)
end do; end do; end do end do; end do; end do
#ifndef __GFORTRAN__
end associate
#endif
F_aim = F_aim - math_mul3333xx33(S, P_av - P_aim) ! S = 0.0 for no bc
err_BC = maxval(abs(merge(math_mul3333xx33(C_scale,F_aim-params%rotation_BC%rotate(F_av)), &
P_av-P_aim, &
params%stress_mask)))
!--------------------------------------------------------------------------------------------------
! calculating curl
tensorField_real = 0.0_pReal
tensorField_real(1:3,1:3,1:cells(1),1:cells(2),1:cells3) = F
call utilities_FFTtensorForward
err_curl = utilities_curlRMS()
end subroutine formResidual end subroutine formResidual

View File

@ -242,11 +242,13 @@ end function grid_thermal_spectral_solution
subroutine grid_thermal_spectral_forward(cutBack) subroutine grid_thermal_spectral_forward(cutBack)
logical, intent(in) :: cutBack logical, intent(in) :: cutBack
integer :: i, j, k, ce integer :: i, j, k, ce
DM :: dm_local DM :: dm_local
PetscScalar, dimension(:,:,:), pointer :: T_PETSc PetscScalar, dimension(:,:,:), pointer :: T_PETSc
PetscErrorCode :: err_PETSc PetscErrorCode :: err_PETSc
if (cutBack) then if (cutBack) then
T_current = T_lastInc T_current = T_lastInc
T_stagInc = T_lastInc T_stagInc = T_lastInc
@ -307,7 +309,7 @@ end subroutine grid_thermal_spectral_restartWrite
!-------------------------------------------------------------------------------------------------- !--------------------------------------------------------------------------------------------------
!> @brief forms the spectral thermal residual vector !> @brief Construct the residual vector.
!-------------------------------------------------------------------------------------------------- !--------------------------------------------------------------------------------------------------
subroutine formResidual(in,x_scal,r,dummy,err_PETSc) subroutine formResidual(in,x_scal,r,dummy,err_PETSc)
@ -320,42 +322,34 @@ subroutine formResidual(in,x_scal,r,dummy,err_PETSc)
X_RANGE,Y_RANGE,Z_RANGE), intent(out) :: & X_RANGE,Y_RANGE,Z_RANGE), intent(out) :: &
r r
PetscObject :: dummy PetscObject :: dummy
PetscErrorCode :: err_PETSc PetscErrorCode, intent(out) :: err_PETSc
integer :: i, j, k, ce integer :: i, j, k, ce
real(pReal), dimension(3,cells(1),cells(2),cells3) :: vectorField
T_current = x_scal T_current = x_scal
!-------------------------------------------------------------------------------------------------- !--------------------------------------------------------------------------------------------------
! evaluate polarization field ! evaluate polarization field
scalarField_real = 0.0_pReal vectorField = utilities_ScalarGradient(T_current)
scalarField_real(1:cells(1),1:cells(2),1:cells3) = T_current
call utilities_FFTscalarForward
call utilities_fourierScalarGradient !< calculate gradient of temperature field
call utilities_FFTvectorBackward
ce = 0 ce = 0
do k = 1, cells3; do j = 1, cells(2); do i = 1,cells(1) do k = 1, cells3; do j = 1, cells(2); do i = 1,cells(1)
ce = ce + 1 ce = ce + 1
vectorField_real(1:3,i,j,k) = matmul(homogenization_K_T(ce) - K_ref, vectorField_real(1:3,i,j,k)) vectorField(1:3,i,j,k) = matmul(homogenization_K_T(ce) - K_ref, vectorField(1:3,i,j,k))
end do; end do; end do end do; end do; end do
call utilities_FFTvectorForward r = utilities_VectorDivergence(vectorField)
call utilities_fourierVectorDivergence !< calculate temperature divergence in fourier field
call utilities_FFTscalarBackward
ce = 0 ce = 0
do k = 1, cells3; do j = 1, cells(2); do i = 1,cells(1) do k = 1, cells3; do j = 1, cells(2); do i = 1,cells(1)
ce = ce + 1 ce = ce + 1
scalarField_real(i,j,k) = params%Delta_t*(scalarField_real(i,j,k) + homogenization_f_T(ce)) & r(i,j,k) = params%Delta_t*(r(i,j,k) + homogenization_f_T(ce)) &
+ homogenization_mu_T(ce) * (T_lastInc(i,j,k) - T_current(i,j,k)) & + homogenization_mu_T(ce) * (T_lastInc(i,j,k) - T_current(i,j,k)) &
+ mu_ref*T_current(i,j,k) + mu_ref*T_current(i,j,k)
end do; end do; end do end do; end do; end do
!--------------------------------------------------------------------------------------------------
! convolution of temperature field with green operator
call utilities_FFTscalarForward
call utilities_fourierGreenConvolution(K_ref, mu_ref, params%Delta_t)
call utilities_FFTscalarBackward
!-------------------------------------------------------------------------------------------------- !--------------------------------------------------------------------------------------------------
! constructing residual ! constructing residual
r = T_current - scalarField_real(1:cells(1),1:cells(2),1:cells3) r = T_current &
- utilities_GreenConvolution(r, K_ref, mu_ref, params%Delta_t)
err_PETSc = 0 err_PETSc = 0
end subroutine formResidual end subroutine formResidual

View File

@ -42,9 +42,9 @@ module spectral_utilities
!-------------------------------------------------------------------------------------------------- !--------------------------------------------------------------------------------------------------
! variables storing information for spectral method and FFTW ! variables storing information for spectral method and FFTW
real(C_DOUBLE), public, dimension(:,:,:,:,:), pointer :: tensorField_real !< tensor field in real space real(C_DOUBLE), dimension(:,:,:,:,:), pointer :: tensorField_real !< tensor field in real space
real(C_DOUBLE), public, dimension(:,:,:,:), pointer :: vectorField_real !< vector field in real space real(C_DOUBLE), dimension(:,:,:,:), pointer :: vectorField_real !< vector field in real space
real(C_DOUBLE), public, dimension(:,:,:), pointer :: scalarField_real !< scalar field in real space real(C_DOUBLE), dimension(:,:,:), pointer :: scalarField_real !< scalar field in real space
complex(C_DOUBLE_COMPLEX), dimension(:,:,:,:,:), pointer :: tensorField_fourier !< tensor field in Fourier space complex(C_DOUBLE_COMPLEX), dimension(:,:,:,:,:), pointer :: tensorField_fourier !< tensor field in Fourier space
complex(C_DOUBLE_COMPLEX), dimension(:,:,:,:), pointer :: vectorField_fourier !< vector field in Fourier space complex(C_DOUBLE_COMPLEX), dimension(:,:,:,:), pointer :: vectorField_fourier !< vector field in Fourier space
complex(C_DOUBLE_COMPLEX), dimension(:,:,:), pointer :: scalarField_fourier !< scalar field in Fourier space complex(C_DOUBLE_COMPLEX), dimension(:,:,:), pointer :: scalarField_fourier !< scalar field in Fourier space
@ -116,18 +116,12 @@ module spectral_utilities
public :: & public :: &
spectral_utilities_init, & spectral_utilities_init, &
utilities_updateGamma, & utilities_updateGamma, &
utilities_FFTtensorForward, & utilities_GammaConvolution, &
utilities_FFTtensorBackward, & utilities_GreenConvolution, &
utilities_FFTvectorForward, &
utilities_FFTvectorBackward, &
utilities_FFTscalarForward, &
utilities_FFTscalarBackward, &
utilities_fourierGammaConvolution, &
utilities_fourierGreenConvolution, &
utilities_divergenceRMS, & utilities_divergenceRMS, &
utilities_curlRMS, & utilities_curlRMS, &
utilities_fourierScalarGradient, & utilities_ScalarGradient, &
utilities_fourierVectorDivergence, & utilities_VectorDivergence, &
utilities_maskedCompliance, & utilities_maskedCompliance, &
utilities_constitutiveResponse, & utilities_constitutiveResponse, &
utilities_calculateRate, & utilities_calculateRate, &
@ -385,6 +379,7 @@ end subroutine spectral_utilities_init
subroutine utilities_updateGamma(C) subroutine utilities_updateGamma(C)
real(pReal), intent(in), dimension(3,3,3,3) :: C !< input stiffness to store as reference stiffness real(pReal), intent(in), dimension(3,3,3,3) :: C !< input stiffness to store as reference stiffness
complex(pReal), dimension(3,3) :: temp33_cmplx, xiDyad_cmplx complex(pReal), dimension(3,3) :: temp33_cmplx, xiDyad_cmplx
real(pReal), dimension(6,6) :: A, A_inv real(pReal), dimension(6,6) :: A, A_inv
integer :: & integer :: &
@ -392,7 +387,8 @@ subroutine utilities_updateGamma(C)
l, m, n, o l, m, n, o
logical :: err logical :: err
C_ref = C
C_ref = C/wgt
if (.not. num%memory_efficient) then if (.not. num%memory_efficient) then
gamma_hat = cmplx(0.0_pReal,0.0_pReal,pReal) ! for the singular point and any non invertible A gamma_hat = cmplx(0.0_pReal,0.0_pReal,pReal) ! for the singular point and any non invertible A
@ -434,68 +430,6 @@ subroutine utilities_updateGamma(C)
end subroutine utilities_updateGamma end subroutine utilities_updateGamma
!--------------------------------------------------------------------------------------------------
!> @brief forward FFT of data in field_real to field_fourier
!> @details Does an unweighted FFT transform from real to complex. Extra padding entries are set
! to 0.0
!--------------------------------------------------------------------------------------------------
subroutine utilities_FFTtensorForward()
tensorField_real(1:3,1:3,cells(1)+1:cells1Red*2,:,:) = 0.0_pReal
call fftw_mpi_execute_dft_r2c(planTensorForth,tensorField_real,tensorField_fourier)
end subroutine utilities_FFTtensorForward
!--------------------------------------------------------------------------------------------------
!> @brief backward FFT of data in field_fourier to field_real
!> @details Does an weighted inverse FFT transform from complex to real
!--------------------------------------------------------------------------------------------------
subroutine utilities_FFTtensorBackward()
call fftw_mpi_execute_dft_c2r(planTensorBack,tensorField_fourier,tensorField_real)
tensorField_real = tensorField_real * wgt ! normalize the result by number of elements
end subroutine utilities_FFTtensorBackward
!--------------------------------------------------------------------------------------------------
!> @brief forward FFT of data in scalarField_real to scalarField_fourier
!> @details Does an unweighted FFT transform from real to complex. Extra padding entries are set
! to 0.0
!--------------------------------------------------------------------------------------------------
subroutine utilities_FFTscalarForward()
scalarField_real(cells(1)+1:cells1Red*2,:,:) = 0.0_pReal
call fftw_mpi_execute_dft_r2c(planScalarForth,scalarField_real,scalarField_fourier)
end subroutine utilities_FFTscalarForward
!--------------------------------------------------------------------------------------------------
!> @brief backward FFT of data in scalarField_fourier to scalarField_real
!> @details Does an weighted inverse FFT transform from complex to real
!--------------------------------------------------------------------------------------------------
subroutine utilities_FFTscalarBackward()
call fftw_mpi_execute_dft_c2r(planScalarBack,scalarField_fourier,scalarField_real)
scalarField_real = scalarField_real * wgt ! normalize the result by number of elements
end subroutine utilities_FFTscalarBackward
!--------------------------------------------------------------------------------------------------
!> @brief forward FFT of data in field_real to field_fourier with highest freqs. removed
!> @details Does an unweighted FFT transform from real to complex. Extra padding entries are set
! to 0.0
!--------------------------------------------------------------------------------------------------
subroutine utilities_FFTvectorForward()
vectorField_real(1:3,cells(1)+1:cells1Red*2,:,:) = 0.0_pReal
call fftw_mpi_execute_dft_r2c(planVectorForth,vectorField_real,vectorField_fourier)
end subroutine utilities_FFTvectorForward
!-------------------------------------------------------------------------------------------------- !--------------------------------------------------------------------------------------------------
!> @brief backward FFT of data in field_fourier to field_real !> @brief backward FFT of data in field_fourier to field_real
!> @details Does an weighted inverse FFT transform from complex to real !> @details Does an weighted inverse FFT transform from complex to real
@ -511,12 +445,14 @@ end subroutine utilities_FFTvectorBackward
!-------------------------------------------------------------------------------------------------- !--------------------------------------------------------------------------------------------------
!> @brief doing convolution gamma_hat * field_real, ensuring that average value = fieldAim !> @brief doing convolution gamma_hat * field_real, ensuring that average value = fieldAim
!-------------------------------------------------------------------------------------------------- !--------------------------------------------------------------------------------------------------
subroutine utilities_fourierGammaConvolution(fieldAim) function utilities_GammaConvolution(field, fieldAim) result(gammaField)
real(pReal), intent(in), dimension(3,3,cells(1),cells(2),cells3) :: field
real(pReal), intent(in), dimension(3,3) :: fieldAim !< desired average value of the field after convolution real(pReal), intent(in), dimension(3,3) :: fieldAim !< desired average value of the field after convolution
real(pReal), dimension(3,3,cells(1),cells(2),cells3) :: gammaField
complex(pReal), dimension(3,3) :: temp33_cmplx, xiDyad_cmplx complex(pReal), dimension(3,3) :: temp33_cmplx, xiDyad_cmplx
real(pReal), dimension(6,6) :: A, A_inv real(pReal), dimension(6,6) :: A, A_inv
integer :: & integer :: &
i, j, k, & i, j, k, &
l, m, n, o l, m, n, o
@ -526,8 +462,10 @@ subroutine utilities_fourierGammaConvolution(fieldAim)
print'(/,1x,a)', '... doing gamma convolution ...............................................' print'(/,1x,a)', '... doing gamma convolution ...............................................'
flush(IO_STDOUT) flush(IO_STDOUT)
!-------------------------------------------------------------------------------------------------- tensorField_real(1:3,1:3,cells(1)+1:cells1Red*2,1:cells(2),1:cells3) = 0.0_pReal
! do the actual spectral method calculation (mechanical equilibrium) tensorField_real(1:3,1:3,1:cells(1), 1:cells(2),1:cells3) = field
call fftw_mpi_execute_dft_r2c(planTensorForth,tensorField_real,tensorField_fourier)
memoryEfficient: if (num%memory_efficient) then memoryEfficient: if (num%memory_efficient) then
!$OMP PARALLEL DO PRIVATE(l,m,n,o,temp33_cmplx,xiDyad_cmplx,A,A_inv,err,gamma_hat) !$OMP PARALLEL DO PRIVATE(l,m,n,o,temp33_cmplx,xiDyad_cmplx,A,A_inv,err,gamma_hat)
do j = 1, cells2; do k = 1, cells(3); do i = 1, cells1Red do j = 1, cells2; do k = 1, cells(3); do i = 1, cells1Red
@ -586,39 +524,53 @@ subroutine utilities_fourierGammaConvolution(fieldAim)
!$OMP END PARALLEL DO !$OMP END PARALLEL DO
end if memoryEfficient end if memoryEfficient
if (cells3Offset == 0) tensorField_fourier(1:3,1:3,1,1,1) = cmplx(fieldAim/wgt,0.0_pReal,pReal) if (cells3Offset == 0) tensorField_fourier(1:3,1:3,1,1,1) = cmplx(fieldAim,0.0_pReal,pReal)
end subroutine utilities_fourierGammaConvolution call fftw_mpi_execute_dft_c2r(planTensorBack,tensorField_fourier,tensorField_real)
gammaField = tensorField_real(1:3,1:3,1:cells(1),1:cells(2),1:cells3)
end function utilities_GammaConvolution
!-------------------------------------------------------------------------------------------------- !--------------------------------------------------------------------------------------------------
!> @brief doing convolution DamageGreenOp_hat * field_real !> @brief Convolution of Greens' operator for damage/thermal.
!-------------------------------------------------------------------------------------------------- !--------------------------------------------------------------------------------------------------
subroutine utilities_fourierGreenConvolution(D_ref, mu_ref, Delta_t) function utilities_GreenConvolution(field, D_ref, mu_ref, Delta_t) result(greenField)
real(pReal), intent(in), dimension(cells(1),cells(2),cells3) :: field
real(pReal), dimension(3,3), intent(in) :: D_ref real(pReal), dimension(3,3), intent(in) :: D_ref
real(pReal), intent(in) :: mu_ref, Delta_t real(pReal), intent(in) :: mu_ref, Delta_t
real(pReal), dimension(cells(1),cells(2),cells3) :: greenField
complex(pReal) :: GreenOp_hat complex(pReal) :: GreenOp_hat
integer :: i, j, k integer :: i, j, k
!--------------------------------------------------------------------------------------------------
! do the actual spectral method calculation scalarField_real(cells(1)+1:cells1Red*2,1:cells(2),1:cells3) = 0.0_pReal
scalarField_real(1:cells(1), 1:cells(2),1:cells3) = field
call fftw_mpi_execute_dft_r2c(planScalarForth,scalarField_real,scalarField_fourier)
!$OMP PARALLEL DO PRIVATE(GreenOp_hat) !$OMP PARALLEL DO PRIVATE(GreenOp_hat)
do j = 1, cells2; do k = 1, cells(3); do i = 1, cells1Red do j = 1, cells2; do k = 1, cells(3); do i = 1, cells1Red
GreenOp_hat = cmplx(1.0_pReal,0.0_pReal,pReal) & GreenOp_hat = cmplx(wgt,0.0_pReal,pReal) &
/ (cmplx(mu_ref,0.0_pReal,pReal) + cmplx(Delta_t,0.0_pReal,pReal) & / (cmplx(mu_ref,0.0_pReal,pReal) + cmplx(Delta_t,0.0_pReal,pReal) &
* sum(conjg(xi1st(1:3,i,k,j))* matmul(cmplx(D_ref,0.0_pReal,pReal),xi1st(1:3,i,k,j)))) * sum(conjg(xi1st(1:3,i,k,j))* matmul(cmplx(D_ref,0.0_pReal,pReal),xi1st(1:3,i,k,j))))
scalarField_fourier(i,k,j) = scalarField_fourier(i,k,j)*GreenOp_hat scalarField_fourier(i,k,j) = scalarField_fourier(i,k,j)*GreenOp_hat
end do; end do; end do end do; end do; end do
!$OMP END PARALLEL DO !$OMP END PARALLEL DO
end subroutine utilities_fourierGreenConvolution call fftw_mpi_execute_dft_c2r(planScalarBack,scalarField_fourier,scalarField_real)
greenField = scalarField_real(1:cells(1),1:cells(2),1:cells3)
end function utilities_GreenConvolution
!-------------------------------------------------------------------------------------------------- !--------------------------------------------------------------------------------------------------
!> @brief calculate root mean square of divergence of field_fourier !> @brief Calculate root mean square of divergence.
!-------------------------------------------------------------------------------------------------- !--------------------------------------------------------------------------------------------------
real(pReal) function utilities_divergenceRMS() real(pReal) function utilities_divergenceRMS(tensorField)
real(pReal), dimension(3,3,cells(1),cells(2),cells3), intent(in) :: tensorField
integer :: i, j, k integer :: i, j, k
integer(MPI_INTEGER_KIND) :: err_MPI integer(MPI_INTEGER_KIND) :: err_MPI
@ -628,6 +580,10 @@ real(pReal) function utilities_divergenceRMS()
print'(/,1x,a)', '... calculating divergence ................................................' print'(/,1x,a)', '... calculating divergence ................................................'
flush(IO_STDOUT) flush(IO_STDOUT)
tensorField_real(1:3,1:3,cells(1)+1:cells1Red*2,1:cells(2),1:cells3) = 0.0_pReal
tensorField_real(1:3,1:3,1:cells(1), 1:cells(2),1:cells3) = tensorField
call fftw_mpi_execute_dft_r2c(planTensorForth,tensorField_real,tensorField_fourier)
rescaledGeom = cmplx(geomSize/scaledGeomSize,0.0_pReal,pReal) rescaledGeom = cmplx(geomSize/scaledGeomSize,0.0_pReal,pReal)
!-------------------------------------------------------------------------------------------------- !--------------------------------------------------------------------------------------------------
@ -660,9 +616,11 @@ end function utilities_divergenceRMS
!-------------------------------------------------------------------------------------------------- !--------------------------------------------------------------------------------------------------
!> @brief calculate max of curl of field_fourier !> @brief Calculate root mean square of curl.
!-------------------------------------------------------------------------------------------------- !--------------------------------------------------------------------------------------------------
real(pReal) function utilities_curlRMS() real(pReal) function utilities_curlRMS(tensorField)
real(pReal), dimension(3,3,cells(1),cells(2),cells3), intent(in) :: tensorField
integer :: i, j, k, l integer :: i, j, k, l
integer(MPI_INTEGER_KIND) :: err_MPI integer(MPI_INTEGER_KIND) :: err_MPI
@ -673,6 +631,10 @@ real(pReal) function utilities_curlRMS()
print'(/,1x,a)', '... calculating curl ......................................................' print'(/,1x,a)', '... calculating curl ......................................................'
flush(IO_STDOUT) flush(IO_STDOUT)
tensorField_real(1:3,1:3,cells(1)+1:cells1Red*2,1:cells(2),1:cells3) = 0.0_pReal
tensorField_real(1:3,1:3,1:cells(1), 1:cells(2),1:cells3) = tensorField
call fftw_mpi_execute_dft_r2c(planTensorForth,tensorField_real,tensorField_fourier)
rescaledGeom = cmplx(geomSize/scaledGeomSize,0.0_pReal,pReal) rescaledGeom = cmplx(geomSize/scaledGeomSize,0.0_pReal,pReal)
!-------------------------------------------------------------------------------------------------- !--------------------------------------------------------------------------------------------------
@ -723,7 +685,7 @@ end function utilities_curlRMS
!-------------------------------------------------------------------------------------------------- !--------------------------------------------------------------------------------------------------
!> @brief calculates mask compliance tensor used to adjust F to fullfill stress BC !> @brief Calculate masked compliance tensor used to adjust F to fullfill stress BC.
!-------------------------------------------------------------------------------------------------- !--------------------------------------------------------------------------------------------------
function utilities_maskedCompliance(rot_BC,mask_stress,C) function utilities_maskedCompliance(rot_BC,mask_stress,C)
@ -793,29 +755,46 @@ end function utilities_maskedCompliance
!-------------------------------------------------------------------------------------------------- !--------------------------------------------------------------------------------------------------
!> @brief calculate scalar gradient in fourier field !> @brief Calculate gradient of scalar field.
!-------------------------------------------------------------------------------------------------- !--------------------------------------------------------------------------------------------------
subroutine utilities_fourierScalarGradient() function utilities_ScalarGradient(field) result(grad)
real(pReal), intent(in), dimension( cells(1),cells(2),cells3) :: field
real(pReal), dimension(3,cells(1),cells(2),cells3) :: grad
integer :: i, j, k integer :: i, j, k
scalarField_real(cells(1)+1:cells1Red*2,1:cells(2),1:cells3) = 0.0_pReal
scalarField_real(1:cells(1), 1:cells(2),1:cells3) = field
call fftw_mpi_execute_dft_r2c(planScalarForth,scalarField_real,scalarField_fourier)
do j = 1, cells2; do k = 1, cells(3); do i = 1,cells1Red do j = 1, cells2; do k = 1, cells(3); do i = 1,cells1Red
vectorField_fourier(1:3,i,k,j) = scalarField_fourier(i,k,j)*xi1st(1:3,i,k,j) ! ToDo: no -conjg? vectorField_fourier(1:3,i,k,j) = scalarField_fourier(i,k,j)*xi1st(1:3,i,k,j) ! ToDo: no -conjg?
end do; end do; end do end do; end do; end do
call fftw_mpi_execute_dft_c2r(planVectorBack,vectorField_fourier,vectorField_real)
grad = vectorField_real(1:3,1:cells(1),1:cells(2),1:cells3)*wgt
end subroutine utilities_fourierScalarGradient end function utilities_ScalarGradient
!-------------------------------------------------------------------------------------------------- !--------------------------------------------------------------------------------------------------
!> @brief calculate vector divergence in fourier field !> @brief Calculate divergence of vector field.
!-------------------------------------------------------------------------------------------------- !--------------------------------------------------------------------------------------------------
subroutine utilities_fourierVectorDivergence() function utilities_VectorDivergence(field) result(div)
real(pReal), intent(in), dimension(3,cells(1),cells(2),cells3) :: field
real(pReal), dimension( cells(1),cells(2),cells3) :: div
vectorField_real(1:3,cells(1)+1:cells1Red*2,1:cells(2),1:cells3) = 0.0_pReal
vectorField_real(1:3,1:cells(1), 1:cells(2),1:cells3) = field
call fftw_mpi_execute_dft_r2c(planVectorForth,vectorField_real,vectorField_fourier)
scalarField_fourier(1:cells1Red,1:cells(3),1:cells2) = sum(vectorField_fourier(1:3,1:cells1Red,1:cells(3),1:cells2) & scalarField_fourier(1:cells1Red,1:cells(3),1:cells2) = sum(vectorField_fourier(1:3,1:cells1Red,1:cells(3),1:cells2) &
*conjg(-xi1st),1) *conjg(-xi1st),1)
call fftw_mpi_execute_dft_c2r(planScalarBack,scalarField_fourier,scalarField_real)
div = scalarField_real(1:cells(1),1:cells(2),1:cells3)*wgt
end subroutine utilities_fourierVectorDivergence end function utilities_VectorDivergence
!-------------------------------------------------------------------------------------------------- !--------------------------------------------------------------------------------------------------
@ -1046,11 +1025,19 @@ subroutine utilities_updateCoords(F)
step = geomSize/real(cells, pReal) step = geomSize/real(cells, pReal)
tensorField_real(1:3,1:3,1:cells(1), 1:cells(2),1:cells3) = F
tensorField_real(1:3,1:3,cells(1)+1:cells1Red*2,1:cells(2),1:cells3) = 0.0_pReal
call fftw_mpi_execute_dft_r2c(planTensorForth,tensorField_real,tensorField_fourier)
!--------------------------------------------------------------------------------------------------
! average F
if (cells3Offset == 0) Favg = tensorField_fourier(1:3,1:3,1,1,1)%re*wgt
call MPI_Bcast(Favg,9_MPI_INTEGER_KIND,MPI_DOUBLE,0_MPI_INTEGER_KIND,MPI_COMM_WORLD,err_MPI)
if (err_MPI /= 0_MPI_INTEGER_KIND) error stop 'MPI error'
!-------------------------------------------------------------------------------------------------- !--------------------------------------------------------------------------------------------------
! integration in Fourier space to get fluctuations of cell center discplacements ! integration in Fourier space to get fluctuations of cell center discplacements
tensorField_real(1:3,1:3,1:cells(1),1:cells(2),1:cells3) = F
call utilities_FFTtensorForward()
!$OMP PARALLEL DO !$OMP PARALLEL DO
do j = 1, cells2; do k = 1, cells(3); do i = 1, cells1Red do j = 1, cells2; do k = 1, cells(3); do i = 1, cells1Red
if (any([i,j+cells2Offset,k] /= 1)) then if (any([i,j+cells2Offset,k] /= 1)) then
@ -1062,13 +1049,8 @@ subroutine utilities_updateCoords(F)
end do; end do; end do end do; end do; end do
!$OMP END PARALLEL DO !$OMP END PARALLEL DO
call utilities_FFTvectorBackward() call fftw_mpi_execute_dft_c2r(planVectorBack,vectorField_fourier,vectorField_real)
vectorField_real = vectorField_real * wgt ! normalize the result by number of elements
!--------------------------------------------------------------------------------------------------
! average F
if (cells3Offset == 0) Favg = tensorField_fourier(1:3,1:3,1,1,1)%re*wgt
call MPI_Bcast(Favg,9_MPI_INTEGER_KIND,MPI_DOUBLE,0_MPI_INTEGER_KIND,MPI_COMM_WORLD,err_MPI)
if (err_MPI /= 0_MPI_INTEGER_KIND) error stop 'MPI error'
!-------------------------------------------------------------------------------------------------- !--------------------------------------------------------------------------------------------------
! pad cell center fluctuations along z-direction (needed when running MPI simulation) ! pad cell center fluctuations along z-direction (needed when running MPI simulation)
@ -1136,7 +1118,7 @@ subroutine utilities_saveReferenceStiffness()
open(newunit=fileUnit, file=getSolverJobName()//'.C_ref',& open(newunit=fileUnit, file=getSolverJobName()//'.C_ref',&
status='replace',access='stream',action='write',iostat=ierr) status='replace',access='stream',action='write',iostat=ierr)
if (ierr /=0) call IO_error(100,ext_msg='could not open file '//getSolverJobName()//'.C_ref') if (ierr /=0) call IO_error(100,ext_msg='could not open file '//getSolverJobName()//'.C_ref')
write(fileUnit) C_ref write(fileUnit) C_ref*wgt
close(fileUnit) close(fileUnit)
end if end if
@ -1156,38 +1138,38 @@ subroutine selfTest()
call random_number(tensorField_real) call random_number(tensorField_real)
tensorField_real(1:3,1:3,cells(1)+1:cells1Red*2,:,:) = 0.0_pReal tensorField_real(1:3,1:3,cells(1)+1:cells1Red*2,:,:) = 0.0_pReal
tensorField_real_ = tensorField_real tensorField_real_ = tensorField_real
call utilities_FFTtensorForward() call fftw_mpi_execute_dft_r2c(planTensorForth,tensorField_real,tensorField_fourier)
if (worldsize==1) then if (worldsize==1) then
if (any(dNeq(sum(sum(sum(tensorField_real_,dim=5),dim=4),dim=3)/tensorField_fourier(:,:,1,1,1)%re,1.0_pReal,1.0e-12_pReal))) & if (any(dNeq(sum(sum(sum(tensorField_real_,dim=5),dim=4),dim=3)/tensorField_fourier(:,:,1,1,1)%re,1.0_pReal,1.0e-12_pReal))) &
error stop 'tensorField avg' error stop 'tensorField avg'
endif endif
call utilities_FFTtensorBackward() call fftw_mpi_execute_dft_c2r(planTensorBack,tensorField_fourier,tensorField_real)
tensorField_real(1:3,1:3,cells(1)+1:cells1Red*2,:,:) = 0.0_pReal tensorField_real(1:3,1:3,cells(1)+1:cells1Red*2,:,:) = 0.0_pReal
if (maxval(abs(tensorField_real_ - tensorField_real))>5.0e-15_pReal) error stop 'tensorField' if (maxval(abs(tensorField_real_ - tensorField_real*wgt))>5.0e-15_pReal) error stop 'tensorField'
call random_number(vectorField_real) call random_number(vectorField_real)
vectorField_real(1:3,cells(1)+1:cells1Red*2,:,:) = 0.0_pReal vectorField_real(1:3,cells(1)+1:cells1Red*2,:,:) = 0.0_pReal
vectorField_real_ = vectorField_real vectorField_real_ = vectorField_real
call utilities_FFTvectorForward() call fftw_mpi_execute_dft_r2c(planVectorForth,vectorField_real,vectorField_fourier)
if (worldsize==1) then if (worldsize==1) then
if (any(dNeq(sum(sum(sum(vectorField_real_,dim=4),dim=3),dim=2)/vectorField_fourier(:,1,1,1)%re,1.0_pReal,1.0e-12_pReal))) & if (any(dNeq(sum(sum(sum(vectorField_real_,dim=4),dim=3),dim=2)/vectorField_fourier(:,1,1,1)%re,1.0_pReal,1.0e-12_pReal))) &
error stop 'vector avg' error stop 'vector avg'
endif endif
call utilities_FFTvectorBackward() call fftw_mpi_execute_dft_c2r(planVectorBack,vectorField_fourier,vectorField_real)
vectorField_real(1:3,cells(1)+1:cells1Red*2,:,:) = 0.0_pReal vectorField_real(1:3,cells(1)+1:cells1Red*2,:,:) = 0.0_pReal
if (maxval(abs(vectorField_real_ - vectorField_real))>5.0e-15_pReal) error stop 'vectorField' if (maxval(abs(vectorField_real_ - vectorField_real*wgt))>5.0e-15_pReal) error stop 'vectorField'
call random_number(scalarField_real) call random_number(scalarField_real)
scalarField_real(cells(1)+1:cells1Red*2,:,:) = 0.0_pReal scalarField_real(cells(1)+1:cells1Red*2,:,:) = 0.0_pReal
scalarField_real_ = scalarField_real scalarField_real_ = scalarField_real
call utilities_FFTscalarForward() call fftw_mpi_execute_dft_r2c(planScalarForth,scalarField_real,scalarField_fourier)
if (worldsize==1) then if (worldsize==1) then
if (dNeq(sum(sum(sum(scalarField_real_,dim=3),dim=2),dim=1)/scalarField_fourier(1,1,1)%re,1.0_pReal,1.0e-12_pReal)) & if (dNeq(sum(sum(sum(scalarField_real_,dim=3),dim=2),dim=1)/scalarField_fourier(1,1,1)%re,1.0_pReal,1.0e-12_pReal)) &
error stop 'scalar avg' error stop 'scalar avg'
endif endif
call utilities_FFTscalarBackward() call fftw_mpi_execute_dft_c2r(planScalarBack,scalarField_fourier,scalarField_real)
scalarField_real(cells(1)+1:cells1Red*2,:,:) = 0.0_pReal scalarField_real(cells(1)+1:cells1Red*2,:,:) = 0.0_pReal
if (maxval(abs(scalarField_real_ - scalarField_real))>5.0e-15_pReal) error stop 'scalarField' if (maxval(abs(scalarField_real_ - scalarField_real*wgt))>5.0e-15_pReal) error stop 'scalarField'
end subroutine selfTest end subroutine selfTest

View File

@ -9,8 +9,8 @@ submodule(phase:eigen) thermalexpansion
type :: tParameters type :: tParameters
type(tPolynomial) :: & type(tPolynomial) :: &
A_11, & Alpha_11, &
A_33 Alpha_33
end type tParameters end type tParameters
type(tParameters), dimension(:), allocatable :: param type(tParameters), dimension(:), allocatable :: param
@ -57,9 +57,9 @@ module function thermalexpansion_init(kinematics_length) result(myKinematics)
if (myKinematics(k,p)) then if (myKinematics(k,p)) then
associate(prm => param(kinematics_thermal_expansion_instance(p))) associate(prm => param(kinematics_thermal_expansion_instance(p)))
prm%A_11 = polynomial(kinematics%get_dict(k),'A_11','T') prm%Alpha_11 = polynomial(kinematics%get_dict(k),'Alpha_11','T')
if (any(phase_lattice(p) == ['hP','tI'])) & if (any(phase_lattice(p) == ['hP','tI'])) &
prm%A_33 = polynomial(kinematics%get_dict(k),'A_33','T') prm%Alpha_33 = polynomial(kinematics%get_dict(k),'Alpha_33','T')
end associate end associate
end if end if
end do end do
@ -80,7 +80,7 @@ module subroutine thermalexpansion_LiAndItsTangent(Li, dLi_dTstar, ph,me)
dLi_dTstar !< derivative of Li with respect to Tstar (4th-order tensor defined to be zero) dLi_dTstar !< derivative of Li with respect to Tstar (4th-order tensor defined to be zero)
real(pReal) :: T, dot_T real(pReal) :: T, dot_T
real(pReal), dimension(3,3) :: A real(pReal), dimension(3,3) :: Alpha
T = thermal_T(ph,me) T = thermal_T(ph,me)
@ -88,11 +88,11 @@ module subroutine thermalexpansion_LiAndItsTangent(Li, dLi_dTstar, ph,me)
associate(prm => param(kinematics_thermal_expansion_instance(ph))) associate(prm => param(kinematics_thermal_expansion_instance(ph)))
A = 0.0_pReal Alpha = 0.0_pReal
A(1,1) = prm%A_11%at(T) Alpha(1,1) = prm%Alpha_11%at(T)
if (any(phase_lattice(ph) == ['hP','tI'])) A(3,3) = prm%A_33%at(T) if (any(phase_lattice(ph) == ['hP','tI'])) Alpha(3,3) = prm%Alpha_33%at(T)
A = lattice_symmetrize_33(A,phase_lattice(ph)) Alpha = lattice_symmetrize_33(Alpha,phase_lattice(ph))
Li = dot_T * A Li = dot_T * Alpha
end associate end associate
dLi_dTstar = 0.0_pReal dLi_dTstar = 0.0_pReal

View File

@ -45,17 +45,17 @@ module subroutine elastic_init(phases)
associate(prm => param(ph)) associate(prm => param(ph))
prm%C_11 = polynomial(elastic%asDict(),'C_11','T') prm%C_11 = polynomial(elastic,'C_11','T')
prm%C_12 = polynomial(elastic%asDict(),'C_12','T') prm%C_12 = polynomial(elastic,'C_12','T')
prm%C_44 = polynomial(elastic%asDict(),'C_44','T') prm%C_44 = polynomial(elastic,'C_44','T')
if (any(phase_lattice(ph) == ['hP','tI'])) then if (any(phase_lattice(ph) == ['hP','tI'])) then
prm%C_13 = polynomial(elastic%asDict(),'C_13','T') prm%C_13 = polynomial(elastic,'C_13','T')
prm%C_33 = polynomial(elastic%asDict(),'C_33','T') prm%C_33 = polynomial(elastic,'C_33','T')
end if end if
if (phase_lattice(ph) == 'tI') & if (phase_lattice(ph) == 'tI') &
prm%C_66 = polynomial(elastic%asDict(),'C_66','T') prm%C_66 = polynomial(elastic,'C_66','T')
end associate end associate
end do end do

View File

@ -303,7 +303,7 @@ module function plastic_dislotwin_init() result(myPlasticity)
prm%b_tr = math_expand(prm%b_tr,prm%N_tr) prm%b_tr = math_expand(prm%b_tr,prm%N_tr)
prm%i_tr = pl%get_asFloat('i_tr') prm%i_tr = pl%get_asFloat('i_tr')
prm%Delta_G = polynomial(pl%asDict(),'Delta_G','T') prm%Delta_G = polynomial(pl,'Delta_G','T')
prm%L_tr = pl%get_asFloat('L_tr') prm%L_tr = pl%get_asFloat('L_tr')
a_cF = prm%b_tr(1)*sqrt(6.0_pReal) ! b_tr is Shockley partial a_cF = prm%b_tr(1)*sqrt(6.0_pReal) ! b_tr is Shockley partial
prm%h = 5.0_pReal * a_cF/sqrt(3.0_pReal) prm%h = 5.0_pReal * a_cF/sqrt(3.0_pReal)
@ -361,7 +361,7 @@ module function plastic_dislotwin_init() result(myPlasticity)
end if end if
if (prm%sum_N_tw + prm%sum_N_tr > 0 .or. prm%extendedDislocations) & if (prm%sum_N_tw + prm%sum_N_tr > 0 .or. prm%extendedDislocations) &
prm%Gamma_sf = polynomial(pl%asDict(),'Gamma_sf','T') prm%Gamma_sf = polynomial(pl,'Gamma_sf','T')
slipAndTwinActive: if (prm%sum_N_sl * prm%sum_N_tw > 0) then slipAndTwinActive: if (prm%sum_N_sl * prm%sum_N_tw > 0) then
prm%h_sl_tw = lattice_interaction_SlipByTwin(N_sl,prm%N_tw,pl%get_as1dFloat('h_sl-tw'), & prm%h_sl_tw = lattice_interaction_SlipByTwin(N_sl,prm%N_tw,pl%get_as1dFloat('h_sl-tw'), &

View File

@ -157,7 +157,7 @@ subroutine selfTest()
'C,T^4: '//trim(adjustl(coef_s(5)))//IO_EOL//& 'C,T^4: '//trim(adjustl(coef_s(5)))//IO_EOL//&
'T_ref: '//trim(adjustl(x_ref_s))//IO_EOL 'T_ref: '//trim(adjustl(x_ref_s))//IO_EOL
dict => YAML_parse_str_asDict(trim(YAML_s)) dict => YAML_parse_str_asDict(trim(YAML_s))
p2 = polynomial(dict%asDict(),'C','T') p2 = polynomial(dict,'C','T')
if (dNeq(p1%at(x),p2%at(x),1.0e-6_pReal)) error stop 'polynomials: init' if (dNeq(p1%at(x),p2%at(x),1.0e-6_pReal)) error stop 'polynomials: init'
y = coef(1)+coef(2)*(x-x_ref)+coef(3)*(x-x_ref)**2+coef(4)*(x-x_ref)**3+coef(5)*(x-x_ref)**4 y = coef(1)+coef(2)*(x-x_ref)+coef(3)*(x-x_ref)**2+coef(4)*(x-x_ref)**3+coef(5)*(x-x_ref)**4
if (dNeq(p1%at(x),y,1.0e-6_pReal)) error stop 'polynomials: eval(full)' if (dNeq(p1%at(x),y,1.0e-6_pReal)) error stop 'polynomials: eval(full)'
@ -166,28 +166,28 @@ subroutine selfTest()
'C,T: '//trim(adjustl(coef_s(2)))//IO_EOL//& 'C,T: '//trim(adjustl(coef_s(2)))//IO_EOL//&
'T_ref: '//trim(adjustl(x_ref_s))//IO_EOL 'T_ref: '//trim(adjustl(x_ref_s))//IO_EOL
dict => YAML_parse_str_asDict(trim(YAML_s)) dict => YAML_parse_str_asDict(trim(YAML_s))
p1 = polynomial(dict%asDict(),'C','T') p1 = polynomial(dict,'C','T')
if (dNeq(p1%at(x_ref+x),-p1%at(x_ref-x),1.0e-10_pReal)) error stop 'polynomials: eval(linear)' if (dNeq(p1%at(x_ref+x),-p1%at(x_ref-x),1.0e-10_pReal)) error stop 'polynomials: eval(linear)'
YAML_s = 'C: 0.0'//IO_EOL//& YAML_s = 'C: 0.0'//IO_EOL//&
'C,T^2: '//trim(adjustl(coef_s(3)))//IO_EOL//& 'C,T^2: '//trim(adjustl(coef_s(3)))//IO_EOL//&
'T_ref: '//trim(adjustl(x_ref_s))//IO_EOL 'T_ref: '//trim(adjustl(x_ref_s))//IO_EOL
dict => YAML_parse_str_asDict(trim(YAML_s)) dict => YAML_parse_str_asDict(trim(YAML_s))
p1 = polynomial(dict%asDict(),'C','T') p1 = polynomial(dict,'C','T')
if (dNeq(p1%at(x_ref+x),p1%at(x_ref-x),1e-10_pReal)) error stop 'polynomials: eval(quadratic)' if (dNeq(p1%at(x_ref+x),p1%at(x_ref-x),1e-10_pReal)) error stop 'polynomials: eval(quadratic)'
YAML_s = 'Y: '//trim(adjustl(coef_s(1)))//IO_EOL//& YAML_s = 'Y: '//trim(adjustl(coef_s(1)))//IO_EOL//&
'Y,X^3: '//trim(adjustl(coef_s(2)))//IO_EOL//& 'Y,X^3: '//trim(adjustl(coef_s(2)))//IO_EOL//&
'X_ref: '//trim(adjustl(x_ref_s))//IO_EOL 'X_ref: '//trim(adjustl(x_ref_s))//IO_EOL
dict => YAML_parse_str_asDict(trim(YAML_s)) dict => YAML_parse_str_asDict(trim(YAML_s))
p1 = polynomial(dict%asDict(),'Y','X') p1 = polynomial(dict,'Y','X')
if (dNeq(p1%at(x_ref+x)-coef(1),-(p1%at(x_ref-x)-coef(1)),1.0e-8_pReal)) error stop 'polynomials: eval(cubic)' if (dNeq(p1%at(x_ref+x)-coef(1),-(p1%at(x_ref-x)-coef(1)),1.0e-8_pReal)) error stop 'polynomials: eval(cubic)'
YAML_s = 'Y: '//trim(adjustl(coef_s(1)))//IO_EOL//& YAML_s = 'Y: '//trim(adjustl(coef_s(1)))//IO_EOL//&
'Y,X^4: '//trim(adjustl(coef_s(2)))//IO_EOL//& 'Y,X^4: '//trim(adjustl(coef_s(2)))//IO_EOL//&
'X_ref: '//trim(adjustl(x_ref_s))//IO_EOL 'X_ref: '//trim(adjustl(x_ref_s))//IO_EOL
dict => YAML_parse_str_asDict(trim(YAML_s)) dict => YAML_parse_str_asDict(trim(YAML_s))
p1 = polynomial(dict%asDict(),'Y','X') p1 = polynomial(dict,'Y','X')
if (dNeq(p1%at(x_ref+x),p1%at(x_ref-x),1.0e-6_pReal)) error stop 'polynomials: eval(quartic)' if (dNeq(p1%at(x_ref+x),p1%at(x_ref-x),1.0e-6_pReal)) error stop 'polynomials: eval(quartic)'