├── docs ├── SOD.md └── images │ ├── SOD.png │ ├── TBL.png │ ├── naca.png │ ├── Advection.png │ ├── Euler2D.png │ ├── TGvortex.png │ ├── cylinder.png │ ├── pressure.png │ └── directivity.png ├── pyranda ├── parcop │ ├── fexl │ ├── __init__.py │ ├── undo_fexl │ ├── ompsync.f90 │ ├── vendor.sh │ ├── nrtype.f90 │ ├── scripts │ │ ├── make-funroll.py │ │ └── FEXL-README.md │ ├── test_pent.f90 │ └── makefile ├── __init__.py ├── pyrandaPackage.py ├── latex_template.tex ├── pyrandaEq.py ├── pyrandaProbes.py ├── pyrandaTimestep.py ├── pyrandaEllipticalFFT.py ├── pyrandaVar.py └── pyrandaUtils.py ├── requirements.txt ├── .gitignore ├── tests ├── cases │ ├── testRT.py │ ├── testShuOsher.py │ ├── testTaylorGreen.py │ ├── testUnit.py │ ├── testElliptic.py │ ├── testHeat1D.py │ ├── test1DAdvection.py │ ├── testCylinder.py │ ├── testIntegration.py │ ├── testMM_simple.py │ └── test2deuler.py ├── baselines │ ├── cylinder-2d-32.dat │ ├── cavity-2d-32.dat │ ├── RT_2D.dat │ ├── cylinder-2d-64.dat │ ├── euler-2d-64.dat │ ├── KelvinHelmholtzKH-2d-64.dat │ ├── cylinder_curved-2d-64.dat │ ├── cylinder_omesh-2d-64.dat │ ├── cavity-2d-64.dat │ └── euler-2d-128.dat ├── testObj.py └── run_tests.py ├── .travis.yml ├── examples ├── simple.py ├── tutorials │ ├── Advection1D.py │ ├── SOD.py │ ├── Euler2D.py │ └── cylinder.py ├── poisson.py ├── meshTest.py ├── TBL_data │ ├── vvmean.dat │ ├── uumean.dat │ ├── umean.dat │ ├── wwmean.dat │ └── uvmean.dat ├── intTest.py ├── grid_conv.py ├── shallow_water.py ├── curv_advect.py ├── SOD.py ├── heat1D.py ├── mesh.py ├── elliptical.py ├── advection.py ├── cavity.py ├── SOD_leos.py ├── eulerRZ.py ├── shu_osher.py ├── unit_test.py ├── interface2.py ├── euler.py ├── cylinder.py ├── eulerSpherical.py ├── TBL3D.py ├── TaylorGreen.py ├── KH.py ├── interface.py └── 3Dadvect.py ├── .github ├── scripts │ └── install-mpi.sh └── workflows │ └── regression-tests.yaml ├── NOTICE ├── README.md └── INSTALL.md /docs/SOD.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /pyranda/parcop/fexl: -------------------------------------------------------------------------------- 1 | python scripts/make-funroll.py 1 -------------------------------------------------------------------------------- /pyranda/parcop/__init__.py: -------------------------------------------------------------------------------- 1 | from .parcop import parcop 2 | -------------------------------------------------------------------------------- /pyranda/parcop/undo_fexl: -------------------------------------------------------------------------------- 1 | python scripts/make-funroll.py 2 -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | matplotlib 2 | numpy<2 3 | scipy 4 | mpi4py 5 | -------------------------------------------------------------------------------- /docs/images/SOD.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LLNL/pyranda/HEAD/docs/images/SOD.png -------------------------------------------------------------------------------- /docs/images/TBL.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LLNL/pyranda/HEAD/docs/images/TBL.png -------------------------------------------------------------------------------- /docs/images/naca.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LLNL/pyranda/HEAD/docs/images/naca.png -------------------------------------------------------------------------------- /docs/images/Advection.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LLNL/pyranda/HEAD/docs/images/Advection.png -------------------------------------------------------------------------------- /docs/images/Euler2D.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LLNL/pyranda/HEAD/docs/images/Euler2D.png -------------------------------------------------------------------------------- /docs/images/TGvortex.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LLNL/pyranda/HEAD/docs/images/TGvortex.png -------------------------------------------------------------------------------- /docs/images/cylinder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LLNL/pyranda/HEAD/docs/images/cylinder.png -------------------------------------------------------------------------------- /docs/images/pressure.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LLNL/pyranda/HEAD/docs/images/pressure.png -------------------------------------------------------------------------------- /docs/images/directivity.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LLNL/pyranda/HEAD/docs/images/directivity.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.mod 2 | pyranda/parcop/test_pent 3 | build 4 | pyranda.egg-info 5 | *.pyc 6 | *.o 7 | *.so 8 | *.a 9 | -------------------------------------------------------------------------------- /pyranda/parcop/ompsync.f90: -------------------------------------------------------------------------------- 1 | module LES_ompsync 2 | 3 | implicit none 4 | integer :: sync_var 5 | 6 | 7 | end module LES_ompsync 8 | -------------------------------------------------------------------------------- /tests/cases/testRT.py: -------------------------------------------------------------------------------- 1 | # Copy and paste baselines here 2 | baselines = """ 3 | RT_2D -- RT_2D.dat 4 | """ 5 | 6 | # Update dictionary of baseline scalars 7 | dbase.update( baseDict( baselines) ) 8 | 9 | script = 'examples/RT3D.py' 10 | 11 | test = testObj('RT_2D') 12 | test.script = script 13 | test.args = ['32','1','1'] # Size, 2d?, test 14 | tests.append( test ) 15 | -------------------------------------------------------------------------------- /tests/cases/testShuOsher.py: -------------------------------------------------------------------------------- 1 | # Copy and paste baselines here 2 | baselines = """ 3 | shu-osher-CR -- 1.8474038265057673 4 | """ 5 | 6 | # Update dictionary of baseline scalars 7 | dbase.update( baseDict( baselines) ) 8 | 9 | test = testObj('shu-osher-CR') 10 | test.script = 'examples/shu_osher.py' 11 | test.args = ['1'] 12 | tests.append( test ) 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /tests/cases/testTaylorGreen.py: -------------------------------------------------------------------------------- 1 | # Copy and paste baselines here 2 | baselines = """ 3 | taylorgreen -- 1.00106718415 4 | """ 5 | 6 | # Update dictionary of baseline scalars 7 | dbase.update( baseDict( baselines) ) 8 | 9 | script = 'examples/TaylorGreen.py' 10 | 11 | test = testObj('taylorgreen') 12 | test.script = script 13 | test.args = ['32','1'] 14 | tests.append( test ) 15 | 16 | -------------------------------------------------------------------------------- /tests/cases/testUnit.py: -------------------------------------------------------------------------------- 1 | # Copy and paste baselines here 2 | baselines = """ 3 | unit-test-3D -- 0.017490746954566275 4 | """ 5 | 6 | # Update dictionary of baseline scalars 7 | dbase.update( baseDict( baselines) ) 8 | relE.update( relDict( baselines) ) 9 | 10 | test = testObj('unit-test-3D') 11 | test.script = 'examples/unit_test.py' 12 | test.args = [] 13 | tests.append( test ) 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /pyranda/__init__.py: -------------------------------------------------------------------------------- 1 | from .pyranda import pyrandaSim 2 | from .pyrandaIBM import pyrandaIBM 3 | from .pyrandaTimestep import pyrandaTimestep 4 | from .pyrandaBC import pyrandaBC 5 | from .pyrandaProbes import pyrandaProbes 6 | from .pyrandaTBL import pyrandaTBL 7 | from .pyrandaRANSBOX import pyrandaRANSBOX 8 | from .pyrandaLEOS import pyrandaLEOS 9 | from .pyrandaEllipticalFFT import pyrandaPoissonFFT 10 | from .pyrandaElliptical import pyrandaPoisson 11 | from .pyranda import pyrandaRestart 12 | from .pyrandaMirandaReader import mirandaReader 13 | -------------------------------------------------------------------------------- /tests/cases/testElliptic.py: -------------------------------------------------------------------------------- 1 | # Copy and paste baselines here 2 | baselines = """ 3 | cavity-2d-32 -- cavity-2d-32.dat 4 | cavity-2d-64 -- cavity-2d-64.dat 5 | """ 6 | 7 | 8 | # Update dictionary of baseline scalars 9 | dbase.update( baseDict( baselines) ) 10 | 11 | script = 'examples/cavity.py' 12 | 13 | test = testObj('cavity-2d-32') 14 | test.script = script 15 | test.args = ['32','1',test.name] 16 | tests.append( test ) 17 | 18 | test = testObj('cavity-2d-64') 19 | test.script = script 20 | test.args = ['64','1',test.name] 21 | tests.append( test ) 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /tests/cases/testHeat1D.py: -------------------------------------------------------------------------------- 1 | # Copy and paste baselines here 2 | baselines = """ 3 | heat1D-analytic-16 -- 0.0 4 | heat1D-analytic-32 -- 0.0 5 | heat1D-analytic-64 -- 0.0 6 | heat1D-analytic-128 -- 0.0 7 | heat1D-analytic-256 -- 0.0 8 | """ 9 | 10 | # Update dictionary of baseline scalars 11 | dbase.update( baseDict( baselines) ) 12 | relE.update( relDict( baselines) ) 13 | 14 | # Run a bunch of resolutions for the analytical heat transfer problem 15 | for npts in [16,32,64,128,256]: 16 | test = testObj('heat1D-analytic-%s' % npts) 17 | test.script = 'examples/heat1D.py' 18 | test.args = ['%s' % npts,'1'] 19 | tests.append( test ) 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | 3 | python: 4 | - "2.7" 5 | - "3.5" 6 | - "3.6" 7 | 8 | os: 9 | - linux 10 | 11 | env: 12 | - MPI=mpich 13 | - MPI=openmpi 14 | 15 | addons: 16 | apt: 17 | packages: 18 | - gfortran 19 | 20 | cache: 21 | directories: 22 | - openmpi 23 | - mpich 24 | 25 | before_install: 26 | - ./github/scripts/install-mpi.sh $MPI 27 | - export PATH=$(pwd)/${MPI}/bin:${PATH} 28 | - export LD_LIBRARY_PATH=$(pwd)/${MPI}/lib:${LD_LIBRARY_PATH} 29 | 30 | install: 31 | - pip install -r requirements.txt 32 | - python setup.py build 33 | - python setup.py install 34 | 35 | script: 36 | - cd tests && python run_tests.py 1 37 | -------------------------------------------------------------------------------- /pyranda/parcop/vendor.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | default=default 4 | 5 | info=$($1 --version 2>/dev/null) 6 | # += because certain compilers return non-0 status with --version 7 | test $? -ne 0 && info+=$($1 -qversion 2>/dev/null) || true 8 | test $? -ne 0 && { echo "unknown compiler"; exit 0; } || true 9 | 10 | echo $info | grep -i "intel" > /dev/null && { echo "intel"; exit 0; } 11 | echo $info | grep -i "ibm" > /dev/null && { echo "ibm"; exit 0; } 12 | echo $info | grep -i "pgi" > /dev/null && { echo "pgi"; exit 0; } 13 | echo $info | grep -i "clang" > /dev/null && { echo "clang"; exit 0; } 14 | echo $info | grep -iE "gnu|gcc" > /dev/null && { echo "gnu"; exit 0; } 15 | 16 | echo $default 17 | -------------------------------------------------------------------------------- /examples/simple.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import time 3 | import numpy 4 | import matplotlib.pyplot as plt 5 | from pyranda import pyrandaSim 6 | 7 | # Define the domain/mesh 8 | domain = "xdom = (0.0 , 1.0 , 100 )" 9 | 10 | # Initialize a simulation object on a mesh 11 | pysim = pyrandaSim('advection',domain) 12 | 13 | # Define the equations of motion 14 | pysim.EOM(" ddt(:phi:) = -:c: * ddx(:phi:) ") 15 | 16 | # Initialize variables 17 | ic = """ 18 | :phi: = 1.0 + 0.1 * exp( -(abs(meshx-.5)/.1 )**2 ) 19 | :phi0: = :phi: 20 | :c: = 1.0 21 | """ 22 | pysim.setIC(ic) 23 | 24 | # Integrate in time 25 | dt = .001 26 | time = 0.0 27 | while time < .1: 28 | time = pysim.rk4(time,dt) 29 | 30 | 31 | # Plot the initial/final solution 32 | x = pysim.mesh.coords[0].data 33 | phi = pysim.variables['phi'].data 34 | phi0 = pysim.variables['phi0'].data 35 | plt.plot(x[:,0,0],phi[:,0,0] ,'k.-') 36 | plt.plot(x[:,0,0],phi0[:,0,0] ,'b-') 37 | plt.show() 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /pyranda/pyrandaPackage.py: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | # Copyright (c) 2018, Lawrence Livemore National Security, LLC. 3 | # Produced at the Lawrence Livermore National Laboratory. 4 | # 5 | # LLNL-CODE-749864 6 | # This file is part of pyranda 7 | # For details about use and distribution, please read: pyranda/LICENSE 8 | # 9 | # Written by: Britton J. Olson, olson45@llnl.gov 10 | ################################################################################ 11 | 12 | 13 | class pyrandaPackage: 14 | """ 15 | Case physics package module for adding new physics packages to pyranda 16 | """ 17 | def __init__(self,name,pyranda): 18 | 19 | self.name = name 20 | self.pyranda = pyranda 21 | 22 | 23 | def get_sMap(self): 24 | """ 25 | String mappings for this package. Packages added to the main 26 | pyranda object will check this map 27 | """ 28 | sMap = {} 29 | self.sMap = sMap 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /tests/cases/test1DAdvection.py: -------------------------------------------------------------------------------- 1 | # Copy and paste baselines here 2 | baselines = """ 3 | advec-1d-50 -- 9.65612670412e-09 4 | advec-1d-100 -- 7.6111541815e-11 5 | advec-1d-200 -- 5.93285138337e-13 6 | advec-1d-300 -- 3.47125615129e-14 7 | advec-1d-400 -- 4.63496183249e-15 8 | """ 9 | 10 | # Update dictionary of baseline scalars 11 | dbase.update( baseDict( baselines) ) 12 | 13 | test = testObj('advec-1d-50') 14 | test.script = 'examples/advection.py' 15 | test.args = ['50','1'] 16 | tests.append( test ) 17 | 18 | test = testObj('advec-1d-100') 19 | test.script = 'examples/advection.py' 20 | test.args = ['100','1'] 21 | tests.append( test ) 22 | 23 | test = testObj('advec-1d-200') 24 | test.script = 'examples/advection.py' 25 | test.args = ['200','1'] 26 | tests.append( test ) 27 | 28 | test = testObj('advec-1d-300') 29 | test.script = 'examples/advection.py' 30 | test.args = ['300','1'] 31 | tests.append( test ) 32 | 33 | test = testObj('advec-1d-400') 34 | test.script = 'examples/advection.py' 35 | test.args = ['400','1'] 36 | tests.append( test ) 37 | 38 | 39 | -------------------------------------------------------------------------------- /tests/cases/testCylinder.py: -------------------------------------------------------------------------------- 1 | # Copy and paste baselines here 2 | baselines = """ 3 | cylinder-2d-32 -- cylinder-2d-32.dat 4 | cylinder-2d-64 -- cylinder-2d-64.dat 5 | cylinder_curved-2d-64 -- cylinder_curved-2d-64.dat 6 | cylinder_omesh-2d-64 -- cylinder_omesh-2d-64.dat 7 | """ 8 | 9 | # Update dictionary of baseline scalars 10 | dbase.update( baseDict( baselines) ) 11 | 12 | script = 'examples/cylinder.py' 13 | 14 | test = testObj('cylinder-2d-32') 15 | test.script = script 16 | test.args = ['32','1',test.name] 17 | tests.append( test ) 18 | 19 | test = testObj('cylinder-2d-64') 20 | test.script = script 21 | test.args = ['64','1',test.name] 22 | tests.append( test ) 23 | 24 | 25 | script = 'examples/cylinder_curv.py' 26 | 27 | test = testObj('cylinder_curved-2d-64') 28 | test.script = script 29 | test.args = ['64','1',test.name] 30 | tests.append( test ) 31 | 32 | 33 | script = 'examples/cylinder_curv2.py' 34 | 35 | test = testObj('cylinder_omesh-2d-64') 36 | test.script = script 37 | test.args = ['64','1',test.name] 38 | tests.append( test ) 39 | 40 | 41 | -------------------------------------------------------------------------------- /.github/scripts/install-mpi.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | install_dir=$2 4 | test -e ${install_dir}/lib/libmpi.so && { echo "$1 already installed"; exit 0; } 5 | 6 | case "$1" in 7 | mpich-*) 8 | # https://www.mpich.org/static/downloads/3.3.2/mpich-3.3.2.tar.gz 9 | # https://www.mpich.org/static/downloads/3.4/mpich-3.4.tar.gz 10 | ver="$(echo $1 | cut -d- -f2)" 11 | wget http://www.mpich.org/static/downloads/${ver}/${1}.tar.gz 12 | tar -xzf ${1}.tar.gz 13 | cd $1 14 | ./configure --prefix=$install_dir --with-device=ch3 FFLAGS=-fallow-argument-mismatch 15 | make -j4 16 | make install 17 | ;; 18 | 19 | openmpi-*) 20 | # https://download.open-mpi.org/release/open-mpi/v4.1/openmpi-4.1.1.tar.gz 21 | ver="$(echo $1 | cut -d- -f2 | cut -d. -f1,2)" 22 | wget https://download.open-mpi.org/release/open-mpi/v${ver}/${1}.tar.gz 23 | tar -xzf ${1}.tar.gz 24 | cd $1 25 | ./configure --prefix=$install_dir 26 | make -j4 27 | make install 28 | ;; 29 | 30 | *) 31 | echo "unknown mpi: '$1'" 32 | exit 1 33 | ;; 34 | esac 35 | -------------------------------------------------------------------------------- /tests/cases/testIntegration.py: -------------------------------------------------------------------------------- 1 | # Copy and paste baselines here 2 | baselines = """ 3 | integration-25 -- 2.19857470896e-07 4 | integration-50 -- 2.70774644928e-08 5 | integration-100 -- 3.35909833282e-09 6 | integration-200 -- 4.18383105938e-10 7 | integration-400 -- 5.12416775678e-11 8 | """ 9 | 10 | # Update dictionary of baseline scalars 11 | dbase.update( baseDict( baselines) ) 12 | 13 | 14 | test = testObj('integration-25') 15 | test.script = 'examples/intTest.py' 16 | test.args = ['25','1'] 17 | tests.append( test ) 18 | 19 | test = testObj('integration-50') 20 | test.script = 'examples/intTest.py' 21 | test.args = ['50','1'] 22 | tests.append( test ) 23 | 24 | test = testObj('integration-100') 25 | test.script = 'examples/intTest.py' 26 | test.args = ['100','1'] 27 | tests.append( test ) 28 | 29 | test = testObj('integration-200') 30 | test.script = 'examples/intTest.py' 31 | test.args = ['200','1'] 32 | tests.append( test ) 33 | 34 | test = testObj('integration-400') 35 | test.script = 'examples/intTest.py' 36 | test.args = ['400','1'] 37 | tests.append( test ) 38 | 39 | 40 | -------------------------------------------------------------------------------- /examples/tutorials/Advection1D.py: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | # Copyright (c) 2018, Lawrence Livemore National Security, LLC. 3 | # Produced at the Lawrence Livermore National Laboratory. 4 | # 5 | # LLNL-CODE-749864 6 | # This file is part of pyranda 7 | # For details about use and distribution, please read: pyranda/LICENSE 8 | # 9 | # Written by: Britton J. Olson, olson45@llnl.gov 10 | ################################################################################ 11 | 12 | from pyranda import pyrandaSim 13 | 14 | # Define the domain/mesh 15 | domain = "xdom = (0.0 , 1.0 , 100 )" 16 | 17 | # Initialize a simulation object on a mesh 18 | pysim = pyrandaSim('advection',domain) 19 | 20 | # Define the equations of motion 21 | pysim.EOM("ddt(:phi:) = - ddx(:phi:)") 22 | 23 | # Initialize variables 24 | pysim.setIC(":phi: = 1.0 + 0.1 * exp( -(abs(meshx-.5)/.1 )**2 )") 25 | 26 | # Integrate in time 27 | dt = .001 28 | time = 0.0 29 | while time < .1: 30 | time = pysim.rk4(time,dt) 31 | 32 | # Plot solution 33 | pysim.plot.plot('phi') 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | This work was produced under the auspices of the U.S. Department of Energy by 2 | Lawrence Livermore National Laboratory under Contract DE-AC52-07NA27344. 3 | 4 | This work was prepared as an account of work sponsored by an agency of the 5 | United States Government. Neither the United States Government nor Lawrence 6 | Livermore National Security, LLC, nor any of their employees makes any warranty, 7 | expressed or implied, or assumes any legal liability or responsibility for the 8 | accuracy, completeness, or usefulness of any information, apparatus, product, or 9 | process disclosed, or represents that its use would not infringe privately owned 10 | rights. Reference herein to any specific commercial product, process, or service 11 | by trade name, trademark, manufacturer, or otherwise does not necessarily 12 | constitute or imply its endorsement, recommendation, or favoring by the United 13 | States Government or Lawrence Livermore National Security, LLC. The views and 14 | opinions of authors expressed herein do not necessarily state or reflect those 15 | of the United States Government or Lawrence Livermore National Security, LLC, 16 | and shall not be used for advertising or product endorsement purposes. -------------------------------------------------------------------------------- /tests/cases/testMM_simple.py: -------------------------------------------------------------------------------- 1 | # Copy and paste baselines here 2 | baselines = """ 3 | MM-adv1d-50-d -- -30.6887885339 4 | MM-adv1d-100-d -- -0.816951930754 5 | MM-adv1d-200-d -- 0.996534886127 6 | MM-adv1d-50 -- 1.0 7 | MM-adv1d-100 -- 1.0 8 | MM-adv1d-200 -- 1.0 9 | """ 10 | 11 | # Update dictionary of baseline scalars 12 | dbase.update( baseDict( baselines) ) 13 | 14 | test = testObj('MM-adv1d-50-d') 15 | test.script = 'examples/interface.py' 16 | test.args = ['50','1','1'] 17 | tests.append( test ) 18 | 19 | test = testObj('MM-adv1d-100-d') 20 | test.script = 'examples/interface.py' 21 | test.args = ['100','1','1'] 22 | tests.append( test ) 23 | 24 | test = testObj('MM-adv1d-200-d') 25 | test.script = 'examples/interface.py' 26 | test.args = ['200','1','1'] 27 | tests.append( test ) 28 | 29 | 30 | 31 | 32 | test = testObj('MM-adv1d-50') 33 | test.script = 'examples/interface.py' 34 | test.args = ['50','1','0'] 35 | tests.append( test ) 36 | 37 | test = testObj('MM-adv1d-100') 38 | test.script = 'examples/interface.py' 39 | test.args = ['100','1','0'] 40 | tests.append( test ) 41 | 42 | test = testObj('MM-adv1d-200') 43 | test.script = 'examples/interface.py' 44 | test.args = ['200','1','0'] 45 | tests.append( test ) 46 | 47 | 48 | -------------------------------------------------------------------------------- /tests/cases/test2deuler.py: -------------------------------------------------------------------------------- 1 | # Copy and paste baselines here 2 | baselines = """ 3 | euler-2d-64 -- euler-2d-64.dat 4 | euler-2d-128 -- euler-2d-128.dat 5 | euler-RZ-128 -- euler-RZ-128.dat 6 | euler-SPH-1D -- euler-SPH-1D.dat 7 | euler-SPH-2D -- euler-SPH-2D.dat 8 | KH-2d-64 -- KelvinHelmholtzKH-2d-64.dat 9 | """ 10 | 11 | # Update dictionary of baseline scalars 12 | dbase.update( baseDict( baselines) ) 13 | 14 | test = testObj('euler-2d-64') 15 | test.script = 'examples/euler.py' 16 | test.args = ['64','1',test.name] 17 | tests.append( test ) 18 | 19 | test = testObj('euler-2d-128') 20 | test.script = 'examples/euler.py' 21 | test.args = ['128','1',test.name] 22 | tests.append( test ) 23 | 24 | test = testObj('euler-RZ-128') 25 | test.script = 'examples/eulerRZ.py' 26 | test.args = ['128','1',test.name] 27 | tests.append( test ) 28 | 29 | test = testObj('euler-SPH-1D') 30 | test.script = 'examples/eulerSpherical1D.py' 31 | test.args = ['128','1',test.name] 32 | tests.append( test ) 33 | 34 | test = testObj('euler-SPH-2D') 35 | test.script = 'examples/eulerSpherical.py' 36 | test.args = ['32','1',test.name] 37 | tests.append( test ) 38 | 39 | 40 | 41 | # Kelvin-Helmholtz test problem 42 | test = testObj('KH-2d-64') 43 | test.script = 'examples/KH.py' 44 | test.args = ['64','0',test.name,"1"] 45 | tests.append( test ) 46 | 47 | -------------------------------------------------------------------------------- /examples/poisson.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import time 3 | import numpy 4 | import matplotlib.pyplot as plt 5 | 6 | from pyranda import pyrandaSim 7 | 8 | # Try to get args 9 | try: 10 | Npts = int(sys.argv[1]) 11 | except: 12 | Npts = 100 13 | 14 | try: 15 | test = bool(int(sys.argv[2])) 16 | except: 17 | test = False 18 | 19 | ## Define a mesh 20 | L = numpy.pi * 2.0 21 | 22 | 23 | # Define the domain/mesh 24 | imesh = """ 25 | Lp = %s 26 | Npts = %d 27 | xdom = (0.0, Lp, Npts, periodic=False) 28 | ydom = (0.0, Lp, Npts, periodic=False) 29 | """ % ( L, Npts) 30 | 31 | # Initialize a simulation object on a mesh 32 | ss = pyrandaSim('Poisson',imesh) 33 | 34 | # Define the equations of motion 35 | eom = """ 36 | :wx: = meshx * ( 2.0 * pi - meshx ) 37 | :wy: = meshy * ( 2.0 * pi - meshy ) 38 | :phi: = cos( meshx ) * :wy: + cos( meshy ) * :wx: 39 | Delta(:ff:) = :phi: 40 | :gg: = lap(:ff:) 41 | """ 42 | ss.EOM(eom) 43 | 44 | # Perform the solve at update 45 | ss.updateVars() 46 | 47 | 48 | if not test: 49 | ss.plot.figure(1) 50 | ss.plot.clf() 51 | ss.plot.contourf('phi',32) 52 | ss.plot.figure(2) 53 | ss.plot.clf() 54 | ss.plot.contourf('ff',32) 55 | plt.pause(.001) 56 | 57 | 58 | ss.plot.figure(3) 59 | ss.plot.clf() 60 | ss.plot.contourf('gg',32) 61 | plt.pause(.001) 62 | 63 | 64 | -------------------------------------------------------------------------------- /pyranda/latex_template.tex: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | % Copyright (c) 2018, Lawrence Livemore National Security, LLC. 3 | % Produced at the Lawrence Livermore National Laboratory. 4 | % 5 | % LLNL-CODE-749864 6 | % This file is part of pyranda 7 | % For details about use and distribution, please read: pyranda/LICENSE 8 | % 9 | % Written by: Britton J. Olson, olson45@llnl.gov 10 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 11 | \documentclass[11pt, oneside]{article} % use "amsart" instead of "article" for AMSLaTeX format 12 | \usepackage{geometry} % See geometry.pdf to learn the layout options. There are lots. 13 | \geometry{letterpaper} % ... or a4paper or a5paper or ... 14 | 15 | 16 | \usepackage{graphicx} % Use pdf, png, jpg, or epsß with pdflatex; use eps in DVI mode % TeX will automatically convert eps --> pdf in pdflatex 17 | \usepackage{amssymb} 18 | \usepackage{amsmath} 19 | 20 | $$PACKAGES$$ 21 | 22 | 23 | \title{$$TITLE$$} 24 | \author{$$AUTHOR$$} 25 | %\date{} % Activate to display a given date or no date 26 | 27 | \begin{document} 28 | \maketitle 29 | 30 | 31 | $$SECTIONS$$ 32 | 33 | 34 | \section{Pyranda Code} 35 | $$PYRANDA$$ 36 | \subsection{Copyright} 37 | $$COPY$$ 38 | 39 | 40 | 41 | \end{document} 42 | -------------------------------------------------------------------------------- /tests/baselines/cylinder-2d-32.dat: -------------------------------------------------------------------------------- 1 | -1.387778780781445676e-17 1.963495408493620142e-01 3.926990816987240840e-01 5.890486225480860982e-01 7.853981633974481680e-01 9.817477042468102377e-01 1.178097245096172418e+00 1.374446785945534266e+00 1.570796326794896114e+00 1.767145867644258406e+00 1.963495408493620253e+00 2.159844949342982545e+00 2.356194490192344393e+00 2.552544031041706241e+00 2.748893571891068532e+00 2.945243112740430380e+00 3.141592653589792672e+00 3.337942194439154520e+00 3.534291735288516811e+00 3.730641276137878659e+00 3.926990816987240951e+00 4.123340357836602799e+00 4.319689898685965090e+00 4.516039439535327382e+00 4.712388980384689674e+00 4.908738521234051078e+00 5.105088062083413369e+00 5.301437602932775661e+00 5.497787143782137065e+00 5.694136684631499357e+00 5.890486225480861648e+00 6.086835766330223940e+00 2 | 1.000000000000000000e+00 1.064464718419664946e+00 1.023380782816208034e+00 1.033937781593674332e+00 1.018931543795355887e+00 1.008948435295844659e+00 1.080525299498673819e+00 1.144087209335044486e+00 1.538649512888202953e+00 1.936264397295182516e+00 2.665684618801191785e+00 4.032005010004460210e+00 4.368756452835030224e+00 3.767560770770502998e+00 3.370414756731695771e+00 2.813982898917729347e+00 2.196770622676791351e+00 1.626575359957591616e+00 1.196025802867650700e+00 9.307876797351962717e-01 8.067969745002216975e-01 8.463596013813088348e-01 8.140799158021488902e-01 7.830348467181850181e-01 7.982476601188028820e-01 7.524208561836747133e-01 6.899575878053491040e-01 6.446168756624072183e-01 6.023729358257676747e-01 5.680175296159649667e-01 5.539936124966327036e-01 5.399696953773004404e-01 3 | -------------------------------------------------------------------------------- /pyranda/parcop/nrtype.f90: -------------------------------------------------------------------------------- 1 | ! Data types from Numerical Recipes------------------------------------- 2 | MODULE LES_nrtype 3 | INTEGER, PARAMETER :: I4B = SELECTED_INT_KIND(9) 4 | INTEGER, PARAMETER :: I2B = SELECTED_INT_KIND(4) 5 | INTEGER, PARAMETER :: I1B = SELECTED_INT_KIND(2) 6 | INTEGER, PARAMETER :: SP = KIND(1.0) 7 | INTEGER, PARAMETER :: DP = KIND(1.0D0) 8 | INTEGER, PARAMETER :: SPC = KIND((1.0,1.0)) 9 | INTEGER, PARAMETER :: DPC = KIND((1.0D0,1.0D0)) 10 | INTEGER, PARAMETER :: LGT = KIND(.true.) 11 | REAL(SP), PARAMETER :: PI=3.141592653589793238462643383279502884197_sp 12 | REAL(SP), PARAMETER :: PIO2=1.57079632679489661923132169163975144209858_sp 13 | REAL(SP), PARAMETER :: TWOPI=6.283185307179586476925286766559005768394_sp 14 | REAL(SP), PARAMETER :: SQRT2=1.41421356237309504880168872420969807856967_sp 15 | REAL(SP), PARAMETER :: EULER=0.5772156649015328606065120900824024310422_sp 16 | REAL(DP), PARAMETER :: PI_D=3.141592653589793238462643383279502884197_dp 17 | REAL(DP), PARAMETER :: PIO2_D=1.57079632679489661923132169163975144209858_dp 18 | REAL(DP), PARAMETER :: TWOPI_D=6.283185307179586476925286766559005768394_dp 19 | TYPE sprs2_sp 20 | INTEGER(I4B) :: n,len 21 | REAL(SP), DIMENSION(:), POINTER :: val 22 | INTEGER(I4B), DIMENSION(:), POINTER :: irow 23 | INTEGER(I4B), DIMENSION(:), POINTER :: jcol 24 | END TYPE sprs2_sp 25 | TYPE sprs2_dp 26 | INTEGER(I4B) :: n,len 27 | REAL(DP), DIMENSION(:), POINTER :: val 28 | INTEGER(I4B), DIMENSION(:), POINTER :: irow 29 | INTEGER(I4B), DIMENSION(:), POINTER :: jcol 30 | END TYPE sprs2_dp 31 | END MODULE LES_nrtype 32 | -------------------------------------------------------------------------------- /pyranda/parcop/scripts/make-funroll.py: -------------------------------------------------------------------------------- 1 | #!/bin/local/bin/python 2 | import os,sys 3 | import shutil 4 | import glob 5 | 6 | 7 | # Select files for code-to-code transforms 8 | pwd = os.path.dirname(os.path.abspath(__file__)) 9 | DIRS = [] 10 | DIRS.append(pwd + '/../../parcop') ### Add source file dirs here ### 11 | 12 | 13 | #### Addd your Fortran suffix support here 14 | fsuff = ".f90" 15 | 16 | try: 17 | option = int(sys.argv[1]) 18 | except: 19 | print("Error: specify 1- forward transform, or 2-backward") 20 | exit() 21 | 22 | 23 | # Option-1: Make conversion (safe to call multple times) 24 | if option == 1: 25 | 26 | # Option 1- Convert files 27 | Files = [] 28 | for D in DIRS: 29 | Files += glob.glob( D + '/*%s' % fsuff ) 30 | 31 | # Not go through each and convert it 32 | for ff in Files: 33 | try: 34 | os.system('python %s/funroller.py %s %s %s' % (pwd, 35 | ff, 36 | fsuff, 37 | 0) ) 38 | except: 39 | print("Error processing file:%s" % ff) 40 | 41 | 42 | 43 | # Option-2: Revert space (safe to call multple times) 44 | if option == 2: 45 | 46 | # Option 2- Revert files 47 | Files = [] 48 | for D in DIRS: 49 | Files += glob.glob( D + '/*.fexl' ) 50 | 51 | for ff in Files: 52 | cmd = 'mv -f %s %s' % (ff,ff.replace(fsuff+".fexl",fsuff)) 53 | os.system( cmd ) 54 | 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /.github/workflows/regression-tests.yaml: -------------------------------------------------------------------------------- 1 | name: Regression Tests 2 | on: [push, pull_request] 3 | jobs: 4 | regression-tests: 5 | strategy: 6 | matrix: 7 | mpi: [mpich-3.4, openmpi-4.1.1, openmpi-3.1.6] 8 | python-version: [3.7, 3.8, 3.9] 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v2 12 | - name: Set up Python ${{ matrix.python-version }} 13 | uses: actions/setup-python@v2 14 | with: 15 | python-version: ${{ matrix.python-version }} 16 | - name: Maybe use cached MPI 17 | id: cache-mpi 18 | uses: actions/cache@v2 19 | with: 20 | path: ~/mpi 21 | # NOTE: without the `-v2' an empty cache dir will be used because the initial caching 22 | # of ~/mpi was incorrect. caches cannot be cleared: 23 | # https://github.com/actions/cache/issues/2 24 | key: ${{ runner.os }}-${{ matrix.mpi }}-v2 25 | - name: Maybe build ${{ matrix.MPI }} 26 | if: steps.cache-mpi.outputs.cache-hit != 'true' 27 | run: bash ./.github/scripts/install-mpi.sh ${{ matrix.MPI }} ~/mpi 28 | - name: Add mpi to path 29 | run: echo "PATH=$HOME/mpi/bin:$PATH" >> $GITHUB_ENV 30 | - name: Install Python Requirements 31 | run: | 32 | python -m pip install --upgrade pip 33 | pip install -r requirements.txt 34 | - name: Install Pyranda 35 | run: | 36 | python setup.py build 37 | python setup.py install 38 | - name: Run Regression Tests 39 | run: cd tests && python run_tests.py 1 40 | -------------------------------------------------------------------------------- /tests/baselines/cavity-2d-32.dat: -------------------------------------------------------------------------------- 1 | 0.000000000000000000e+00 3.225806451612903136e-02 6.451612903225806273e-02 9.677419354838709409e-02 1.290322580645161255e-01 1.612903225806451846e-01 1.935483870967741882e-01 2.258064516129032473e-01 2.580645161290322509e-01 2.903225806451613100e-01 3.225806451612903136e-01 3.548387096774193727e-01 3.870967741935483764e-01 4.193548387096774355e-01 4.516129032258064391e-01 4.838709677419354982e-01 5.161290322580645018e-01 5.483870967741935054e-01 5.806451612903226200e-01 6.129032258064516236e-01 6.451612903225806273e-01 6.774193548387096309e-01 7.096774193548387455e-01 7.419354838709677491e-01 7.741935483870967527e-01 8.064516129032257563e-01 8.387096774193548709e-01 8.709677419354838745e-01 9.032258064516128782e-01 9.354838709677418818e-01 9.677419354838709964e-01 1.000000000000000000e+00 2 | 0.000000000000000000e+00 -1.264467083340862531e-02 -2.318953418798080923e-02 -3.217506970720023646e-02 -4.011658307834083809e-02 -4.740570608064741120e-02 -5.443907903480697807e-02 -6.151688915872511459e-02 -6.893511494908555193e-02 -7.690284377122859338e-02 -8.558067420872293718e-02 -9.502224947681818523e-02 -1.051567862899952660e-01 -1.157527684019000885e-01 -1.263663374611738999e-01 -1.363381499578250888e-01 -1.447625330947707178e-01 -1.505388888414202486e-01 -1.524251217417482429e-01 -1.491146710783824159e-01 -1.393692723781247145e-01 -1.219595236672680189e-01 -9.576220691206767388e-02 -5.931510548750516115e-02 -1.078589511191670527e-02 5.291581687668397288e-02 1.360286806749508304e-01 2.445613540698286237e-01 3.847132962621591656e-01 5.609583434403161428e-01 7.706396036768536906e-01 1.000000000000000000e+00 3 | -------------------------------------------------------------------------------- /examples/meshTest.py: -------------------------------------------------------------------------------- 1 | import numpy 2 | import matplotlib.pyplot as plt 3 | 4 | 5 | 6 | 7 | def zoomMesh(npts,x1,xn,xa,xb,tt,dxc,dxf): 8 | 9 | x = numpy.zeros( (npts) ) 10 | 11 | x[0] = x1 12 | dx = dxc 13 | for i in range(1,npts): 14 | 15 | x[i] = x[i-1] + dx 16 | 17 | xmin = (xa+xb)/2.0 18 | xh = (xb-xa)/2.0 19 | xpr = numpy.abs(x[i]-xmin) 20 | w = 0.5*(numpy.tanh( (xpr - xh)/tt ) + 1.0) 21 | dx = w*dxc + (1.0-w)*dxf 22 | 23 | return x 24 | 25 | def sfunc(npts,x1,xn,xa,xb,tt,dxc,dxf): 26 | xx = zoomMesh(npts,x1,xn,xa,xb,tt,dxc,dxf) 27 | error = xx[-1] - xn 28 | return error 29 | 30 | 31 | def zoomMesh_solve(npts,x1,xn,xa,xb,tt,dxf): 32 | 33 | # take initial guess at dxc and solve 34 | nmin = (xb-xa)/dxf 35 | if nmin > npts: 36 | print("Not enough points given") 37 | exit() 38 | dxc = ((xn-x1) - (xb-xa)) / (npts-nmin) 39 | 40 | # NR solvers 41 | delta = 1.0001 42 | f1 = xn 43 | cnt = 1 44 | while ( (abs(f1) > .01*xn) and cnt<100): 45 | f1 = sfunc(npts,x1,xn,xa,xb,tt,dxc,dxf) 46 | f2 = sfunc(npts,x1,xn,xa,xb,tt,dxc*delta,dxf) 47 | dxc = dxc*(1.0- f1/(f2-f1)*(delta-1.0)) 48 | cnt += 1 49 | 50 | 51 | #print(f1) 52 | #print(zoomMesh(npts,x1,xn,xa,xb,tt,dxc,dxf)[-1]) 53 | return zoomMesh(npts,x1,xn,xa,xb,tt,dxc,dxf) 54 | 55 | 56 | npts = 100 57 | x1 = 0 58 | xn = 1 59 | xa = .4 60 | xb = .6 61 | tt = .02 62 | dxf = (xn-x1) / float(npts) * .75 63 | 64 | 65 | #xx = zoomMesh_solve(npts,x1,xn,xa,xb,tt,dxf) 66 | #plt.plot( xx[:-1], numpy.diff(xx) ) 67 | #plt.figure() 68 | #plt.plot( xx ) 69 | #plt.show() 70 | -------------------------------------------------------------------------------- /examples/TBL_data/vvmean.dat: -------------------------------------------------------------------------------- 1 | # v'v' 2 | 0.0, 0.0 3 | 1.0057228438514572, 0.011428571428571566 4 | 1.2492641437899512, 0.01904761904761898 5 | 1.6712765791866788, 0.02666666666666684 6 | 2.0641724281651475, 0.038095238095238404 7 | 2.5349261035409927, 0.05333333333333323 8 | 3.203142119292703, 0.07619047619047592 9 | 3.911264843092913, 0.1028571428571432 10 | 5.027627269030706, 0.14857142857142858 11 | 6.139091257642107, 0.1942857142857144 12 | 7.120988306612089, 0.23619047619047606 13 | 8.450642217856245, 0.29333333333333345 14 | 10.437280629443205, 0.3733333333333335 15 | 12.315682614123574, 0.44571428571428573 16 | 13.647972968663383, 0.49523809523809526 17 | 17.846331124595157, 0.6285714285714286 18 | 20.7007047005487, 0.7047619047619049 19 | 23.739123729349245, 0.7695238095238097 20 | 30.168512925793703, 0.8685714285714288 21 | 35.80167499277173, 0.9142857142857146 22 | 40.59067469035765, 0.9333333333333331 23 | 44.981707332934, 0.940952380952381 24 | 54.30256225683082, 0.9257142857142857 25 | 63.71081124138799, 0.8952380952380952 26 | 73.48031403880893, 0.8457142857142856 27 | 84.26564659861478, 0.784761904761905 28 | 95.53741408321218, 0.716190476190476 29 | 108.31694596950025, 0.6247619047619049 30 | 116.65799236725394, 0.5638095238095238 31 | 124.21554819276477, 0.5066666666666664 32 | 132.2627117073562, 0.44952380952380944 33 | 140.8312015902866, 0.38095238095238093 34 | 149.95479137950298, 0.31619047619047613 35 | 166.17665487108326, 0.21714285714285753 36 | 185.20725395880314, 0.1295238095238096 37 | 207.59853646540188, 0.06095238095238065 38 | 234.02857981749008, 0.02285714285714313 39 | 279.3165404137928, 0.011428571428571566 40 | 348.9401387064079, 0.007619047619047858 41 | 433.4379061587587, 0.007619047619047858 -------------------------------------------------------------------------------- /examples/intTest.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function 2 | import sys 3 | import time 4 | import numpy 5 | import matplotlib.pyplot as plt 6 | from pyranda import pyrandaSim 7 | 8 | 9 | 10 | # Try to get args 11 | try: 12 | Npts = int(sys.argv[1]) 13 | except: 14 | Npts = 10 15 | 16 | try: 17 | test = bool(int(sys.argv[2])) 18 | except: 19 | test = False 20 | 21 | 22 | # Define the domain/mesh 23 | domain = "xdom = (0.0 , 1.0 , 1 )" 24 | 25 | # Initialize a simulation object on a mesh 26 | pysim = pyrandaSim('integralTests',domain) 27 | 28 | # Define the equations of motion 29 | eom = """ 30 | ddt(:a:) = :a: 31 | ddt(:b:) = cos( 6.0*simtime ) 32 | """ 33 | pysim.EOM(eom) 34 | 35 | # Initialize variables 36 | a0 = 1.0 37 | b0 = 0.0 38 | ic = """ 39 | :a: = %s 40 | :b: = %s 41 | """ % (a0,b0) 42 | pysim.setIC(ic) 43 | 44 | # Integrate in time 45 | dt = 1.0 / float(Npts) 46 | time = 0.0 47 | tt = [ time ] 48 | aa = [ a0 ] 49 | bb = [ b0 ] 50 | while time < 1.0: 51 | time = pysim.rk4(time,dt) 52 | tt.append( time ) 53 | aa.append( pysim.variables['a'].data[0,0,0] ) 54 | bb.append( pysim.variables['b'].data[0,0,0] ) 55 | 56 | # Plot the initial/final solution 57 | tt = numpy.array(tt) 58 | aa = numpy.array(aa) 59 | a_sol = 1.0-a0+numpy.exp(tt) 60 | 61 | bb = numpy.array(bb) 62 | b_sol = b0+1.0/6.0*numpy.sin(6.0*tt) 63 | 64 | 65 | if not test: 66 | plt.figure() 67 | plt.plot(tt, aa ,'b-') 68 | plt.plot(tt, a_sol,'k--') 69 | 70 | plt.figure() 71 | plt.plot(tt,bb ,'b-') 72 | plt.plot(tt,b_sol ,'k--') 73 | 74 | 75 | if test: 76 | a_error = numpy.sum( numpy.abs(aa-a_sol) ) 77 | b_error = numpy.sum( numpy.abs(bb-b_sol) ) 78 | print(a_error) 79 | 80 | 81 | 82 | plt.show() 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /examples/grid_conv.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import time 3 | import numpy 4 | import matplotlib.pyplot as plt 5 | from pyranda import pyrandaSim 6 | 7 | 8 | def gridAdv(npts,cfl=1.0): 9 | 10 | # Define the domain/mesh 11 | xf = 1.0 * (npts-1) / npts 12 | domain = "xdom = (0.0 , xf , npts , periodic=True)" 13 | domain = domain.replace('xf',str(xf)) 14 | domain = domain.replace('npts',str(npts)) 15 | 16 | # Initialize a simulation object on a mesh 17 | pysim = pyrandaSim('advection',domain,silent=True) 18 | 19 | # Define the equations of motion 20 | pysim.EOM(" ddt(:phi:) = -:c: * ddx(:phi:) ") 21 | 22 | # Initialize variables 23 | ic = """ 24 | :phi: = 1.0 + 0.1 * exp( -(abs(meshx-.5)/.1 )**2 ) 25 | :phi0: = :phi: 26 | :c: = 1.0 27 | """ 28 | pysim.setIC(ic) 29 | 30 | # Integrate in time 31 | dt = 1.0 / (npts-1) / 1.0 * cfl 32 | time = 0.0 33 | tfinal = 1.0 34 | while time < tfinal : 35 | time = pysim.rk4(time,dt) 36 | dt = min(dt, (tfinal - time) ) 37 | 38 | x = pysim.mesh.coords[0].data 39 | phi = pysim.variables['phi'].data 40 | phi0 = pysim.variables['phi0'].data 41 | 42 | error = numpy.sum( numpy.abs(phi-phi0) ) 43 | return error 44 | 45 | 46 | npts = [16,32,64,128,256]#,512] 47 | error = [] 48 | 49 | cfl = 0.25 50 | 51 | for npt in npts: 52 | error.append( gridAdv(npt,cfl) ) 53 | 54 | plt.loglog( npts, error ,'k-o') 55 | # 10th order fiducial 56 | plt.loglog( npts, 1.e10*(1./numpy.array( npts))**10, 'k--') 57 | 58 | # 10th order fiducial 59 | fourth = 1.e-2*(1./numpy.array( npts))**4 60 | fact = fourth[-1] / error[-1] * 10.0 61 | plt.loglog( npts, fourth/fact , 'k--') 62 | plt.xlabel('Npts') 63 | plt.ylabel('L2-Error') 64 | plt.title('CFL = %s' % cfl) 65 | plt.show() 66 | 67 | 68 | 69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /pyranda/pyrandaEq.py: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | # Copyright (c) 2018, Lawrence Livemore National Security, LLC. 3 | # Produced at the Lawrence Livermore National Laboratory. 4 | # 5 | # LLNL-CODE-749864 6 | # This file is part of pyranda 7 | # For details about use and distribution, please read: pyranda/LICENSE 8 | # 9 | # Written by: Britton J. Olson, olson45@llnl.gov 10 | ################################################################################ 11 | from .pyrandaUtils import * 12 | import numpy 13 | 14 | class pyrandaEq: 15 | 16 | def __init__(self,eqstr,sMap,pympi): 17 | """ 18 | Read in eqstr and extract the LHS variable 19 | and the kind of equation (PDE or ALG) 20 | """ 21 | self.eqstr = eqstr 22 | self.kind = 'ALG' 23 | self.active = True 24 | self.rank = 1 25 | self.sRHS = '' 26 | if '=' in eqstr: 27 | self.LHS = findVar(eqstr.split('=')[0],'scalar', unique=False) # Return values are assumed to all be unique. Unique to false ensure order is preserved 28 | self.rank = len(self.LHS) 29 | else: 30 | self.LHS = None # No return functions 31 | 32 | 33 | # Make a lambda for this equation 34 | if self.LHS: 35 | Srhs = fortran3d( self.eqstr.split('=')[1] , sMap) 36 | else: 37 | Srhs = fortran3d( self.eqstr , sMap) 38 | self.sRHS = Srhs 39 | self.RHS = eval( 'lambda self: ' + Srhs ) 40 | 41 | 42 | # Check to see if this is conserved PDE 43 | if ( 'ddt(' in eqstr ): 44 | self.kind = 'PDE' 45 | 46 | # Check to see if this is an elliptic equation 47 | #if ( 'Delta(' in eqstr ): 48 | # self.kind = 'ELP' 49 | # self.solver = None 50 | -------------------------------------------------------------------------------- /examples/TBL_data/uumean.dat: -------------------------------------------------------------------------------- 1 | # u'u' 2 | 0.0 , 0.0 3 | 0.9943097207282859, 0.40380952380952406 4 | 1.8733314405991552, 0.7314285714285713 5 | 2.809150253597101, 1.081904761904762 6 | 3.6109445369649213, 1.363809523809524 7 | 4.38413096570873, 1.6076190476190477 8 | 5.202750044263939, 1.84 9 | 6.245094773315424, 2.083809523809524 10 | 7.161740610758884, 2.2552380952380955 11 | 8.07352504836407, 2.388571428571429 12 | 9.258545195808463, 2.5104761904761905 13 | 10.437280629443205, 2.586666666666667 14 | 11.63256105784664, 2.6285714285714286 15 | 12.89095244235596, 2.64 16 | 14.042994552757019, 2.6361904761904764 17 | 15.651202393574833, 2.605714285714286 18 | 16.952904440225574, 2.5714285714285716 19 | 18.362868342780136, 2.521904761904762 20 | 19.776917967906204, 2.4647619047619047 21 | 21.544346900318846, 2.3923809523809525 22 | 23.469727897668918, 2.3085714285714287 23 | 25.567176862644516, 2.217142857142857 24 | 27.8520712117276, 2.125714285714286 25 | 30.341162614498682, 2.038095238095238 26 | 32.677611845633635, 1.958095238095238 27 | 35.597953463667736, 1.8780952380952383 28 | 39.001208727691605, 1.8019047619047621 29 | 43.220295548239314, 1.721904761904762 30 | 48.72281162797283, 1.638095238095238 31 | 53.68632704577854, 1.5695238095238095 32 | 59.15548826848792, 1.5047619047619047 33 | 66.30729912536806, 1.4323809523809525 34 | 74.32375331509397, 1.363809523809524 35 | 81.89530108014252, 1.2914285714285716 36 | 91.27397489707161, 1.1961904761904762 37 | 98.86518207347628, 1.0933333333333333 38 | 105.87249491216852, 0.9828571428571427 39 | 112.08985178927148, 0.8761904761904762 40 | 119.35146580457013, 0.7390476190476192 41 | 127.81079436806334, 0.5942857142857143 42 | 137.65298255400032, 0.4419047619047616 43 | 148.25307752524697, 0.3314285714285714 44 | 162.4264503572129, 0.2209523809523808 45 | 185.20725395880314, 0.12190476190476218 46 | 207.59853646540188, 0.06095238095238065 47 | 238.06954470749778, 0.01904761904761898 48 | 269.91484182945703, 0.015238095238095273 49 | 384.48754864623504, 0.015238095238095273 -------------------------------------------------------------------------------- /examples/TBL_data/umean.dat: -------------------------------------------------------------------------------- 1 | # Umean 2 | 0.0 , 0.0 3 | 0.994365418571293, 1.062176165803109 4 | 1.8202150436431448, 1.8720874789408413 5 | 2.2689672159518066, 2.3408881401188815 6 | 2.688115052421818, 2.7313964207381005 7 | 3.026785153658577, 3.0436123207984984 8 | 3.466389021911045, 3.5373660955529402 9 | 3.903112264065039, 3.927302202867221 10 | 4.320985630746922, 4.29114084999523 11 | 4.756643612553491, 4.680822658062873 12 | 5.325744997409134, 5.200228869321974 13 | 5.962935651216915, 5.719635080581073 14 | 6.63874350552271, 6.264884452779807 15 | 7.51750316523807, 6.9139514924187 16 | 8.416923388923276, 7.562891382434275 17 | 9.423953376248447, 8.211831272449851 18 | 10.374111710338047, 8.731046759273974 19 | 11.484780503199769, 9.302139292412344 20 | 12.931724439694007, 9.977049492990874 21 | 14.726453130308297, 10.626180107441428 22 | 16.581808751343413, 11.19746336501478 23 | 18.46110399251669, 11.716806001462217 24 | 20.553388700427767, 12.132521694904478 25 | 22.75386697312397, 12.548173813535074 26 | 24.906862224387798, 12.860071839537172 27 | 27.418065513887118, 13.22384691185352 28 | 30.353486933782413, 13.561778823230233 29 | 34.37132853692854, 13.925871769604878 30 | 38.48363382254435, 14.212117359102322 31 | 43.087949614647655, 14.498362948599762 32 | 47.701013587893414, 14.86220159572777 33 | 53.710766439191, 15.226230967290757 34 | 61.16501231125817, 15.616294224228357 35 | 69.2613253199492, 16.10992084935948 36 | 76.6765522553265, 16.49966623223878 37 | 84.88566510393376, 16.91531835086938 38 | 94.50616120697359, 17.305127308560344 39 | 104.03462692709667, 17.720715852379282 40 | 115.17273848124464, 18.136367971009882 41 | 124.6537997735964, 18.474045583139954 42 | 138.78140769753335, 18.73432086207444 43 | 155.38569797995865, 18.839219301312816 44 | 177.95358781532846, 18.892558568295236 45 | 208.4579223330515, 18.894338663021706 46 | 244.19122939239475, 18.922025493499472 47 | 281.241726022239, 18.923614863790963 48 | 335.0837555129797, 18.899678947201114 49 | 424.8355576140584, 18.928255825042115 50 | -------------------------------------------------------------------------------- /tests/baselines/RT_2D.dat: -------------------------------------------------------------------------------- 1 | 1.099802685603180397e+00 4.223193976753846002e+00 7.449609280482797580e+00 1.067661795171572692e+01 1.393752045272217721e+01 1.719436334592181481e+01 2.045406324318241431e+01 2.374708865784005596e+01 2.701224101483085960e+01 3.024326752911209226e+01 3.348302326758828684e+01 3.674037151362556131e+01 4.000058917631361766e+01 4.326529857925116573e+01 4.655097953748027351e+01 4.981302447560319990e+01 5.305146867063137961e+01 5.629094082249296349e+01 5.954375657877289285e+01 6.280316414491919375e+01 6.606498910172342676e+01 6.934049540683909640e+01 7.258952332904169680e+01 7.547940096154547973e+01 7.746076039350741382e+01 7.912865248880513036e+01 8.063328985736519883e+01 8.205465014149083913e+01 8.343256165343207442e+01 8.478958412910141362e+01 8.617588202958647514e+01 8.768445190016879565e+01 8.933790630794717913e+01 9.086994444358802525e+01 9.223754875783808416e+01 9.356639181227359359e+01 9.483619238068993695e+01 9.600642222998006048e+01 9.712061857233004503e+01 9.828388440379566759e+01 9.952222933777628100e+01 2 | 8.863186603662803753e-01 8.830909213832127680e-01 8.666376984818142670e-01 8.589622789073511067e-01 8.564666605021425960e-01 8.685743514887309669e-01 8.770621004779174390e-01 8.787850028557500082e-01 8.723202067922030123e-01 8.622255683613911925e-01 8.524257368834035065e-01 8.532685934014792029e-01 8.611659618107937453e-01 8.687291954589119181e-01 8.697571437278297513e-01 8.651185143624774421e-01 8.558846613109800661e-01 8.491943308063508722e-01 8.504847465036472487e-01 8.596167207770292196e-01 8.724194968011732554e-01 8.860470303223416666e-01 9.015336667051876418e-01 9.250736101567916814e-01 9.567355052217589861e-01 9.936344946595813132e-01 1.034221971234628557e+00 1.076619323208145795e+00 1.119620620333939609e+00 1.163487136087611784e+00 1.208768204000806756e+00 1.255232367394874649e+00 1.303457879592223589e+00 1.352532617905253698e+00 1.398437132214971124e+00 1.438885747922074909e+00 1.476615053031655300e+00 1.514148859978992068e+00 1.548095071139689027e+00 1.580422397019050962e+00 1.614546966289024832e+00 3 | -------------------------------------------------------------------------------- /examples/tutorials/SOD.py: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | # Copyright (c) 2018, Lawrence Livemore National Security, LLC. 3 | # Produced at the Lawrence Livermore National Laboratory. 4 | # 5 | # LLNL-CODE-749864 6 | # This file is part of pyranda 7 | # For details about use and distribution, please read: pyranda/LICENSE 8 | # 9 | # Written by: Britton J. Olson, olson45@llnl.gov 10 | ################################################################################ 11 | 12 | from pyranda import pyrandaSim, pyrandaBC 13 | 14 | ss = pyrandaSim('sod','xdom=(0.0,6.0,200)') 15 | 16 | ss.addPackage( pyrandaBC(ss) ) 17 | 18 | # Define the equations of motion 19 | eom =""" 20 | # Primary Equations of motion here 21 | ddt(:rho:) = -ddx(:rho:*:u:) 22 | ddt(:rhou:) = -ddx(:rhou:*:u: + :p: - :tau:) 23 | ddt(:Et:) = -ddx( (:Et: + :p: - :tau:)*:u: ) 24 | # Conservative filter of the EoM 25 | :rho: = fbar( :rho: ) 26 | :rhou: = fbar( :rhou: ) 27 | :Et: = fbar( :Et: ) 28 | # Update the primatives and enforce the EOS 29 | :u: = :rhou: / :rho: 30 | :p: = ( :Et: - .5*:rho:*(:u:*:u:) ) * ( :gamma: - 1.0 ) 31 | # Artificial bulk viscosity (old school way) 32 | :div: = ddx(:u:) 33 | :beta: = gbar( ring(:div:) * :rho:) * 7.0e-2 34 | :tau: = :beta:*:div: 35 | # Apply constant BCs 36 | bc.extrap(['rho','Et'],['x1']) 37 | bc.const(['u'],['x1','xn'],0.0) 38 | """ 39 | # Add the EOM to the solver 40 | ss.EOM(eom) 41 | 42 | # Initial conditions SOD shock tube in 1d 43 | ic = """ 44 | :gamma: = 1.4 45 | :Et: = gbar( where( meshx < pi, 1.0/(:gamma:-1.0) , .1 /(:gamma:-1.0) ) ) 46 | :rho: = gbar( where( meshx < pi, 1.0 , .125 ) ) 47 | """ 48 | 49 | # Set the initial conditions 50 | ss.setIC(ic) 51 | 52 | # Approx a max dt and stopping time 53 | dt = 1.0 / 200.0 * 0.75 54 | tt = 1.5 55 | 56 | # Start time loop 57 | time = 0.0 58 | while tt > time: 59 | time = ss.rk4(time,dt) 60 | 61 | ss.plot.figure(1) 62 | ss.plot.plot('rho','b.-') 63 | -------------------------------------------------------------------------------- /pyranda/parcop/scripts/FEXL-README.md: -------------------------------------------------------------------------------- 1 | # FEXL README File 2 | ### Simple instructions for adding FEXL to array syntax code 3 | 4 | 5 | 6 | ## Simple setup 7 | The following files need to be customized for FEXL to work with your build: 8 | - make-funroller.py: The driver for the pre-processor and tells which files should be parsed and converted [Needs to be modified] 9 | - ../fexl: Short cut for the forward conversion [Maybe modify] 10 | - ../undo_fexl: Short cut for the backward conversion [Maybe modify] 11 | - funroller.py: Actual script that will do the conversion itself. [Maybe modify] 12 | 13 | 14 | ## Simple examples of FEXL syntax 15 | 16 | #### Always add DEF-FEXL to include 17 | You'll need to tell FEXL where it is appropriate to add new vaiable definition lines to the code. If you have a FEXL loop inside 18 | of a subroutine, you'll need to add 19 | ```fortran 20 | SUBROUTINE foobar(arg1,arg2) 21 | USE globals 22 | IMPLICIT NONE 23 | REAL*8, DIMENSION(:,:,:) :: arg1 24 | INTEGER :: arg2 25 | !$DEF-FEXL 26 | ... 27 | ``` 28 | 29 | #### Trivial case - Array syntax 30 | ```fortran90 31 | !$FEXL {dim=3,var=['arg1','tmp','vari']} 32 | tmp = arg1 * vari**2 / 3.2 33 | vari = tmp * SQRT( arg1 ) 34 | !$FEXL 35 | ``` 36 | 37 | #### Multi-line input syntax 38 | ```fortran90 39 | !$FEXL { dim=3, 40 | !$FEXL var=['arg1','tmp','vari']} 41 | tmp = arg1 * vari**2 / 3.2 42 | vari = tmp * SQRT( arg1 ) 43 | !$FEXL 44 | ``` 45 | 46 | #### Specify loop bounds 47 | ```fortran90 48 | !$FEXL {dim=3,var=['arg1','tmp','vari'], 49 | !$FEXL bounds="x1:xn,y1:yn,z1:zn"} 50 | tmp = arg1 * vari**2 / 3.2 51 | vari = tmp * SQRT( arg1 ) 52 | !$FEXL 53 | ``` 54 | 55 | #### Blended array syntax 56 | ```fortran90 57 | !$FEXL {dim=3,var=['arg1','tmp','vari']} 58 | tmp = arg1 * vari**2 / 3.2 59 | vari = tmp4d[:,:,:,n] * SQRT( arg1 ) 60 | !$FEXL 61 | ``` 62 | 63 | #### Find and replace 64 | ```fortran90 65 | !$FEXL {dim=3,var=['arg1','tmp','vari'], 66 | replace={'tmp3d':'tmp'} } 67 | tmp = arg1 * vari**2 / 3.2 68 | vari = tmp3d * SQRT( arg1 ) 69 | !$FEXL 70 | ``` 71 | 72 | #### More examples to come 73 | 74 | 75 | -------------------------------------------------------------------------------- /examples/shallow_water.py: -------------------------------------------------------------------------------- 1 | import numpy 2 | import re 3 | import sys 4 | import time 5 | 6 | import matplotlib.pyplot as plt 7 | from pyranda.pyranda import pyrandaSim,pyrandaMPI 8 | 9 | 10 | ## Define a mesh 11 | Npts = 64 12 | L = numpy.pi * 2.0 13 | Lp = L * (Npts-1.0) / Npts 14 | 15 | mesh_options = {} 16 | mesh_options['type'] = 'cartesian' 17 | mesh_options['periodic'] = numpy.array([True, True, True]) 18 | mesh_options['dim'] = 2 19 | mesh_options['x1'] = [ 0.0 , 0.0 , 0.0 ] 20 | mesh_options['xn'] = [ Lp , Lp , Lp ] 21 | mesh_options['nn'] = [ Npts, Npts , 1 ] 22 | 23 | 24 | # Initialize a simulation object on a mesh 25 | ss = pyrandaSim('advection',mesh_options) 26 | 27 | 28 | # Define the equations of motion 29 | eom =""" 30 | ddt(:eta:) = - ddx(:eta:*:u:) - ddy(:eta:*:v:) 31 | ddt(:ueta:) = - ddx(:ueta:*:u: + .5*:g:*:eta:**2) - ddy(:ueta:*:v:) 32 | ddt(:veta:) = - ddx(:veta:*:u:) - ddy(:veta:*:v: + .5*:g:*:eta:**2) 33 | :eta: = fbar( :eta: ) 34 | :ueta: = fbar( :ueta: ) 35 | :veta: = fbar( :veta: ) 36 | :v: = :veta: / :eta: 37 | :u: = :ueta: / :eta: 38 | """ 39 | ss.EOM(eom) 40 | 41 | # Initialize variables 42 | x = ss.mesh.coords[0].data 43 | y = ss.mesh.coords[1].data 44 | z = ss.mesh.coords[2].data 45 | 46 | # Set some initial comnditions 47 | ic = """ 48 | rad = sqrt( (meshx-pi)**2 + (meshy-pi)**2 ) 49 | :eta: = 1.0 + 0.01 * exp( -(rad)*2/(0.7**2) ) 50 | :g: = 1.0 51 | """ 52 | 53 | ss.setIC(ic) 54 | 55 | 56 | time = 0.0 57 | viz = True 58 | 59 | 60 | v = 1.0 61 | 62 | dt_max = v / ss.mesh.nn[0] * .75 63 | 64 | tt = L/v * .5 #dt_max 65 | 66 | 67 | xx = ss.PyMPI.zbar( x ) 68 | yy = ss.PyMPI.zbar( y ) 69 | 70 | 71 | dt = dt_max 72 | cnt = 1 73 | while tt > time: 74 | 75 | time = ss.rk4(time,dt) 76 | dt = min(dt_max, (tt - time) ) 77 | 78 | ss.iprint("%s -- %s" % (cnt,time) ) 79 | cnt += 1 80 | if viz: 81 | phi = ss.PyMPI.zbar( ss.variables['eta'].data ) 82 | if ss.PyMPI.master and (cnt%10 == 0): 83 | plt.figure(2) 84 | plt.clf() 85 | plt.contourf( xx,yy,phi ,32 ) 86 | plt.pause(.001) 87 | 88 | -------------------------------------------------------------------------------- /examples/TBL_data/wwmean.dat: -------------------------------------------------------------------------------- 1 | # w'w' 2 | 0.0, 0.0 3 | 1.0114784386446625, 0.21333333333333337 4 | 1.2564134874140855, 0.2628571428571429 5 | 1.465706750248673, 0.2971428571428576 6 | 1.6150219849356722, 0.31619047619047613 7 | 1.9946930949077788, 0.3695238095238098 8 | 2.2874712173851335, 0.4114285714285715 9 | 2.593454079094974, 0.44952380952380944 10 | 2.9236351338807487, 0.48761904761904784 11 | 3.5496527824418065, 0.5561904761904763 12 | 4.070665603784068, 0.6057142857142859 13 | 4.668151921730211, 0.6552380952380954 14 | 5.292585782603056, 0.7009523809523808 15 | 6.034887033371561, 0.7504761904761907 16 | 6.96028485213835, 0.803809523809524 17 | 7.80177297487299, 0.8457142857142856 18 | 8.94690575214542, 0.8990476190476193 19 | 10.377889587824425, 0.9523809523809526 20 | 12.315682614123574, 1.0171428571428573 21 | 13.963085991940678, 1.0590476190476192 22 | 17.049923265165663, 1.1161904761904762 23 | 20.7007047005487, 1.1504761904761907 24 | 22.550690854531513, 1.161904761904762 25 | 25.567176862644516, 1.1695238095238096 26 | 29.153051167439695, 1.1771428571428573 27 | 33.2418552481296, 1.1771428571428573 28 | 39.674641499276106, 1.1771428571428573 29 | 47.08281856336967, 1.1733333333333336 30 | 55.24020306842935, 1.1504761904761907 31 | 59.834500911072844, 1.1276190476190475 32 | 66.68676544447435, 1.081904761904762 33 | 74.32375331509397, 1.020952380952381 34 | 80.96593852250439, 0.9561904761904763 35 | 88.20172432678594, 0.8723809523809525 36 | 96.08415978598244, 0.784761904761905 37 | 105.87249491216852, 0.6857142857142859 38 | 113.376468275724, 0.5942857142857143 39 | 120.72143428195848, 0.5066666666666664 40 | 130.01769975119282, 0.40380952380952406 41 | 136.86969864068365, 0.33904761904761926 42 | 143.26292997785274, 0.2857142857142856 43 | 150.81295923534574, 0.22857142857142865 44 | 166.17665487108326, 0.14095238095238072 45 | 182.06356747197475, 0.08761904761904793 46 | 196.08354052450068, 0.057142857142857384 47 | 209.9814435289418, 0.03428571428571425 48 | 223.58485337329626, 0.01904761904761898 49 | 253.49261035409924, 0.007619047619047858 50 | 307.77121920733066, 0.007619047619047858 51 | 350.9370686337305, 0.003809523809523707 52 | 430.97152342576834, 0.007619047619047858 -------------------------------------------------------------------------------- /examples/curv_advect.py: -------------------------------------------------------------------------------- 1 | import re 2 | import sys 3 | import time 4 | import numpy 5 | import matplotlib.pyplot as plt 6 | from matplotlib import cm 7 | from pyranda import pyrandaSim, pyrandaBC 8 | 9 | 10 | 11 | ## Define a mesh 12 | L = numpy.pi * 2.0 13 | Npts = 200 14 | Lp = L * (Npts-1.0) / Npts 15 | 16 | dx = L/ float(Npts) 17 | 18 | def myMesh(i,j,k): 19 | x = (i-1)*dx + .5*numpy.sin( j / float(Npts) * 2.0*numpy.pi ) 20 | y = (j-1)*dx - .5*numpy.sin( i / float(Npts) * 2.0*numpy.pi ) 21 | z = 0.0 22 | return x,y,z 23 | 24 | imesh = {} 25 | 26 | imesh['x1'] = [ 0.0 , 0.0 , 0.0 ] 27 | imesh['xn'] = [ Lp , Lp , 1 ] 28 | imesh['nn'] = [ Npts , Npts , 1 ] 29 | imesh['periodic'] = numpy.array([True, True, True]) 30 | imesh['coordsys'] = 3 31 | imesh['dim'] = 3 32 | imesh['function'] = myMesh 33 | 34 | 35 | ss = pyrandaSim('curved_advection',imesh) 36 | 37 | 38 | eom = """ 39 | ddt(:phi:) = -div( :phi: * :u: , :phi:*:v: ) 40 | """ 41 | 42 | ss.EOM(eom) 43 | 44 | ic = """ 45 | r = sqrt( (meshx-pi)**2 + (meshy-pi)**2 ) 46 | :u: = 1.0 47 | :v: = 0.0 48 | :phi: = 1.0 + 0.1 * exp( -(r/(pi/4.0))**2 ) 49 | """ 50 | 51 | # Set the initial conditions 52 | ss.setIC(ic) 53 | 54 | 55 | # Mesh for viz on master 56 | x = ss.mesh.coords[0].data 57 | y = ss.mesh.coords[1].data 58 | xx = ss.PyMPI.zbar( x ) 59 | yy = ss.PyMPI.zbar( y ) 60 | 61 | # Time step size 62 | v = 1.0 63 | dt_max = v / ss.mesh.nn[0] * L * .590 64 | tt = L/v * 1.0 65 | 66 | 67 | # Main time loop for physics 68 | dt = dt_max 69 | cnt = 1 70 | time = 0.0 71 | viz = True 72 | viz_freq = 25 73 | while tt > time: 74 | 75 | 76 | #raw_input('Pause...') 77 | 78 | time = ss.rk4(time,dt) 79 | dt = min(dt_max, (tt - time) ) 80 | 81 | ss.iprint("%s -- %s" % (cnt,time) ) 82 | 83 | 84 | phi = ss.PyMPI.zbar( ss.variables['phi'].data ) 85 | if (ss.PyMPI.master) and (cnt%viz_freq == 1) :#or True: 86 | 87 | plt.figure(1) 88 | plt.clf() 89 | plt.contourf( xx,yy,phi ,64 , cmap=cm.jet) 90 | plt.pause(.001) 91 | 92 | cnt += 1 93 | 94 | 95 | phi = ss.PyMPI.zbar( ss.variables['phi'].data ) 96 | if (ss.PyMPI.master): 97 | plt.figure(1) 98 | plt.clf() 99 | plt.contourf( xx,yy,phi ,64 , cmap=cm.jet) 100 | plt.pause(.001) 101 | -------------------------------------------------------------------------------- /examples/SOD.py: -------------------------------------------------------------------------------- 1 | import re 2 | import sys 3 | import time 4 | import numpy 5 | import matplotlib.pyplot as plt 6 | from matplotlib import cm 7 | 8 | from pyranda import pyrandaSim, pyrandaBC 9 | from pyranda.pyranda import pyrandaRestart 10 | 11 | 12 | ## Define a mesh 13 | L = numpy.pi * 2.0 14 | Npts = 200 15 | Lp = L * (Npts-1.0) / Npts 16 | 17 | imesh = """ 18 | xdom = (0.0, Lp, Npts) 19 | """.replace('Lp',str(Lp)).replace('Npts',str(Npts)) 20 | 21 | # Initialize a simulation object on a mesh 22 | ss = pyrandaSim('sod',imesh) 23 | ss.addPackage( pyrandaBC(ss) ) 24 | 25 | 26 | # Define the equations of motion 27 | eom =""" 28 | # Primary Equations of motion here 29 | ddt(:rho:) = -ddx(:rho:*:u:) 30 | ddt(:rhou:) = -ddx(:rhou:*:u: + :p: - :tau:) 31 | ddt(:Et:) = -ddx( (:Et: + :p: - :tau:)*:u: ) 32 | # Conservative filter of the EoM 33 | :rho: = fbar( :rho: ) 34 | :rhou: = fbar( :rhou: ) 35 | :Et: = fbar( :Et: ) 36 | # Update the primatives and enforce the EOS 37 | :u: = :rhou: / :rho: 38 | :p: = ( :Et: - .5*:rho:*(:u:*:u:) ) * ( :gamma: - 1.0 ) 39 | # Artificial bulk viscosity (old school way) 40 | :div: = ddx(:u:) 41 | :beta: = gbar( ring(:div:) * :rho:) * 7.0e-2 42 | :tau: = :beta:*:div: 43 | # Apply constant BCs 44 | bc.extrap(['rho','Et'],['x1']) 45 | bc.const(['u'],['x1','xn'],0.0) 46 | """ 47 | 48 | # Add the EOM to the solver 49 | ss.EOM(eom) 50 | 51 | 52 | # Initial conditions SOD shock tube in 1d 53 | ic = """ 54 | :gamma: = 1.4 55 | :Et: = gbar( where( meshx < pi, 1.0/(:gamma:-1.0) , .1 /(:gamma:-1.0) ) ) 56 | :rho: = gbar( where( meshx < pi, 1.0 , .125 ) ) 57 | """ 58 | 59 | # Set the initial conditions 60 | ss.setIC(ic) 61 | 62 | 63 | # Write a time loop 64 | time = 0.0 65 | 66 | # Approx a max dt and stopping time 67 | v = 1.0 68 | dt_max = v / ss.mesh.nn[0] * 0.75 69 | tt = L/v * .25 #dt_max 70 | 71 | # Start time loop 72 | dt = dt_max 73 | cnt = 1 74 | viz_freq = 25 75 | pvar = 'rho' 76 | viz = True 77 | 78 | while tt > time: 79 | 80 | # Update the EOM and get next dt 81 | time = ss.rk4(time,dt) 82 | dt = min(dt_max, (tt - time) ) 83 | 84 | # Print some output 85 | ss.iprint("%s -- %s" % (cnt,time) ) 86 | cnt += 1 87 | if viz: 88 | 89 | if (cnt%viz_freq == 0): 90 | ss.plot.figure(1) 91 | plt.clf() 92 | ss.plot.plot(pvar,'b.-') 93 | 94 | 95 | ss.writeGrid() 96 | ss.write() 97 | -------------------------------------------------------------------------------- /examples/heat1D.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function 2 | import sys 3 | import time 4 | import numpy 5 | import matplotlib.pyplot as plt 6 | 7 | from pyranda import pyrandaSim, pyrandaBC 8 | 9 | # Try to get args 10 | try: 11 | Npts = int(sys.argv[1]) 12 | except: 13 | Npts = 16 14 | 15 | try: 16 | test = bool(sys.argv[2]) 17 | except: 18 | test = False 19 | 20 | ## Define a mesh 21 | L = numpy.pi * 2.0 22 | Lp = L * (Npts-1.0) / Npts 23 | 24 | 25 | mesh_options = {} 26 | mesh_options['coordsys'] = 0 27 | mesh_options['periodic'] = numpy.array([False, True, True]) 28 | mesh_options['dim'] = 1 29 | mesh_options['x1'] = [ 0.0 , 0.0 , 0.0 ] 30 | mesh_options['xn'] = [ Lp , Lp , Lp ] 31 | mesh_options['nn'] = [ Npts, 1 , 1 ] 32 | 33 | # Initialize a simulation object on a mesh 34 | ss = pyrandaSim('heat_equation',mesh_options) 35 | 36 | ss.addPackage( pyrandaBC(ss) ) 37 | 38 | 39 | 40 | # Define the equations of motion 41 | eom = """ 42 | # Heat equation 43 | ddt(:phi:) = :c: * lap(:phi:) 44 | # Boundary condition 45 | bc.const(['phi'],['x1'],2.0) 46 | bc.const(['phi'],['xn'],1.0) 47 | """ 48 | ss.EOM(eom) 49 | 50 | # Initialize variables 51 | ic = """ 52 | xnn = meshx[-1,0,0] 53 | :phi: = 1.0 + 1.0*(xnn - meshx)/xnn 54 | :c: = 1.0 55 | """ 56 | ss.setIC(ic) 57 | 58 | x = ss.mesh.coords[0].data 59 | xx = ss.PyMPI.zbar( x ) 60 | 61 | # Time step size 62 | dt_max = L / ss.mesh.nn[0] * .005 63 | tt = dt_max * 500 64 | 65 | 66 | # Main time loop for physics 67 | dt = dt_max 68 | cnt = 1 69 | time = 0.0 70 | viz = True 71 | while tt > time: 72 | 73 | time = ss.rk4(time,dt) 74 | dt = min(dt_max, (tt - time) ) 75 | 76 | if not test: 77 | ss.iprint("%s -- %s" % (cnt,time) ) 78 | 79 | # Plot animation of advection 80 | xnn = xx[-1,0] 81 | anl = 1.0 + 1.0*(xnn - xx)/xnn 82 | v = ss.PyMPI.zbar( ss.variables['phi'].data ) 83 | 84 | error = numpy.abs( anl - v ) 85 | 86 | cnt += 1 87 | if viz: 88 | if (ss.PyMPI.master and (cnt%50 == 0)) and (not test): 89 | plt.figure(1) 90 | plt.clf() 91 | 92 | plt.plot(xx[:,0],v[:,0],'k.-') 93 | plt.plot(xx[:,0],anl[:,0],'b.-') 94 | plt.plot(xx[:,0],error[:,0],'b.-') 95 | plt.pause(.001) 96 | 97 | print(numpy.sum( error[:,0] )) 98 | 99 | 100 | 101 | -------------------------------------------------------------------------------- /examples/tutorials/Euler2D.py: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | # Copyright (c) 2018, Lawrence Livemore National Security, LLC. 3 | # Produced at the Lawrence Livermore National Laboratory. 4 | # 5 | # LLNL-CODE-749864 6 | # This file is part of pyranda 7 | # For details about use and distribution, please read: pyranda/LICENSE 8 | # 9 | # Written by: Britton J. Olson, olson45@llnl.gov 10 | ################################################################################ 11 | from pyranda import pyrandaSim, pyrandaBC 12 | from numpy import pi 13 | 14 | # Domain is specified with a "mesh dictionary" 15 | mesh_options = {} 16 | mesh_options['x1'] = [ 0.0 , 0.0 , 0.0 ] 17 | mesh_options['xn'] = [ 2.0*pi , 2.0*pi , 1.0 ] 18 | mesh_options['nn'] = [ 64 , 64 , 1 ] 19 | 20 | ss = pyrandaSim('sod',mesh_options) 21 | 22 | 23 | ss.addPackage( pyrandaBC(ss) ) 24 | 25 | 26 | # Define the equations of motion 27 | eom =""" 28 | # Primary Equations of motion here 29 | ddt(:rho:) = -ddx(:rho:*:u:) - ddy(:rho:*:v:) 30 | ddt(:rhou:) = -ddx(:rhou:*:u: + :p: - :tau:) - ddy(:rhou:*:v:) 31 | ddt(:rhov:) = -ddx(:rhov:*:u:) - ddy(:rhov:*:v: + :p: - :tau:) 32 | ddt(:Et:) = -ddx( (:Et: + :p: - :tau:)*:u: ) - ddy( (:Et: + :p: - :tau:)*:v: ) 33 | # Conservative filter of the EoM 34 | :rho: = fbar( :rho: ) 35 | :rhou: = fbar( :rhou: ) 36 | :rhov: = fbar( :rhov: ) 37 | :Et: = fbar( :Et: ) 38 | # Update the primatives and enforce the EOS 39 | :u: = :rhou: / :rho: 40 | :v: = :rhov: / :rho: 41 | :p: = ( :Et: - .5*:rho:*(:u:*:u: + :v:*:v:) ) * ( :gamma: - 1.0 ) 42 | # Artificial bulk viscosity (old school way) 43 | :div: = ddx(:u:) + ddy(:v:) 44 | :beta: = gbar(abs(ring(:div:))) * :rho: * 7.0e-2 45 | :tau: = :beta:*:div: 46 | # Apply wall BC's 47 | bc.extrap(['rho','Et'],['x1','xn','y1','yn']) 48 | bc.const(['u','v'],['x1','xn','y1','yn'],0.0) 49 | :umag: = sqrt( :u:*:u: + :v:*:v: ) 50 | """ 51 | 52 | # Add the EOM to the solver 53 | ss.EOM(eom) 54 | 55 | # Initial conditions SOD-like problem in 2d 56 | ic = """ 57 | rad = sqrt( (meshx-pi)**2 + (meshy-pi)**2 ) 58 | :gamma: = 1.4 59 | :Et: = gbar( where( rad < pi/2.0, 1.0/(:gamma:-1.0) , .1 /(:gamma:-1.0) ) ) 60 | :rho: = gbar( where( rad < pi/2.0, 1.0 , .125 ) ) 61 | """ 62 | 63 | # Set the initial conditions 64 | ss.setIC(ic) 65 | 66 | # Approx a max dt and stopping time 67 | dt = .01 68 | tt = .75 69 | time = 0.0 70 | while tt > time: 71 | time = ss.rk4(time,dt) 72 | 73 | ss.plot.figure(1) 74 | ss.plot.clf() 75 | ss.plot.contourf('umag',16) 76 | -------------------------------------------------------------------------------- /examples/mesh.py: -------------------------------------------------------------------------------- 1 | from mpi4py import MPI 2 | import numpy 3 | import re 4 | import sys 5 | import time 6 | # TODO: remove 7 | sys.path.append('/Users/olson45/Research/FloATPy') 8 | 9 | import matplotlib.pyplot as plt 10 | 11 | from pyranda import pyrandaSim,pyrandaMPI 12 | 13 | 14 | 15 | 16 | Npts = 64 17 | L = numpy.pi * 2.0 18 | Lp = L * (Npts-1.0) / Npts 19 | 20 | mesh_options = {} 21 | mesh_options['type'] = 'cartesian' 22 | mesh_options['periodic'] = numpy.array([True, True, True]) 23 | mesh_options['dim'] = 3 24 | mesh_options['x1'] = [ 0.0 , 0.0 , 0.0 ] 25 | mesh_options['xn'] = [ Lp , Lp , Lp ] 26 | mesh_options['nn'] = [ Npts, Npts , 1 ] 27 | 28 | 29 | ss = pyrandaSim('advection',mesh_options) 30 | 31 | ss.addVar('phi' , kind='conserved' ) 32 | ss.addVar('Cx' , kind='constant' ) 33 | ss.addVar('Cy' , kind='constant' ) 34 | 35 | eq = 'ddt(:phi:) = - :Cx: * ddx( :phi: ) - :Cy: * ddy(:phi:)' 36 | ss.addEqu( eq ) 37 | 38 | eq = ':phi: = fbar( :phi: )' 39 | ss.addEqu( eq ) 40 | 41 | ss.allocate() 42 | 43 | 44 | x = ss.mesh.coords[0].data 45 | y = ss.mesh.coords[1].data 46 | z = ss.mesh.coords[2].data 47 | rad = numpy.sqrt( (x-numpy.pi)**2 + (y-numpy.pi)**2 ) #+ (z-numpy.pi)**2 ) 48 | 49 | ss.variables['phi'].data = numpy.exp( -(rad)**2/(.8**2) ) 50 | #ss.variables['phi'].data = numpy.sin( x ) 51 | 52 | theta = 45.0*numpy.pi / 180.0 53 | 54 | v = 1.0 55 | ss.variables['Cx'].data = v * numpy.cos( theta ) 56 | ss.variables['Cy'].data = v * numpy.sin( theta ) 57 | 58 | d = L / numpy.cos( theta ) 59 | 60 | #plt.ion() 61 | time = 0.0 62 | viz = False 63 | 64 | 65 | 66 | tt = d/v 67 | 68 | dt_max = v / ss.mesh.nn[0] * .75 69 | 70 | 71 | phi1 = ss.PyMPI.zbar( ss.variables['phi'].data ) 72 | xx = ss.PyMPI.zbar( x ) 73 | yy = ss.PyMPI.zbar( y ) 74 | if ss.PyMPI.master: 75 | plt.figure(1) 76 | plt.contour( xx,yy,phi1 , 32 ) 77 | plt.figure(2) 78 | plt.plot(xx[:,Npts/2],phi1[:,Npts/2],'k--') 79 | 80 | 81 | 82 | dt = dt_max 83 | cnt = 1 84 | while tt > time: 85 | 86 | 87 | time = ss.rk4(time,dt) 88 | dt = min(dt_max, (tt - time) ) 89 | 90 | #if time >= tt: 91 | # break 92 | 93 | ss.iprint("%s -- %s" % (cnt,time) ) 94 | cnt += 1 95 | if viz: 96 | plt.figure(1) 97 | plt.clf() 98 | plt.plot( ss.variables['phi'].data[:,16,0] ) 99 | plt.pause(.001) 100 | input('Press Enter') 101 | 102 | 103 | phi = ss.PyMPI.zbar( ss.variables['phi'].data ) 104 | if ss.PyMPI.master: 105 | plt.figure(1) 106 | plt.contour( xx,yy,phi , 32 ) 107 | plt.figure(2) 108 | plt.plot(xx[:,Npts/2],phi[:,Npts/2],'b-') 109 | 110 | plt.figure(3) 111 | plt.plot(xx[:,Npts/2],numpy.abs(phi[:,Npts/2]-phi1[:,Npts/2]),'b-') 112 | 113 | plt.show() 114 | -------------------------------------------------------------------------------- /pyranda/pyrandaProbes.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018, Lawrence Livemore National Security, LLC. 2 | # Produced at the Lawrence Livermore National Laboratory. 3 | # 4 | # LLNL-CODE-749864 5 | # This file is part of pyranda 6 | # For details about use and distribution, please read: pyranda/LICENSE 7 | # 8 | # Written by: Britton J. Olson, olson45@llnl.gov 9 | ################################################################################ 10 | import numpy 11 | from mpi4py import MPI 12 | from .pyrandaPackage import pyrandaPackage 13 | from .pyrandaMisc import ipoint 14 | 15 | class pyrandaProbes(pyrandaPackage): 16 | 17 | def __init__(self,pysim,x=None,y=None,z=None): 18 | 19 | PackageName = 'Probes' 20 | pyrandaPackage.__init__(self,PackageName,pysim) 21 | 22 | self.xpts = x 23 | self.ypts = y 24 | 25 | self.pysim = pysim 26 | # 3D not supported for now. 27 | self.zpts = None 28 | 29 | self.values = None 30 | 31 | self.points = [] 32 | 33 | xmesh = pysim.PyMPI.ghost( pysim.x().data, 1)[:,:,0] 34 | ymesh = pysim.PyMPI.ghost( pysim.y().data, 1)[:,:,0] 35 | for ix,iy in zip(self.xpts,self.ypts): 36 | self.points.append( ipoint(ix,iy,xmesh,ymesh) ) 37 | 38 | def getOld(self,var,method='linear' ): 39 | 40 | # Get the pysim data 41 | values = [] 42 | vdata = self.pysim.PyMPI.ghost( self.pysim.variables[var].data, 1 ) 43 | vals = vdata[:,:,0] 44 | 45 | # Get interpolated values 46 | for pt in self.points: 47 | values.append( pt.interp( vals,method ) ) 48 | 49 | # Communicate 50 | Lvalues = numpy.array( values ) 51 | Gvalues = self.pysim.PyMPI.comm.allreduce( Lvalues, op=MPI.SUM ) 52 | 53 | self.values = Gvalues 54 | return self.values 55 | 56 | def get(self,var ): 57 | 58 | # Get the pysim data 59 | values = [] 60 | vdata = self.pysim.PyMPI.ghost( self.pysim.variables[var].data, 1 ) 61 | vals = vdata[:,:,0] 62 | 63 | # Get interpolated values 64 | for pt in self.points: 65 | values.append( pt.interpFast( vals ) ) 66 | 67 | # Communicate 68 | Lvalues = numpy.array( values ) 69 | Gvalues = self.pysim.PyMPI.comm.allreduce( Lvalues, op=MPI.SUM ) 70 | 71 | self.values = Gvalues 72 | return self.values 73 | 74 | 75 | def plot(self,var=None,style=None): 76 | 77 | 78 | # Plot the probes on the current figure 79 | #if not var: 80 | # self.get(var) 81 | 82 | #vals = self.values 83 | x = self.xpts 84 | y = self.ypts 85 | 86 | if self.pysim.PyMPI.master: 87 | import matplotlib.pyplot as plt 88 | if style: 89 | plt.plot( x , y, style) 90 | else: 91 | plt.plot( x , y ,'ko') 92 | 93 | plt.pause(.1) 94 | -------------------------------------------------------------------------------- /tests/testObj.py: -------------------------------------------------------------------------------- 1 | # Run a bunch of test and check answers 2 | from __future__ import print_function 3 | import os,sys 4 | import numpy as npy 5 | import subprocess 6 | import matplotlib.pyplot as plt 7 | 8 | def sexe(cmd,ret_output=False,echo = False): 9 | """ Helper for executing shell commands. """ 10 | if echo: 11 | print("[exe: %s]" % cmd) 12 | if ret_output: 13 | p = subprocess.Popen(cmd, 14 | shell=True, 15 | stdout=subprocess.PIPE, 16 | stderr=subprocess.STDOUT) 17 | res =p.communicate()[0] 18 | return p.returncode,res 19 | else: 20 | return subprocess.call(cmd,shell=True) 21 | 22 | 23 | def baseDict(string): 24 | dbase = {} 25 | # Make dictionary 26 | for bb in string.split('\n'): 27 | if bb: 28 | name = bb.split('--')[0].strip() 29 | diff = bb.split('--')[1].strip() 30 | dbase[name] = diff 31 | return dbase 32 | 33 | def relDict(string): 34 | dbase = {} 35 | # Make dictionary 36 | for bb in string.split('\n'): 37 | if bb: 38 | name = bb.split('--')[0].strip() 39 | try: 40 | relE = float(bb.split('--')[2].strip()) 41 | except: 42 | relE = 1.0e-4 43 | dbase[name] = relE 44 | return dbase 45 | 46 | 47 | def checkScalar(baseline,pout): 48 | if abs(baseline) > 0.0: 49 | diff = npy.abs( float(pout)-baseline ) / npy.abs( baseline ) 50 | else: 51 | diff = npy.abs( float(pout)-baseline ) 52 | return diff 53 | 54 | 55 | def checkProfile( baseline, pout ): 56 | 57 | baseline = 'baselines/%s' % baseline 58 | 59 | base = npy.loadtxt( baseline ) 60 | test = npy.loadtxt( pout ) 61 | 62 | minLen = min( base.shape[1], test.shape[1] ) 63 | diff = npy.abs( base[1,:minLen] - test[1,:minLen] ) / npy.max( npy.abs( base[1,:minLen] ) ) 64 | 65 | m_diff = npy.max( diff ) 66 | 67 | 68 | return m_diff 69 | 70 | def plotError( baseline, pout ): 71 | 72 | baseline = 'baselines/%s' % baseline 73 | 74 | base = npy.loadtxt( baseline ) 75 | test = npy.loadtxt( pout ) 76 | minLen = min( base.shape[1], test.shape[1] ) 77 | 78 | diff = (npy.abs( base[1,:minLen] - test[1,:minLen] ) 79 | / npy.max( npy.abs( base[1,:minLen] ) ) ) 80 | 81 | plt.figure() 82 | plt.plot([1,2,3]) 83 | plt.subplot(121) 84 | plt.plot(base[0,:],base[1,:],'k-',label='Baseline') 85 | plt.plot(test[0,:],test[1,:],'b-',label='New test') 86 | plt.legend() 87 | 88 | plt.subplot(122) 89 | plt.plot(base[0,:],diff,'r-') 90 | 91 | 92 | class testObj: 93 | 94 | def __init__(self,name): 95 | 96 | self.name = name 97 | self.parallel = False 98 | self.np = 1 99 | self.script = '' 100 | self.args = None 101 | -------------------------------------------------------------------------------- /pyranda/pyrandaTimestep.py: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | # Copyright (c) 2018, Lawrence Livemore National Security, LLC. 3 | # Produced at the Lawrence Livermore National Laboratory. 4 | # 5 | # LLNL-CODE-749864 6 | # This file is part of pyranda 7 | # For details about use and distribution, please read: pyranda/LICENSE 8 | # 9 | # Written by: Britton J. Olson, olson45@llnl.gov 10 | ################################################################################ 11 | import numpy 12 | from .pyrandaPackage import pyrandaPackage 13 | 14 | 15 | class pyrandaTimestep(pyrandaPackage): 16 | """ 17 | Case physics package module for adding new physics packages to pyranda 18 | """ 19 | def __init__(self,pysim): 20 | 21 | PackageName = 'Timestep' 22 | pyrandaPackage.__init__(self,PackageName,pysim) 23 | 24 | self.dx = pysim.mesh.d1 25 | self.dy = pysim.mesh.d2 26 | self.dz = pysim.mesh.d3 27 | self.pysim = pysim 28 | self.GridLen = pysim.mesh.GridLen 29 | 30 | 31 | def get_sMap(self): 32 | """ 33 | String mappings for this package. Packages added to the main 34 | pyranda object will check this map 35 | """ 36 | sMap = {} 37 | sMap['dt.courant('] = "self.packages['Timestep'].courant(" 38 | sMap['dt.diff('] = "self.packages['Timestep'].diff(" 39 | sMap['dt.diffDir('] = "self.packages['Timestep'].diffDir(" 40 | self.sMap = sMap 41 | 42 | def courant(self,u,v,w,c): 43 | 44 | # Compute the dt for the courant limit 45 | if self.pysim.mesh.coordsys == 3: 46 | dAdx = self.pysim.getVar("dAx") 47 | dAdy = self.pysim.getVar("dAy") 48 | dBdx = self.pysim.getVar("dBx") 49 | dBdy = self.pysim.getVar("dBy") 50 | magA = numpy.sqrt( dAdx*dAdx + dAdy*dAdy ) 51 | magB = numpy.sqrt( dBdx*dBdx + dBdy*dBdy ) 52 | uA = ( u*dAdx + v*dAdy ) / magA 53 | uB = ( u*dBdx + v*dBdy ) / magB 54 | vrate = ( numpy.abs(uA) / self.pysim.getVar('d1') + 55 | numpy.abs(uB) / self.pysim.getVar('d2') ) 56 | 57 | else: 58 | vrate = ( numpy.abs(u) / self.dx + 59 | numpy.abs(v) / self.dy + 60 | numpy.abs(w) / self.dz ) 61 | 62 | 63 | crate = numpy.abs(c) / self.GridLen 64 | 65 | dt_max = 1.0 / self.pyranda.PyMPI.max3D(vrate + crate) 66 | 67 | return dt_max 68 | 69 | 70 | 71 | def diff(self,bulk,density): 72 | 73 | delta = self.GridLen 74 | drate = density * delta * delta / numpy.maximum( 1.0e-12, bulk ) 75 | dt_max = self.pyranda.PyMPI.min3D( drate ) 76 | 77 | return dt_max 78 | 79 | 80 | def diffDir(self,bulk,density,delta): 81 | 82 | drate = density * delta * delta / numpy.maximum( 1.0e-12, bulk ) 83 | dt_max = self.pyranda.PyMPI.min3D( drate ) 84 | 85 | return dt_max 86 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # pyranda 2 | [![Build Status](https://github.com/LLNL/pyranda/actions/workflows/regression-tests.yaml/badge.svg)](https://github.com/LLNL/pyranda/actions) 3 | 4 | A Python driven, Fortran powered Finite Difference solver for arbitrary hyperbolic PDE systems. This is the mini-app for the Miranda code. 5 | 6 | The PDE solver defaults to a 10th order compact finite difference method for spatial derivatives, and a 5-stage, 4th order Runge-Kutta scheme for temporal integration. Other numerical methods will be added in the future. 7 | 8 | Pyranda parses (through a simple interpreter) the full definition of a system of PDEs, namely: 9 | - a domain and discretization (in 1D, 2D or 3D) 10 | - governing equations written on RHS of time derivatives. 11 | - initial values for all variables 12 | - boundary conditions 13 | 14 | 15 | 16 | ## Prerequisites 17 | At a minimum, your system will need the following installed to run pyranda. (see install notes for detailed instructions) 18 | - A fortran compiler with MPI support 19 | - python 2.7, including these packages 20 | - numpy 21 | - mpi4py 22 | 23 | ## Tutorials 24 | A few tutorials are included on the [project wiki page](https://github.com/LLNL/pyranda/wiki) that cover the example below, as well as few others. A great place to start if you want to discover what types of problems you can solve. 25 | 26 | 27 | ## Example Usage - Solve the 1D advection equation in less than 10 lines of code 28 | [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/LLNL/pyranda/blob/master/examples/tutorials/notebooks/advection.ipynb) 29 | 30 | The one-dimensional advection equation is written as: 31 | 32 | ![Advection](http://mathurl.com/y7qnvzeg.png) 33 | 34 | where phi is a scalar and where c is the advection velocity, assumed to be unity. We solve this equation 35 | in 1D, in the x-direction from (0,1) using 100 points and evolve the solution .1 units in time. 36 | 37 | ### 1 - Import pyranda 38 | `from pyranda import pyrandaSim` 39 | 40 | ### 2 - Initialize a simulation object on a domain/mesh 41 | `pysim = pyrandaSim('advection',"xdom = (0.0 , 1.0 , 100 )")` 42 | 43 | ### 3 - Define the equations of motion 44 | `pysim.EOM(" ddt(:phi:) = - ddx(:phi:) ")` 45 | 46 | ### 4 - Initialize variables 47 | `pysim.setIC(":phi: = 1.0 + 0.1 * exp( -(abs(meshx-.5)/.1 )**2 )")` 48 | 49 | ### 5 - Integrate in time 50 | `dt = .001` 51 | `time = 0.0` 52 | `while time < .1:` 53 |    `time = pysim.rk4(time,dt)` 54 | 55 | ### 6 - Plot the solution 56 | `pysim.plot.plot('phi')` 57 | 58 | alt text 59 | 60 | 61 | ## Cite 62 | 63 | Please us the folowing bibtex, when you refer to this project. 64 | 65 | ``` 66 | @misc{pyrandaCode, 67 | title = {Pyranda: A Python driven, Fortran powered Finite Difference solver for arbitrary hyperbolic PDE systems and mini-app for the LLNL Miranda code}, 68 | author = {Olson, Britton}, 69 | url = https://github.com/LLNL/pyranda}, 70 | year = {2023} 71 | } 72 | ``` 73 | 74 | -------------------------------------------------------------------------------- /tests/baselines/cylinder-2d-64.dat: -------------------------------------------------------------------------------- 1 | 0.000000000000000000e+00 9.817477042468103487e-02 1.963495408493620697e-01 2.945243112740431046e-01 3.926990816987241395e-01 4.908738521234051189e-01 5.890486225480862092e-01 6.872233929727671331e-01 7.853981633974482790e-01 8.835729338221292029e-01 9.817477042468103487e-01 1.079922474671491273e+00 1.178097245096172418e+00 1.276272015520853342e+00 1.374446785945534488e+00 1.472621556370215412e+00 1.570796326794896558e+00 1.668971097219577482e+00 1.767145867644258628e+00 1.865320638068939552e+00 1.963495408493620475e+00 2.061670178918301843e+00 2.159844949342982989e+00 2.258019719767664135e+00 2.356194490192344837e+00 2.454369260617025983e+00 2.552544031041707129e+00 2.650718801466388275e+00 2.748893571891068976e+00 2.847068342315750122e+00 2.945243112740431268e+00 3.043417883165112414e+00 3.141592653589793116e+00 3.239767424014474262e+00 3.337942194439155408e+00 3.436116964863836554e+00 3.534291735288517255e+00 3.632466505713198401e+00 3.730641276137879547e+00 3.828816046562560693e+00 3.926990816987241395e+00 4.025165587411922985e+00 4.123340357836603687e+00 4.221515128261284389e+00 4.319689898685965979e+00 4.417864669110646680e+00 4.516039439535327382e+00 4.614214209960008972e+00 4.712388980384689674e+00 4.810563750809371264e+00 4.908738521234051966e+00 5.006913291658732668e+00 5.105088062083414258e+00 5.203262832508094959e+00 5.301437602932775661e+00 5.399612373357457251e+00 5.497787143782137953e+00 5.595961914206819543e+00 5.694136684631500245e+00 5.792311455056180947e+00 5.890486225480862537e+00 5.988660995905543238e+00 6.086835766330223940e+00 6.185010536754905530e+00 2 | 1.000000000000000000e+00 9.905749388930478183e-01 9.891411243611782922e-01 9.898047279532016240e-01 9.963151551482164470e-01 1.001471481335293401e+00 1.007558737513255753e+00 1.003502748156444691e+00 9.981579540389426963e-01 9.945409446252960750e-01 9.866628364560630082e-01 9.965152628366191756e-01 9.919245432450357614e-01 1.000818844903046179e+00 1.008101190672552994e+00 1.020007746576402585e+00 1.182765585294756949e+00 1.529203860649158697e+00 2.561567562108844065e+00 4.265843193305274283e+00 5.222628120426573872e+00 5.243245504086870845e+00 5.476649682333076363e+00 5.634016158493667881e+00 5.432429994629652370e+00 5.303040320498450200e+00 5.115878737323075853e+00 4.873180013679334621e+00 4.556727497856310372e+00 4.139077484634163362e+00 3.593800360008301720e+00 2.927158685780592240e+00 2.213716844674687767e+00 1.578220439796473196e+00 1.115319209219560515e+00 8.356707457070887690e-01 6.918403852167676060e-01 6.307455907893559921e-01 6.179062981424736645e-01 6.365679808745814405e-01 6.777510091315332996e-01 8.041848461305682871e-01 8.778642830922208651e-01 8.741476702731608706e-01 9.005430656392166000e-01 8.893495495511931637e-01 8.481715413556830674e-01 8.338133553105206985e-01 8.293556885400675815e-01 8.498247055366862091e-01 8.725646489218561452e-01 8.838173667430124780e-01 8.834879475479331390e-01 8.451047178834842910e-01 7.617305360401702696e-01 6.641866838217187485e-01 6.002549307527059730e-01 5.719703219648066828e-01 5.524644709170608570e-01 5.439906843889860122e-01 5.371482004316429082e-01 5.309185829120132150e-01 5.439070484536198125e-01 5.568955139952264100e-01 3 | -------------------------------------------------------------------------------- /tests/baselines/euler-2d-64.dat: -------------------------------------------------------------------------------- 1 | 0.000000000000000000e+00 9.817477042468103487e-02 1.963495408493620697e-01 2.945243112740431046e-01 3.926990816987241395e-01 4.908738521234051189e-01 5.890486225480862092e-01 6.872233929727671331e-01 7.853981633974482790e-01 8.835729338221292029e-01 9.817477042468103487e-01 1.079922474671491273e+00 1.178097245096172418e+00 1.276272015520853342e+00 1.374446785945534488e+00 1.472621556370215412e+00 1.570796326794896558e+00 1.668971097219577482e+00 1.767145867644258628e+00 1.865320638068939552e+00 1.963495408493620475e+00 2.061670178918301843e+00 2.159844949342982989e+00 2.258019719767664135e+00 2.356194490192344837e+00 2.454369260617025983e+00 2.552544031041707129e+00 2.650718801466388275e+00 2.748893571891068976e+00 2.847068342315750122e+00 2.945243112740431268e+00 3.043417883165112414e+00 3.141592653589793116e+00 3.239767424014474262e+00 3.337942194439155408e+00 3.436116964863836554e+00 3.534291735288517255e+00 3.632466505713198401e+00 3.730641276137879547e+00 3.828816046562560693e+00 3.926990816987241395e+00 4.025165587411922985e+00 4.123340357836603687e+00 4.221515128261284389e+00 4.319689898685965979e+00 4.417864669110646680e+00 4.516039439535327382e+00 4.614214209960008972e+00 4.712388980384689674e+00 4.810563750809371264e+00 4.908738521234051966e+00 5.006913291658732668e+00 5.105088062083414258e+00 5.203262832508094959e+00 5.301437602932775661e+00 5.399612373357457251e+00 5.497787143782137953e+00 5.595961914206819543e+00 5.694136684631500245e+00 5.792311455056180947e+00 5.890486225480862537e+00 5.988660995905543238e+00 6.086835766330223940e+00 6.185010536754905530e+00 2 | 1.124635497493928771e-01 1.285068314057678796e-01 1.445501130621428820e-01 1.811738007688645236e-01 2.224165090261963074e-01 2.386627441394727767e-01 2.382563897601501501e-01 2.324594259667207286e-01 2.357915918216165474e-01 2.657546148907399819e-01 3.037393673362802637e-01 3.233820129401559496e-01 3.316529610451957599e-01 3.380997046798633332e-01 3.432946299083446950e-01 3.565288186292148165e-01 3.830249121679306090e-01 4.183664248779882522e-01 4.595084351071458406e-01 5.052493743029969897e-01 5.548601784867365216e-01 6.080443633651695379e-01 6.642273443611103056e-01 7.226609706161359892e-01 7.821600926758727201e-01 8.409294505915434481e-01 8.961961794939079518e-01 9.438199676834426732e-01 9.781339133184389079e-01 9.953886296562465263e-01 9.997000057280375218e-01 9.999272229305771198e-01 1.000078136796443307e+00 9.999276219277281053e-01 9.997008314237404436e-01 9.953883507966932997e-01 9.781171281272771356e-01 9.437732395932167950e-01 8.961537733681310680e-01 8.409317536038138918e-01 7.822360010601592251e-01 7.227824745506487014e-01 6.643184961337486039e-01 6.081176765506222104e-01 5.548916497203660869e-01 5.052447222445225483e-01 4.593711642122163541e-01 4.181216877380854458e-01 3.827567502391980292e-01 3.562949756869492890e-01 3.431777063532784333e-01 3.379998791272637026e-01 3.318124823870234885e-01 3.234108394690827781e-01 3.037365921328667451e-01 2.655865239301380964e-01 2.360432914848150376e-01 2.334981752109168418e-01 2.386308181577634913e-01 2.405387341641820609e-01 2.199154617985533966e-01 1.748075417799928033e-01 1.412685142389323023e-01 1.077294866978718013e-01 3 | -------------------------------------------------------------------------------- /tests/baselines/KelvinHelmholtzKH-2d-64.dat: -------------------------------------------------------------------------------- 1 | 0.000000000000000000e+00 1.562500000000000000e-02 3.125000000000000000e-02 4.687500000000000000e-02 6.250000000000000000e-02 7.812500000000000000e-02 9.375000000000000000e-02 1.093750000000000000e-01 1.250000000000000000e-01 1.406250000000000000e-01 1.562500000000000000e-01 1.718750000000000000e-01 1.875000000000000000e-01 2.031250000000000000e-01 2.187500000000000000e-01 2.343750000000000000e-01 2.500000000000000000e-01 2.656250000000000000e-01 2.812500000000000000e-01 2.968750000000000000e-01 3.125000000000000000e-01 3.281250000000000000e-01 3.437500000000000000e-01 3.593750000000000000e-01 3.750000000000000000e-01 3.906250000000000000e-01 4.062500000000000000e-01 4.218750000000000000e-01 4.375000000000000000e-01 4.531250000000000000e-01 4.687500000000000000e-01 4.843750000000000000e-01 5.000000000000000000e-01 5.156250000000000000e-01 5.312500000000000000e-01 5.468750000000000000e-01 5.625000000000000000e-01 5.781250000000000000e-01 5.937500000000000000e-01 6.093750000000000000e-01 6.250000000000000000e-01 6.406250000000000000e-01 6.562500000000000000e-01 6.718750000000000000e-01 6.875000000000000000e-01 7.031250000000000000e-01 7.187500000000000000e-01 7.343750000000000000e-01 7.500000000000000000e-01 7.656250000000000000e-01 7.812500000000000000e-01 7.968750000000000000e-01 8.125000000000000000e-01 8.281250000000000000e-01 8.437500000000000000e-01 8.593750000000000000e-01 8.750000000000000000e-01 8.906250000000000000e-01 9.062500000000000000e-01 9.218750000000000000e-01 9.375000000000000000e-01 9.531250000000000000e-01 9.687500000000000000e-01 9.843750000000000000e-01 2 | 1.876190654953457049e+00 1.829375237094084339e+00 1.752486869883273179e+00 1.648445585674381819e+00 1.536158264105951465e+00 1.449900027441602512e+00 1.414758285878209287e+00 1.427390941809017377e+00 1.459103495596771216e+00 1.471960908202980978e+00 1.439254555530596447e+00 1.361548327034455719e+00 1.266134702406757961e+00 1.187817614022169455e+00 1.141004249759362210e+00 1.119727602983145109e+00 1.114942215084194999e+00 1.117735591145551988e+00 1.124736624757284531e+00 1.131062885971871212e+00 1.152113602309013940e+00 1.212284079966770456e+00 1.300622220143474284e+00 1.447349834094870058e+00 1.662819979282401217e+00 1.833176675268036515e+00 1.908732387769023431e+00 1.939578454698136722e+00 1.939853752919855623e+00 1.925382588263851114e+00 1.915182572245420767e+00 1.901358078955860620e+00 1.876190654954075443e+00 1.829375237094101880e+00 1.752486869883794096e+00 1.648445585674380931e+00 1.536158264106491034e+00 1.449900027441364259e+00 1.414758285877955934e+00 1.427390941808755365e+00 1.459103495596792532e+00 1.471960908203032048e+00 1.439254555530606217e+00 1.361548327034029615e+00 1.266134702406648938e+00 1.187817614021945856e+00 1.141004249759466793e+00 1.119727602983419112e+00 1.114942215084205213e+00 1.117735591145586405e+00 1.124736624757384229e+00 1.131062885971834575e+00 1.152113602309039919e+00 1.212284079966701622e+00 1.300622220143268226e+00 1.447349834095179588e+00 1.662819979283012062e+00 1.833176675268668232e+00 1.908732387768841576e+00 1.939578454698361654e+00 1.939853752919425967e+00 1.925382588263963024e+00 1.915182572245551329e+00 1.901358078955702746e+00 3 | -------------------------------------------------------------------------------- /tests/baselines/cylinder_curved-2d-64.dat: -------------------------------------------------------------------------------- 1 | -1.237002107350981106e+01 -1.182997825508175715e+01 -1.128993543788179466e+01 -1.074989262307038729e+01 -1.020984981529311142e+01 -9.669807028230868795e+00 -9.129764302172970858e+00 -8.589721755768557898e+00 -8.049679738430119968e+00 -7.509639279143851986e+00 -6.969603408119361632e+00 -6.429581048384397590e+00 -5.889598471293599147e+00 -5.349732989131818606e+00 -4.810211804683066639e+00 -4.271699904164053763e+00 -3.736120557348124649e+00 -3.208847646051017133e+00 -2.703508173477352727e+00 -2.246882841157279209e+00 -1.867566933692009323e+00 -1.567478731168435946e+00 -1.325862254097103898e+00 -1.122469438736413583e+00 -9.439877707771127113e-01 -7.822470082544548120e-01 -6.321380147957534890e-01 -4.903438215998728866e-01 -3.546295741017820857e-01 -2.234405296315564171e-01 -9.566619617468929970e-02 2.950368258849200842e-02 1.535548974676142209e-01 2.798267148358866141e-01 4.089665711434765649e-01 5.418332441528299626e-01 6.795792417554136211e-01 8.237727380784275466e-01 9.765813523675768160e-01 1.141052623117953413e+00 1.321541242915997172e+00 1.524335814280182611e+00 1.758459271373421950e+00 2.036222895849919112e+00 2.371906013206435127e+00 2.775324477016367641e+00 3.241157523660439743e+00 3.748501151788274477e+00 4.276077197220271131e+00 4.811695043379513592e+00 5.350211462280434205e+00 5.889733145052991503e+00 6.429598674953457049e+00 6.969581254167612983e+00 7.509603612996119004e+00 8.049639483525025341e+00 8.589679942621351927e+00 9.129721959892794558e+00 9.669764506274171723e+00 1.020980723232421283e+01 1.074985001938378382e+01 1.128989282716015197e+01 1.182993564197125025e+01 1.236997845917110794e+01 2 | 2.366431913239846363e+00 2.365459092174853062e+00 2.366240819596211242e+00 2.365785014454345081e+00 2.365577490699852348e+00 2.367595145130867440e+00 2.366545546801881450e+00 2.368011704236690385e+00 2.368125905380885854e+00 2.365157308519611146e+00 2.370472710465555632e+00 2.363797822259118497e+00 2.365223078956765868e+00 2.371994981170868932e+00 2.356698036051440681e+00 2.377654907046987010e+00 2.359982361255246630e+00 2.357635119848841665e+00 2.394781625852240303e+00 2.295716626430976959e+00 2.336988189178830666e+00 1.743581737438367751e+00 8.541255696936221886e-01 5.410252060309049815e-01 4.119048841105223402e-01 2.843846854899111376e-01 3.308447469804736696e-01 3.547333631982840796e-01 3.722558175169442540e-01 4.385889786796493550e-01 6.026783466854491733e-01 7.385840097598039833e-01 7.085121002157086512e-01 6.397475162070461741e-01 5.793018473047256700e-01 5.017135175592702945e-01 3.742325800428161764e-01 2.005580941245193316e-01 1.795195014502333208e-01 2.086255184809500396e-01 2.428307030946587342e-01 2.365900405854351740e-01 3.366018915537310474e-01 4.452797650401230101e-01 5.155450316526890564e-01 7.312251850537999642e-01 1.082736745520542110e+00 1.294333420957824554e+00 1.185956975669558267e+00 9.435284129002927678e-01 9.385942453500093485e-01 1.137384003002769095e+00 1.412320692165737190e+00 1.729392052860946327e+00 1.999331477142112901e+00 2.153857233519719916e+00 2.155954417701868575e+00 2.067669805103468761e+00 2.033338760670701628e+00 2.071752533251970174e+00 2.135290101984872901e+00 2.212506327518944715e+00 2.279577866653992757e+00 2.346653707494466445e+00 3 | -------------------------------------------------------------------------------- /tests/baselines/cylinder_omesh-2d-64.dat: -------------------------------------------------------------------------------- 1 | 5.571428571428571175e+00 5.544600620030811555e+00 5.464375133675140717e+00 5.331524727650877260e+00 5.147328823991454527e+00 4.913561329940835165e+00 4.632473554257037662e+00 4.306772525878105995e+00 3.939594923753622080e+00 3.534476868911739178e+00 3.095319869680641212e+00 2.626353248030559140e+00 2.132093408891214903e+00 1.617300344703432868e+00 1.086931794089857739e+00 5.460954961218384973e-01 3.411516083339055416e-16 -5.460954961218378312e-01 -1.086931794089857073e+00 -1.617300344703431980e+00 -2.132093408891214015e+00 -2.626353248030558696e+00 -3.095319869680639435e+00 -3.534476868911738290e+00 -3.939594923753621192e+00 -4.306772525878105995e+00 -4.632473554257038550e+00 -4.913561329940834277e+00 -5.147328823991454527e+00 -5.331524727650877260e+00 -5.464375133675140717e+00 -5.544600620030810667e+00 -5.571428571428571175e+00 -5.544600620030811555e+00 -5.464375133675140717e+00 -5.331524727650878148e+00 -5.147328823991455415e+00 -4.913561329940835165e+00 -4.632473554257038550e+00 -4.306772525878106883e+00 -3.939594923753622524e+00 -3.534476868911741398e+00 -3.095319869680640767e+00 -2.626353248030559584e+00 -2.132093408891217567e+00 -1.617300344703433534e+00 -1.086931794089859737e+00 -5.460954961218367210e-01 -1.023454825001716575e-15 5.460954961218347226e-01 1.086931794089857739e+00 1.617300344703431314e+00 2.132093408891215791e+00 2.626353248030557808e+00 3.095319869680638547e+00 3.534476868911739622e+00 3.939594923753620748e+00 4.306772525878104219e+00 4.632473554257037662e+00 4.913561329940833389e+00 5.147328823991453639e+00 5.331524727650877260e+00 5.464375133675139828e+00 5.544600620030811555e+00 2 | 1.545388472267181568e+00 1.581385107491545483e+00 1.649579160583112714e+00 1.720431363348836618e+00 1.815324536915375209e+00 1.901090921271884504e+00 1.925189432176474869e+00 1.917622421466032900e+00 1.896313012950467058e+00 1.860325612830895370e+00 1.816908313851578916e+00 1.773204669366153396e+00 1.753855814440038907e+00 1.763964083449976794e+00 1.771421434204806022e+00 1.773741747699922877e+00 1.775373322244460095e+00 1.774563792225184899e+00 1.774789735596613349e+00 1.775033242723012883e+00 1.774599551511705897e+00 1.774954990511725228e+00 1.774826906463654375e+00 1.774734668099299917e+00 1.774927158094439683e+00 1.774783349144146261e+00 1.774825692187600445e+00 1.774835453024625753e+00 1.774784087369561503e+00 1.774857156391075330e+00 1.774838516995436377e+00 1.774835158738496288e+00 1.774870774970701559e+00 1.774835158738561347e+00 1.774838516995526305e+00 1.774857156391169033e+00 1.774784087369658980e+00 1.774835453024705467e+00 1.774825692187622428e+00 1.774783349144067435e+00 1.774927158094250279e+00 1.774734668099067658e+00 1.774826906463486731e+00 1.774954990511652397e+00 1.774599551511651718e+00 1.775033242722940052e+00 1.774789735596564055e+00 1.774563792225167802e+00 1.775373322244460761e+00 1.773741747699937976e+00 1.771421434204814682e+00 1.763964083449961695e+00 1.753855814440003158e+00 1.773204669366109210e+00 1.816908313851541168e+00 1.860325612830872277e+00 1.896313012950461063e+00 1.917622421466061322e+00 1.925189432176528603e+00 1.901090921271916923e+00 1.815324536915388975e+00 1.720431363348822407e+00 1.649579160583084958e+00 1.581385107491538378e+00 3 | -------------------------------------------------------------------------------- /examples/elliptical.py: -------------------------------------------------------------------------------- 1 | # src-ch7/laplace_Diriclhet2.py 2 | import numpy as np 3 | import scipy 4 | import scipy.linalg 5 | import scipy.sparse 6 | import scipy.sparse.linalg 7 | #import matplotlib; matplotlib.use('Qt4Agg') 8 | #import matplotlib.pylab as plt 9 | import time 10 | from math import sinh 11 | 12 | import matplotlib.pyplot as plt 13 | 14 | # Change some default values to make plots more readable on the screen 15 | LNWDT=2; FNT=15 16 | plt.rcParams['lines.linewidth'] = LNWDT; plt.rcParams['font.size'] = FNT 17 | 18 | # Set temperature at the top 19 | Ttop=0 20 | Tbottom=0 21 | Tleft=0.0 22 | Tright=0.0 23 | 24 | xmax=1.0 25 | ymax=1.5 26 | 27 | # Set simulation parameters 28 | #need hx=(1/nx)=hy=(1.5/ny) 29 | Nx = 20 30 | h=xmax/Nx 31 | Ny = int(ymax/h) 32 | 33 | nx = Nx-1 34 | ny = Ny-1 35 | n = (nx)*(ny) #number of unknowns 36 | print(n, nx, ny) 37 | 38 | d = np.ones(n) # diagonals 39 | b = np.zeros(n) #RHS 40 | d0 = d*-4 41 | d1 = d[0:-1] 42 | d5 = d[0:-ny] 43 | 44 | A = scipy.sparse.diags([d0, d1, d1, d5, d5], [0, 1, -1, ny, -ny], format='csc') 45 | 46 | #alternatively (scalar broadcasting version:) 47 | #A = scipy.sparse.diags([1, 1, -4, 1, 1], [-5, -1, 0, 1, 5], shape=(15, 15)).toarray() 48 | 49 | # set elements to zero in A matrix where BC are imposed 50 | for k in range(1,nx): 51 | j = k*(ny) 52 | i = j - 1 53 | A[i, j], A[j, i] = 0, 0 54 | b[i] = -Ttop 55 | 56 | # Dirichlet BCs 57 | b[-ny:]+=-Tright #set the last ny elements to -Tright 58 | b[-1]+=-Ttop #set the last element to -Ttop 59 | b[0:ny-1]+=-Tleft #set the first ny elements to -Tleft 60 | b[0::ny]+=-Tbottom #set every ny-th element to -Tbottom 61 | 62 | # RHS 63 | b += -1.0 64 | 65 | tic=time.time() 66 | theta = scipy.sparse.linalg.spsolve(A,b) #theta=sc.linalg.solve_triangular(A,d) 67 | toc=time.time() 68 | print('sparse solver time:',toc-tic) 69 | 70 | # surfaceplot: 71 | x = np.linspace(0, xmax, Nx + 1) 72 | y = np.linspace(0, ymax, Ny + 1) 73 | 74 | X, Y = np.meshgrid(x, y) 75 | 76 | T = np.zeros_like(X) 77 | 78 | 79 | # set the imposed boudary values 80 | T[-1,:] = Ttop 81 | T[0,:] = Tbottom 82 | T[:,0] = Tleft 83 | T[:,-1] = Tright 84 | 85 | 86 | for j in range(1,ny+1): 87 | for i in range(1, nx + 1): 88 | T[j, i] = theta[j + (i-1)*ny - 1] 89 | 90 | 91 | from mpl_toolkits.mplot3d import Axes3D 92 | from matplotlib import cm 93 | from matplotlib.ticker import LinearLocator, FormatStrFormatter 94 | 95 | fig = plt.figure() 96 | ax = fig.gca(projection='3d') 97 | surf = ax.plot_surface(X, Y, T, rstride=1, cstride=1, cmap=cm.coolwarm, 98 | linewidth=0, antialiased=False) 99 | ax.set_zlim(0, Ttop+10) 100 | ax.set_xlabel('x') 101 | ax.set_ylabel('y') 102 | ax.set_zlabel('T [$^o$C]') 103 | 104 | 105 | nx=4 106 | xticks=np.linspace(0.0,xmax,nx+1) 107 | ax.set_xticks(xticks) 108 | 109 | ny=8 110 | yticks=np.linspace(0.0,ymax,ny+1) 111 | ax.set_yticks(yticks) 112 | 113 | nTicks=5 114 | dT=int(Ttop/nTicks) 115 | #Tticklist=list(range(0,Ttop+1,dT)) 116 | #ax.set_zticks(Tticklist) 117 | 118 | #fig.colorbar(surf, shrink=0.5, aspect=5) 119 | plt.show() 120 | -------------------------------------------------------------------------------- /tests/baselines/cavity-2d-64.dat: -------------------------------------------------------------------------------- 1 | 0.000000000000000000e+00 1.587301587301587213e-02 3.174603174603174427e-02 4.761904761904761640e-02 6.349206349206348854e-02 7.936507936507936067e-02 9.523809523809523281e-02 1.111111111111111049e-01 1.269841269841269771e-01 1.428571428571428492e-01 1.587301587301587213e-01 1.746031746031745935e-01 1.904761904761904656e-01 2.063492063492063378e-01 2.222222222222222099e-01 2.380952380952380820e-01 2.539682539682539542e-01 2.698412698412698818e-01 2.857142857142856984e-01 3.015873015873016261e-01 3.174603174603174427e-01 3.333333333333333703e-01 3.492063492063491870e-01 3.650793650793651146e-01 3.809523809523809312e-01 3.968253968253968589e-01 4.126984126984126755e-01 4.285714285714286031e-01 4.444444444444444198e-01 4.603174603174603474e-01 4.761904761904761640e-01 4.920634920634920917e-01 5.079365079365079083e-01 5.238095238095238360e-01 5.396825396825396526e-01 5.555555555555555802e-01 5.714285714285713969e-01 5.873015873015873245e-01 6.031746031746031411e-01 6.190476190476190688e-01 6.349206349206348854e-01 6.507936507936508130e-01 6.666666666666666297e-01 6.825396825396825573e-01 6.984126984126983739e-01 7.142857142857143016e-01 7.301587301587301182e-01 7.460317460317460458e-01 7.619047619047618625e-01 7.777777777777777901e-01 7.936507936507936067e-01 8.095238095238095344e-01 8.253968253968253510e-01 8.412698412698412787e-01 8.571428571428570953e-01 8.730158730158730229e-01 8.888888888888888395e-01 9.047619047619047672e-01 9.206349206349205838e-01 9.365079365079365115e-01 9.523809523809523281e-01 9.682539682539682557e-01 9.841269841269840724e-01 1.000000000000000000e+00 2 | 0.000000000000000000e+00 -7.085861071499689572e-03 -1.353919219218662276e-02 -1.943417231810885479e-02 -2.485617645848491389e-02 -2.986755293102014847e-02 -3.454129113690834058e-02 -3.893075122093669904e-02 -4.309803096306220188e-02 -4.709106363644497556e-02 -5.096278485186753887e-02 -5.475706703945033144e-02 -5.851920006315895068e-02 -6.228899251346585453e-02 -6.610491753791609970e-02 -7.000180325953894722e-02 -7.401115138606023658e-02 -7.816111266346120745e-02 -8.247490656169866041e-02 -8.697147478872466198e-02 -9.166321093003536313e-02 -9.655639655113043562e-02 -1.016488828035866099e-01 -1.069299794604466752e-01 -1.123784081247639899e-01 -1.179617128020566813e-01 -1.236347023381442756e-01 -1.293387097164973853e-01 -1.350007735738834036e-01 -1.405332132607425843e-01 -1.458338479215771366e-01 -1.507863662229191604e-01 -1.552618202557048133e-01 -1.591201226528175250e-01 -1.622127788963178552e-01 -1.643855254158058665e-01 -1.654817449022741860e-01 -1.653458113619503123e-01 -1.638259510128272645e-01 -1.607774073184313479e-01 -1.560628770873296045e-01 -1.495543134120558004e-01 -1.411287862684764971e-01 -1.306677125335319600e-01 -1.180463865516199196e-01 -1.031296377332352188e-01 -8.575466525352801184e-02 -6.572247425888169681e-02 -4.277643176966333671e-02 -1.658943362131336599e-02 1.325456225331129653e-02 4.727610519242621268e-02 8.610072330310000743e-02 1.304717517608827149e-01 1.812070776735681676e-01 2.391968110957386207e-01 3.052810552465918259e-01 3.802145600240808276e-01 4.644368693876609888e-01 5.579984071476833396e-01 6.602480005824334919e-01 7.697672915899296253e-01 8.841345452375631853e-01 1.000000000000000000e+00 3 | -------------------------------------------------------------------------------- /INSTALL.md: -------------------------------------------------------------------------------- 1 | # Installing Pyranda 2 | 3 | ## Prerequisites 4 | Before installing pyranda you'll need to install numpy and mpi4py. Numpy's f2py utility 5 | is used to build the python-fortran interface and we try to validate that your choice of 6 | compiler will work with the installed mpi4py's version of mpi. 7 | 8 | ### installing `mpi4py` 9 | `mpi4py` should be installed with the `--no-cache-dir` option to avoid using an 10 | existing build with a cached compiler. 11 | 12 | ``` 13 | # if your mpi*s are in your path 14 | pip install mpi4py --no-cache-dir 15 | # otherwise you can specify an environment variable 16 | env MPICC=/path/to/your/mpi pip install mpi4py --no-cache-dir 17 | ``` 18 | 19 | ### installing `numpy` 20 | `numpy` shouldn't have any special build steps, just install as normal: 21 | 22 | ``` 23 | pip install numpy 24 | ``` 25 | 26 | ## Installing with pip 27 | 28 | ### [optional] Using a virtualenv 29 | 30 | ``` 31 | ...> virtualenv [-p python] my_venv 32 | ...> source my_venv/bin/activate 33 | (my_venv) ...> 34 | ``` 35 | 36 | You can also verify that you're in your venv by checking your `$PATH`: 37 | 38 | ``` 39 | ...> echo $PATH 40 | /path/to/your/env/root/my_venv/bin:... 41 | ``` 42 | 43 | ### install pyranda 44 | 45 | ``` 46 | pip install . [--user] 47 | ``` 48 | 49 | ## Installing without pip 50 | 51 | ``` 52 | [python setup.py build [extra_build_args]] 53 | python setup.py install 54 | ``` 55 | 56 | 57 | ## Legacy Instructions - Manual Install 58 | This process should work on any system and will allow for an arbitrary compiler to be used for 59 | the fortran and for the mpi4py. 60 | 61 | ### Step 1: Ensure python and numpy 62 | #### Python- 63 | Though other versions of python may very well work, we recommend and support 64 | python 2.7, 3.5, and 3.6 for pyranda. 65 | #### numpy- 66 | As long as numpy is working with your version of python above, there will be no 67 | compability issues. This can be installed in a number of ways. http://www.numpy.org 68 | 69 | ### Step 2: Custom install of mpi4py 70 | This python package provides MPI bindings to python and may or may not exists on your system 71 | and python path. 72 | #### Install mpi4py (this should work on most systems with a mpi compiler installed) 73 | ``` 74 | wget https://bitbucket.org/mpi4py/mpi4py/downloads/mpi4py-3.0.0.tar.gz 75 | tar xvzf mpi4py-3.0.0.tar.gz 76 | cd mpi4py* 77 | python setup.py build --mpicc=/where/you/have/mpicc 78 | python setup.py install --prefix=install_location_mpi4py 79 | ``` 80 | 81 | ** Add install_location_mpi4py/*/site_packages to PYTHONPATH ** 82 | 83 | ### Step 3: Pyranda build/install 84 | A fortran compiler compatible with the mpicc used in mpi4py is used by default. 85 | 2003 and above standards enforced and MPI libraries is required. 86 | ### Install pyranda 87 | ``` 88 | git clone https://github.com/LLNL/pyranda.git 89 | cd pyranda 90 | python setup.py build 91 | python setup.py install --prefix=install_location_pyranda 92 | ``` 93 | 94 | ** Add install_location_pyranda/*/site_packages to PYTHONPATH ** 95 | 96 | ### Step 4: Run tests to check install 97 | Trying navigating to pyranda/examples and running 98 | ``` 99 | python advection.py 100 | ``` 101 | 102 | -------------------------------------------------------------------------------- /examples/advection.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import time 3 | import numpy 4 | import matplotlib.pyplot as plt 5 | 6 | from pyranda import pyrandaSim 7 | 8 | # Try to get args 9 | try: 10 | Npts = int(sys.argv[1]) 11 | except: 12 | Npts = 100 13 | 14 | try: 15 | test = bool(int(sys.argv[2])) 16 | except: 17 | test = False 18 | 19 | ## Define a mesh 20 | L = numpy.pi * 2.0 21 | Lp = L * (Npts-1.0) / Npts 22 | 23 | 24 | # Define the domain/mesh 25 | imesh = """ 26 | Lp = %s 27 | Npts = %d 28 | xdom = (0.0, Lp, Npts, periodic=True) 29 | """ % ( Lp, Npts) 30 | 31 | # Initialize a simulation object on a mesh 32 | ss = pyrandaSim('advection',imesh) 33 | 34 | # Define the equations of motion 35 | ss.EOM(" ddt(:phi:) = -:c: * ddx(:phi:) ") 36 | 37 | 38 | # Initialize variables 39 | ic = """ 40 | r = sqrt( (meshx-pi)**2 ) 41 | :phi: = 1.0 + 0.1 * exp( -(r/(pi/4.0))**2 ) 42 | :phi2: = 1.0*:phi: 43 | :c: = 1.0 44 | """ 45 | ss.setIC(ic) 46 | 47 | #ss.variables["u"].data += 1.0 48 | 49 | x = ss.mesh.coords[0].data 50 | xx = ss.PyMPI.zbar( x ) 51 | 52 | # Time step size 53 | v = 1.0 54 | dt_max = v / ss.mesh.nn[0] * L * .90 55 | tt = L/v * 1.0 56 | 57 | 58 | # Main time loop for physics 59 | dt = dt_max 60 | cnt = 1 61 | time = 0.0 62 | viz = True 63 | while tt > time: 64 | 65 | 66 | #raw_input('Pause...') 67 | 68 | time = ss.rk4(time,dt) 69 | dt = min(dt_max, (tt - time) ) 70 | 71 | if not test: 72 | ss.iprint("%s -- %s" % (cnt,time) ) 73 | 74 | # Plot animation of advection 75 | cnt += 1 76 | if viz: 77 | v = ss.PyMPI.zbar( ss.variables['phi'].data ) 78 | if (ss.PyMPI.master and (cnt%5 == 0)) and (not test): 79 | plt.figure(1) 80 | plt.clf() 81 | plt.plot(xx[:,0],v[:,0] ,'k.-') 82 | plt.pause(.001) 83 | 84 | 85 | phi = ss.variables['phi'].data 86 | phi2 = ss.variables['phi2'].data 87 | error = numpy.sum( (phi-phi2)**2 ) 88 | ss.iprint( error ) 89 | 90 | 91 | 92 | 93 | if test == 0: 94 | # Latex/PDF generation 95 | ss.setupLatex() 96 | ss.latex.tMap[":phi:"] = r'\phi' 97 | ss.latex.tMap[":phi2:"] = r'\phi_2' 98 | 99 | 100 | intro = ss.latex.addSection("Introduction") 101 | intro.body = """ 102 | This brief document shows the ability to integrate the simulation with formal 103 | documentation. The advection equations is solved and plotted below. 104 | """ 105 | 106 | 107 | equations = ss.latex.addSection("Equations of Motion") 108 | equations.body = """ 109 | Pyranda solves the following equations using a 10th order compact finite difference 110 | stencil and a 5 stage RK4 temporal integration scheme. 111 | """ 112 | equations.body += ss.latex.renderEqu() 113 | 114 | 115 | initial = ss.latex.addSection("Initial Conditions",1) 116 | initial.body = """ 117 | The problem is initialized given the following formulae: 118 | """ 119 | initial.body += ss.latex.renderEqu(kind="IC") 120 | 121 | 122 | results = ss.latex.addSection("Results") 123 | results.addFigure("Profiles",size=.45) 124 | results.body = "Here in the figure, we see the final profile of the advection" 125 | 126 | plt.figure() 127 | plt.plot( xx[:,0], ((phi-phi2)**2)[:,0,0] ) 128 | results.addFigure("Error",size=.45) 129 | 130 | 131 | ss.latex.makeDoc() 132 | ss.latex.showPDF() 133 | -------------------------------------------------------------------------------- /examples/cavity.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import time 3 | import numpy 4 | import matplotlib.pyplot as plt 5 | from pyranda import pyrandaSim, pyrandaBC, pyrandaTimestep, pyrandaPoisson 6 | 7 | 8 | # Try to get args for testing 9 | try: 10 | Npts = int(sys.argv[1]) 11 | except: 12 | Npts = 40 13 | 14 | try: 15 | test = bool(int(sys.argv[2])) 16 | except: 17 | test = False 18 | 19 | try: 20 | testName = (sys.argv[3]) 21 | except: 22 | testName = None 23 | 24 | try: 25 | solver = sys.argv[4] 26 | except: 27 | solver = "scipy" 28 | 29 | 30 | ## Define a mesh 31 | L = 1.0 32 | Re = 100.0 33 | 34 | 35 | mesh_options = {} 36 | mesh_options['coordsys'] = 0 37 | mesh_options['periodic'] = numpy.array([False, False, True]) 38 | mesh_options['x1'] = [ 0.0 , 0.0 , 0.0 ] 39 | mesh_options['xn'] = [ L , L , L ] 40 | mesh_options['nn'] = [ Npts, Npts , 1 ] 41 | 42 | 43 | # Initialize a simulation object on a mesh 44 | pysim = pyrandaSim('lidDrivenCavity',mesh_options) 45 | pysim.addPackage( pyrandaBC(pysim) ) 46 | pysim.addPackage( pyrandaTimestep(pysim) ) 47 | 48 | #pysim.linearSolver = solver 49 | pyPoisson = pyrandaPoisson(pysim,solver) 50 | pyPoisson.BC = {} 51 | pyPoisson.BC["x1"] = ["val",0] 52 | pyPoisson.BC["xn"] = ["val",0] 53 | pyPoisson.BC["y1"] = ["val",0] 54 | pyPoisson.BC["yn"] = ["val",0] 55 | pysim.addPackage(pyPoisson) 56 | 57 | eom =""" 58 | # Primary Equations of motion here 59 | :us: = :u: + :dt: * ( - :u: * ddx( :u: ) - :v: * ddy( :u: ) + lap(:u:)*:nu: ) 60 | :vs: = :v: + :dt: * ( - :u: * ddx( :v: ) - :v: * ddy( :v: ) + lap(:v:)*:nu: ) 61 | :ps: = invDelta( 1.0/:dt: * ( ddx(:us:) + ddy(:vs:) ) ) 62 | :u: = :us: - :dt: * ddx(:ps:) 63 | :v: = :vs: - :dt: * ddy(:ps:) 64 | :u: = fbar(:u:) 65 | :v: = fbar(:v:) 66 | # Boundary conditions 67 | bc.const(['u','v'],['x1','xn','y1'],0.0) 68 | bc.const(['u'],['yn'],1.0) 69 | bc.const(['v'],['yn'],0.0) 70 | :umag: = sqrt( :u:*:u: + :v:*:v: ) 71 | :dt: = dt.courant(:u:,:v:,0.0,0.0)*.9 72 | :dt: = numpy.minimum(:dt:,0.1 * dt.diff(:nu:,1.0)) 73 | """ 74 | 75 | pysim.EOM(eom) 76 | 77 | ics = """ 78 | :u: *= 0.0 79 | :v: *= 0.0 80 | :nu: += 1.0/REY 81 | :dt: = .0001 82 | :bcvar: *= 0.0 83 | """.replace("REY",str(Re)) 84 | pysim.setIC(ics) 85 | 86 | 87 | dt = .001 88 | time = 0.0 89 | tt = 5.0 90 | cyc = 1 91 | 92 | if test: 93 | tt = 2.0 94 | 95 | while tt > time: 96 | 97 | # Simple euler - No RK4 (steady state solution) 98 | pysim.updateVars() 99 | 100 | if ( cyc%50 == 0 and not test): 101 | pysim.plot.figure(1) 102 | pysim.plot.clf() 103 | pysim.plot.contourf('umag',32) 104 | 105 | X = pysim.mesh.coords[0].data[::2, ::2 , 0] 106 | Y = pysim.mesh.coords[1].data[::2, ::2, 0] 107 | u = pysim.var('u').data[::2, ::2, 0] 108 | v = pysim.var('v').data[::2, ::2, 0] 109 | plt.quiver(X, Y, u, v ) 110 | plt.pause(.01) 111 | 112 | 113 | dt = pysim.var("dt").data 114 | time += dt 115 | cyc += 1 116 | 117 | print("Cycle: %s --- Time: %f --- dt: %f " % (cyc,time,dt) ) 118 | 119 | # Plot final solution 120 | ioff = int(Npts/2) 121 | uF = pysim.var('u')[ioff,:,0] 122 | yF = pysim.mesh.coords[1][ioff,:,0] 123 | 124 | if not test: 125 | pysim.plot.figure(2) 126 | pysim.plot.plot('u',slice2d="i=%s;k=0" % ioff ) 127 | plt.plot(yF,uF,'ko') 128 | 129 | # Save file for regression testing 130 | if test: 131 | fname = testName + '.dat' 132 | numpy.savetxt( fname , (yF,uF) ) 133 | print(fname) 134 | -------------------------------------------------------------------------------- /pyranda/parcop/test_pent.f90: -------------------------------------------------------------------------------- 1 | PROGRAM test_pent 2 | 3 | USE iso_c_binding 4 | USE LES_compact, ONLY : compact_type 5 | USE LES_patch, ONLY : patch_type 6 | USE LES_comm, ONLY : comm_type, LES_comm_world 7 | USE LES_mesh, ONLY : mesh_type 8 | USE LES_objects 9 | USE parcop, ONLY : setup,ddx,point_to_objects,setup_mesh 10 | IMPLICIT NONE 11 | INCLUDE "mpif.h" 12 | 13 | 14 | INTEGER(c_int) :: nx,ny,nz,px,py,pz 15 | REAL(c_double) :: x1,xn,y1,yn,z1,zn 16 | CHARACTER(KIND=c_char,LEN=4) :: bx1,bxn,by1,byn,bz1,bzn 17 | REAL(c_double) :: simtime 18 | INTEGER(c_int) :: world_id,world_np,mpierr 19 | REAL(c_double), DIMENSION(:,:,:), ALLOCATABLE :: rho,drho 20 | INTEGER :: i 21 | INTEGER :: t1,t2,clock_rate,clock_max 22 | CHARACTER(LEN=32) :: arg 23 | INTEGER :: nargs,ii,iterations 24 | INTEGER :: rank,ierror 25 | 26 | ! MPI 27 | CALL MPI_INIT(mpierr) 28 | CALL MPI_COMM_RANK(MPI_COMM_WORLD,rank,ierror) 29 | 30 | nargs = command_argument_count() 31 | 32 | ! Print usage: 33 | IF ( rank == 0 .AND. nargs == 0) THEN 34 | PRINT*,"USAGE:" 35 | PRINT*,"Serial: ./test_pent [interations=100,nx=32,px=1,ny=1,py=1,nz=1,pz=1]" 36 | PRINT*,"Parallel: mpirun -n [num procs] test_pent [interations=100,nx=32,px=1,ny=1,py=1,nz=1,pz=1]" 37 | PRINT*,"Examples:" 38 | PRINT*,"./test_pent 100 32 1 32 1 32 1" 39 | PRINT*,"mpirun -n 8 ./test_pent 100 64 2 64 2 64 2" 40 | ENDIF 41 | 42 | ! Default domain, grid and processors map 43 | x1 = 0.0 44 | xn = 1.0 45 | y1 = 0.0 46 | yn = 1.0 47 | z1 = 0.0 48 | zn = 1.0 49 | 50 | ! Grid 51 | nx = 32 52 | ny = 1 53 | nz = 1 54 | 55 | ! Proc map 56 | px = 1 57 | py = 1 58 | pz = 1 59 | 60 | ! Iterations 61 | iterations = 100 62 | 63 | ! Parse the simple input 64 | ii=1 65 | IF (nargs >= ii) CALL GETARG(ii,arg) 66 | IF (nargs >= ii) READ(arg,'(I10)') iterations 67 | 68 | ii=ii+1 69 | IF (nargs >= ii) CALL GETARG(ii,arg) 70 | IF (nargs >= ii) READ(arg,'(I10)') nx 71 | 72 | ii=ii+1 73 | IF (nargs >= ii) CALL GETARG(ii,arg) 74 | IF (nargs >= ii) READ(arg,'(I10)') px 75 | 76 | ii=ii+1 77 | IF (nargs >= ii) CALL GETARG(ii,arg) 78 | IF (nargs >= ii) READ(arg,'(I10)') ny 79 | 80 | ii=ii+1 81 | IF (nargs >= ii) CALL GETARG(ii,arg) 82 | IF (nargs >= ii) READ(arg,'(I10)') py 83 | 84 | ii=ii+1 85 | IF (nargs >= ii) CALL GETARG(ii,arg) 86 | IF (nargs >= ii) READ(arg,'(I10)') nz 87 | 88 | ii=ii+1 89 | IF (nargs >= ii) CALL GETARG(ii,arg) 90 | IF (nargs >= ii) READ(arg,'(I10)') pz 91 | 92 | 93 | 94 | bx1 = "NONE" 95 | bxn = "NONE" 96 | by1 = "NONE" 97 | byn = "NONE" 98 | bz1 = "NONE" 99 | bzn = "NONE" 100 | 101 | simtime = 0.0D0 102 | 103 | ! Setup matrices/solvers 104 | CALL setup(0,0,MPI_COMM_WORLD,nx,ny,nz,px,py,pz,0,x1,xn,y1,yn,z1,zn,bx1,bxn,by1,byn,bz1,bzn) 105 | 106 | 107 | CALL setup_mesh(0,0) 108 | CALL point_to_objects(0,0) 109 | 110 | ! Allocated some arrays 111 | ALLOCATE( rho(nx/px,ny/py,nz/pz) ) 112 | ALLOCATE(drho(nx/px,ny/py,nz/pz) ) 113 | 114 | ! rho = x 115 | rho = mesh_ptr%xgrid 116 | 117 | ! Time the derivatives 118 | CALL SYSTEM_CLOCK( t1, clock_rate, clock_max) 119 | DO i=1,iterations 120 | CALL ddx(rho,drho,nx/px,ny/py,nz/pz) 121 | END DO 122 | CALL SYSTEM_CLOCK( t2, clock_rate, clock_max) 123 | 124 | 125 | IF ( rank == 0 ) THEN 126 | print*,'Ellapsed time = ', real(t2-t1) / real(clock_rate) 127 | END IF 128 | 129 | CALL remove_objects(0,0) 130 | CALL MPI_FINALIZE(mpierr) 131 | 132 | END PROGRAM test_pent 133 | -------------------------------------------------------------------------------- /tests/run_tests.py: -------------------------------------------------------------------------------- 1 | # Run a bunch of test and check answers 2 | from __future__ import print_function 3 | import os,sys 4 | import numpy as npy 5 | import subprocess 6 | from testObj import * 7 | import time 8 | 9 | test_dir = os.path.dirname(os.path.abspath(__file__)) 10 | bin_dir = os.path.join( test_dir, '../bin') 11 | root_dir = os.path.join( test_dir, '..') 12 | pyranda_exe = sys.executable 13 | 14 | tests = [] # List of test objects 15 | dbase = {} # Dictionary of baselines 16 | relE = {} # Dictionary of relative errors for baselines 17 | 18 | verbose = False 19 | try: 20 | verbose = sys.argv[1] 21 | print('Running in verbose mode') 22 | except: 23 | pass 24 | 25 | # Since Python 3 doesn't have execfile 26 | def execfile(file_name): 27 | exec(compile(open(file_name, "rb").read(), file_name, 'exec')) 28 | 29 | # Add tests here 30 | execfile('cases/testUnit.py') 31 | execfile('cases/test1DAdvection.py') 32 | execfile('cases/testIntegration.py') 33 | execfile('cases/testMM_simple.py') 34 | execfile('cases/test2deuler.py') 35 | execfile('cases/testCylinder.py') 36 | execfile('cases/testHeat1D.py') 37 | execfile('cases/testTaylorGreen.py') 38 | execfile('cases/testShuOsher.py') 39 | execfile('cases/testElliptic.py') 40 | execfile('cases/testRT.py') 41 | 42 | 43 | summary = '' 44 | passed = 0 45 | failed = 0 46 | new_baselines = '' 47 | 48 | 49 | # Run tests 50 | start = time.time() 51 | for test in tests: 52 | 53 | script = os.path.join(root_dir,test.script) 54 | 55 | exe = pyranda_exe 56 | if test.parallel: 57 | exe = pyranda_mpi + ' -n %s %s' % (test.np,exe) 58 | 59 | # Args 60 | sargs = '' 61 | for arg in test.args: 62 | sargs += '%s ' % arg 63 | 64 | 65 | cmd = '%s %s %s' % (exe,script,sargs) 66 | 67 | out = sexe(cmd,ret_output=True,echo=False) 68 | pout = out[1].decode('utf-8').split('\n')[-2] 69 | curve = False 70 | if '.dat' in pout: 71 | curve = True 72 | 73 | # Verbose output 74 | if verbose: 75 | for po in out[1].decode('utf-8').split('\n'): 76 | print(po) 77 | 78 | # Diff against baseline 79 | try: 80 | baseline = dbase[test.name] # Baseline value/file 81 | try: 82 | rdiff = relE[test.name] # Rel. error for this baseline 83 | except: 84 | rdiff = 1.0e-4 85 | 86 | 87 | if curve: 88 | # Check curve 89 | print(baseline, pout) 90 | diff = checkProfile( baseline, pout) 91 | else: 92 | # Check if scalar compare 93 | diff = checkScalar( float(baseline) , pout) 94 | 95 | if diff < rdiff: 96 | testPass = True 97 | print('Pass: (Rel. Error = %s )' % diff) 98 | fout = '%s -- %s' % (test.name,pout) 99 | print(fout) 100 | passed += 1 101 | if curve: 102 | sexe("rm %s" % pout,ret_output=False,echo=False) 103 | else: 104 | testPass = False 105 | print('Fail: (Rel. Error = %s )' % diff) 106 | fout = '%s -- %s' % (test.name,pout) 107 | print(fout) 108 | new_baselines += fout + '\n' 109 | failed += 1 110 | 111 | if curve: 112 | plotError( baseline, pout ) 113 | 114 | 115 | 116 | except: 117 | testPass = False 118 | print('Fail: (No baseline data found )') 119 | fout = '%s -- %s' % (test.name,pout) 120 | print(fout) 121 | new_baselines += fout + '\n' 122 | failed += 1 123 | end = time.time() 124 | print("\n\n\n=====Testing Summary======") 125 | print("Passed: %s" % passed) 126 | print("Failed: %s" % failed) 127 | print("Time elapsed: %s" % (end-start) ) 128 | 129 | if failed > 0: 130 | print('\n\n\n===== New baselines =====') 131 | print(new_baselines) 132 | 133 | plt.show() 134 | 135 | sys.exit(failed) 136 | -------------------------------------------------------------------------------- /pyranda/pyrandaEllipticalFFT.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018, Lawrence Livemore National Security, LLC. 2 | # Produced at the Lawrence Livermore National Laboratory. 3 | # 4 | # LLNL-CODE-749864 5 | # This file is part of pyranda 6 | # For details about use and distribution, please read: pyranda/LICENSE 7 | # 8 | # Written by: Britton J. Olson, olson45@llnl.gov, modified to use FFTs by Chris Scullard 9 | ################################################################################ 10 | import numpy 11 | import scipy.sparse 12 | from scipy.sparse.linalg import factorized,bicgstab,cg 13 | from .pyrandaPackage import pyrandaPackage 14 | 15 | 16 | class pyrandaPoissonFFT(pyrandaPackage): 17 | 18 | def __init__(self,pysim): 19 | """ 20 | Solve an elliptical Poisson equation 21 | \Delta \phi = f(x) 22 | Second order FD on structured mesh assumed 23 | """ 24 | PackageName = "Poisson" 25 | 26 | #self.BCtype = BCtype 27 | self.pysim = pysim 28 | pyrandaPackage.__init__(self,PackageName,pysim) 29 | 30 | 31 | nx = self.nx = pysim.mesh.options['nn'][0] 32 | ny = self.ny = pysim.mesh.options['nn'][1] 33 | nz = self.nz = pysim.mesh.options['nn'][2] 34 | 35 | # Setup 1/k^2 array 36 | pi=numpy.pi 37 | self.ksqinv = numpy.ones((self.nx,self.ny,int(self.nz/2+1))) 38 | for k in range(0,int(self.nz/2)): 39 | for j in range(0,self.ny): 40 | for i in range(0, self.nx): 41 | kx=2.*pi*i 42 | if i>(self.nx/2): 43 | kx=(i-self.nx)*2.*pi 44 | ky=2.*pi*j 45 | if j>(self.ny/2): 46 | ky=(j-self.ny)*2.*pi 47 | kz=2.*pi*k 48 | if k>(self.nz/2): 49 | kz=(k-self.nz)*2.*pi 50 | ksq=kx*kx+ky*ky+kz*kz 51 | if ksq>0: 52 | #u_hat[i,j,k]=-u_hat[i,j,k]/ksq 53 | self.ksqinv[i,j,k] = -1.0 / ksq 54 | 55 | 56 | def get_sMap(self): 57 | sMap = {} 58 | sMap['poisson.solve('] = "self.packages['Poisson'].solve(" 59 | self.sMap = sMap 60 | 61 | def solve(self,rhs): 62 | 63 | pi=numpy.pi 64 | #u = numpy.zeros((self.nx,self.ny,self.nz)) #RHS 65 | #uc = numpy.zeros((self.nx,self.ny,self.nz)) #RHS 66 | #u_hat = numpy.zeros((self.nx,self.ny,self.nz)) #RHS 67 | #for k in range(0,self.nz): 68 | # for j in range(0,self.ny): 69 | # for i in range(0, self.nx): 70 | # u[i,j,k] = rhs[i,j,k] 71 | 72 | #u_hat = numpy.fft.rfftn(u) # forward FFT 73 | #import pdb 74 | #pdb.set_trace() 75 | 76 | u_hat = numpy.fft.rfftn(rhs) # forward FFT 77 | 78 | #Divide by -k^2 79 | #for k in range(0,self.nz/2): 80 | # for j in range(0,self.ny): 81 | # for i in range(0, self.nx): 82 | # kx=2.*pi*i 83 | # if i>(self.nx/2): 84 | # kx=(i-self.nx)*2.*pi 85 | # ky=2.*pi*j 86 | # if j>(self.ny/2): 87 | # ky=(j-self.ny)*2.*pi 88 | # kz=2.*pi*k 89 | # if k>(self.nz/2): 90 | # kz=(k-self.nz)*2.*pi 91 | # ksq=kx*kx+ky*ky+kz*kz 92 | # if ksq>0: 93 | # u_hat[i,j,k]=-u_hat[i,j,k]/ksq 94 | 95 | u_hat = self.ksqinv * u_hat 96 | mysol = numpy.fft.irfftn(u_hat,s=(self.nx,self.ny,self.nz)) # inverse FFT 97 | 98 | #sol = self.solver( b ) 99 | #sol = bicgstab(self.A, b )[0] 100 | #sol = cg(self.A, b )[0] 101 | 102 | #for j in range(0,self.ny): 103 | # for i in range(0, self.nx): 104 | # mysol[i,j,0] = sol[j + i*self.ny] 105 | 106 | #mysol -= mysol.mean() 107 | return mysol 108 | 109 | 110 | -------------------------------------------------------------------------------- /examples/SOD_leos.py: -------------------------------------------------------------------------------- 1 | import re 2 | import sys 3 | import time 4 | import numpy 5 | import matplotlib.pyplot as plt 6 | from matplotlib import cm 7 | 8 | from pyranda import pyrandaSim, pyrandaBC,pyrandaLEOS,pyrandaTimestep 9 | #from pyranda.pyranda import pyrandaRestart 10 | 11 | 12 | ## Define a mesh 13 | L = numpy.pi * 2.0 14 | Npts = 200 15 | Lp = L * (Npts-1.0) / Npts 16 | 17 | imesh = """ 18 | xdom = (0.0, Lp, Npts) 19 | """.replace('Lp',str(Lp)).replace('Npts',str(Npts)) 20 | 21 | # Initialize a simulation object on a mesh 22 | ss = pyrandaSim('sod',imesh) 23 | ss.addPackage( pyrandaBC(ss) ) 24 | ss.addPackage( pyrandaTimestep(ss) ) 25 | 26 | 27 | # LEOS package and materials 28 | eos = pyrandaLEOS(ss) 29 | matID = 70 # 70 - Nitrogen 30 | eos.addMaterial(matID) 31 | ss.addPackage( eos ) 32 | 33 | rho0 = eos.materials[matID]['rho0'] 34 | T0 = 300.0 35 | 36 | ## Look up pressure at these rho/T 37 | P0 = eos.materials[matID]['Pt'].eval( rho0 , T0 , N=1)[0] 38 | E0 = eos.materials[matID]['Et'].eval( rho0 , T0 , N=1)[0] 39 | 40 | parms = {} 41 | parms['rho0'] = rho0 42 | parms['E0'] = E0 43 | parms['P0'] = P0 44 | parms['T0'] = T0 45 | parms['matID'] = matID 46 | 47 | # Define the equations of motion 48 | eom =""" 49 | # Primary Equations of motion here 50 | ddt(:rho:) = -ddx(:rho:*:u:) 51 | ddt(:rhou:) = -ddx(:rhou:*:u: + :p: - :tau:) 52 | ddt(:Et:) = -ddx( (:Et: + :p: - :tau:)*:u: - :tx:*:kappa:) 53 | # Conservative filter of the EoM 54 | :rho: = fbar( :rho: ) 55 | :rhou: = fbar( :rhou: ) 56 | :Et: = fbar( :Et: ) 57 | # Update the primatives and enforce the EOS 58 | :u: = :rhou: / :rho: 59 | :ke: = .5*:rho:*:u:*:u: 60 | :ie: = (:Et: - :ke:)/:rho: 61 | #:p: = ( :Et: - .5*:rho:*(:u:*:u:) ) * ( :gamma: - 1.0 ) 62 | #:T: = LEOS.temperature(matID,:rho:,:ie:) 63 | :T: = LEOS.inv.energy(matID,:rho:,:ie:) 64 | :p: = LEOS.pressure(matID,:rho:,:T:) 65 | # Artificial bulk viscosity (old school way) 66 | :div: = ddx(:u:) 67 | :beta: = gbar( ring(:div:) * :rho:) * 7.0e-1 68 | :tau: = :beta:*:div: 69 | # Artificial thermal conductivity 70 | [:tx:,:ty:,:tz:] = grad(:ie:) 71 | :kappa: = 1.0e-3 * :rho: * gbar( ring(:ie:) / (abs(:ie:)+1.0e-6 )) / :dt: 72 | # Apply constant BCs 73 | bc.extrap(['rho','Et'],['x1']) 74 | bc.const(['u'],['x1','xn'],0.0) 75 | # Time step 76 | :cs: = LEOS.soundSpeed( matID, :rho:, :T: ) 77 | :dt: = dt.courant(:u:,:v:,:w:,:cs:)*0.1 78 | :dt: = numpy.minimum(:dt:,0.01 * dt.diff(:beta: ,:rho:)) 79 | #:dt: = numpy.minimum(:dt:,0.1 * dt.diff(:kappa:,:rho:)) 80 | """ 81 | 82 | # Add the EOM to the solver 83 | ss.EOM(eom,eomDict=parms) 84 | 85 | 86 | # Initial conditions SOD shock tube in 1d 87 | ic = """ 88 | :gamma: = 1.4 89 | :p: = gbar( gbar( where( meshx < pi, P0 *10. , P0 ) )) 90 | :rho: = gbar( gbar( where( meshx < pi, rho0*2.0 , rho0 ) )) 91 | 92 | :T: = LEOS.inv.pressure(matID,:rho:,:p:) 93 | :ie: = LEOS.energy(matID,:rho:,:T:) 94 | :Et: = :rho: * :ie: 95 | """ 96 | 97 | # Set the initial conditions 98 | ss.var('dt').data = 1.0e-10 99 | ss.setIC(ic,icDict=parms) 100 | 101 | 102 | 103 | # Write a time loop 104 | time = 0.0 105 | 106 | # Approx a max dt and stopping time 107 | dt_max = ss.var('dt').data * 1.0 108 | 109 | tt = 5.0e-6 #1000 * dt_max 110 | 111 | # Start time loop 112 | dt = dt_max / 10.0 113 | cnt = 1 114 | viz_freq = 100 115 | pvar = 'rho' 116 | viz = True 117 | 118 | cplots = ['rho','p','u','T','ie'] 119 | 120 | def doPlots(): 121 | ifig = 1 # Plot figure counter 122 | for cc in cplots: # Loops over plots 123 | ss.plot.figure(ifig) # - make a new figure 124 | ss.plot.clf() # - clear the figure 125 | ss.plot.plot(cc,'k-o') # - plot a filled contour 126 | ifig += 1 127 | 128 | 129 | doPlots() 130 | 131 | while tt > time: 132 | 133 | # Update the EOM and get next dt 134 | time = ss.rk4(time,dt) 135 | dt = min(dt_max, (tt - time) ) 136 | 137 | # Print some output 138 | ss.iprint("%s -- %s" % (cnt,time) ) 139 | cnt += 1 140 | if viz: 141 | 142 | if (cnt%viz_freq == 0): 143 | doPlots() 144 | 145 | 146 | doPlots() 147 | ss.writeGrid() 148 | ss.write() 149 | 150 | 151 | -------------------------------------------------------------------------------- /examples/eulerRZ.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function 2 | import re 3 | import sys 4 | import time 5 | import numpy 6 | import matplotlib.pyplot as plt 7 | from matplotlib import cm 8 | 9 | from pyranda import pyrandaSim, pyrandaBC 10 | from pyranda.pyrandaMesh import defaultMeshOptions 11 | 12 | 13 | # Try to get args for testing 14 | try: 15 | Npts = int(sys.argv[1]) 16 | except: 17 | Npts = 128 18 | 19 | try: 20 | test = bool(int(sys.argv[2])) 21 | except: 22 | test = False 23 | 24 | try: 25 | testName = (sys.argv[3]) 26 | except: 27 | testName = None 28 | 29 | 30 | ## Define a mesh 31 | L = numpy.pi * 2.0 32 | dx2 = L / (Npts-1) / 2.0 33 | gamma = 1.4 34 | problem = 'sod2dRZ' 35 | mesh_options = defaultMeshOptions() 36 | mesh_options['coordsys'] = 1 37 | mesh_options['periodic'] = numpy.array([False, False, True]) 38 | #mesh_options['dim'] = 2 39 | mesh_options['x1'] = [ dx2 , -0.1 , 0.0 ] 40 | mesh_options['xn'] = [ L , 0.1 , L ] 41 | mesh_options['nn'] = [ Npts, 1 , Npts ] 42 | mesh_options['symmetric'][0][0] = True 43 | 44 | # Initialize a simulation object on a mesh 45 | ss = pyrandaSim('advection',mesh_options) 46 | ss.addPackage( pyrandaBC(ss) ) 47 | 48 | # Define the equations of motion 49 | eom =""" 50 | # Primary Equations of motion here 51 | ddt(:rho:) = -:mass: 52 | ddt(:rhou:) = -:xmom: 53 | ddt(:rhow:) = -:zmom: 54 | ddt(:Et:) = -div( (:Et: + :p: - :tau:)*:u:,:v:, (:Et: + :p: - :tau:)*:w: ) 55 | # Conservative filter of the EoM 56 | :rho: = fbar( :rho: ) 57 | :rhou: = fbar( :rhou: ) 58 | :rhow: = fbar( :rhow: ) 59 | :Et: = fbar( :Et: ) 60 | # Update the primatives and enforce the EOS 61 | :u: = :rhou: / :rho: 62 | :w: = :rhow: / :rho: 63 | :p: = ( :Et: - .5*:rho:*(:u:*:u: + :w:*:w:) ) * ( :gamma: - 1.0 ) 64 | # Artificial bulk viscosity (old school way) 65 | :div: = div(:u:,:v:,:w:) 66 | :beta: = gbar(abs(ring(:div:))) * :rho: * 7.0e-2 67 | :tau: = :beta:*:div: 68 | :v: = :v: * 0.0 69 | # Compute divT of momentum 70 | :mass: = div(:rho:*:u: , :v:, :rho:*:w:) 71 | [:fxx:,:fxy:,:fxz:] = [:rhou:*:u: + :p: - :tau:, :v:, :rhou:*:w:] 72 | [:fyx:,:fyy:,:fyz:] = [ :v: , :p:-:tau: , :v: ] 73 | [:fzx:,:fzy:,:fzz:] = [:rhow:*:u:, :v:, :rhow:*:w: + :p: - :tau:] 74 | [:xmom:,:ymom:,:zmom:] = divT(:fxx:,:fxy:,:fxz:,:fyx:,:fyy:,:fyz:,:fzx:,:fzy:,:fzz:) 75 | """ 76 | 77 | #eom += """# Apply constant BCs 78 | #bc.extrap(['rho','Et'],['x1','xn','z1','zn'],order=1) 79 | #bc.const(['u','w'],['x1','xn','z1','zn'],0.0) 80 | #""" 81 | 82 | print(eom) 83 | 84 | # Add the EOM to the solver 85 | ss.EOM(eom) 86 | 87 | 88 | # Initialize variables 89 | ic = "rad = sqrt( (meshx-pi)**2 + (meshz-pi)**2 ) " 90 | 91 | 92 | # SOD shock tube in 1d and 2d 93 | ic += """ 94 | :gamma: = 1.4 95 | wgt = .5*(1.0-tanh( (rad-pi/2.0)/.1) ) # [0,1] 96 | :Et: = 1.0/(:gamma:-1.0) * (wgt*.9 + .1) 97 | #:Et: = gbar( where( rad < pi/2.0, 1.0/(:gamma:-1.0) , .1 /(:gamma:-1.0) ) ) 98 | #:rho: = gbar( where( rad < pi/2.0, 1.0 , .125 ) ) 99 | :rho: = 1.0*wgt + (1.0-wgt)*.125 100 | """ 101 | 102 | # Set the initial conditions 103 | ss.setIC(ic) 104 | 105 | # Write a time loop 106 | time = 0.0 107 | viz = True 108 | 109 | # Approx a max dt and stopping time 110 | v = 1.0 111 | dt_max = v / ss.mesh.nn[0] * 0.75 112 | tt = 2.0 113 | 114 | if test: 115 | tt = 0.5 116 | 117 | # Start time loop 118 | dt = dt_max 119 | cnt = 1 120 | viz_freq = 10 121 | 122 | 123 | 124 | pvar = 'rho' 125 | 126 | while tt > time: 127 | 128 | # Update the EOM and get next dt 129 | time = ss.rk4(time,dt) 130 | dt = min(dt_max, (tt - time) ) 131 | 132 | # Print some output 133 | ss.iprint("%s -- %s" % (cnt,time) ) 134 | cnt += 1 135 | if viz and (not test): 136 | if (cnt%viz_freq == 0) and True: 137 | ss.plot.figure(1) 138 | ss.plot.clf() 139 | ss.plot.plot(pvar,slice2d="j=0;k=50",style='k.-') 140 | ss.plot.figure(2) 141 | ss.plot.clf() 142 | ss.plot.contourf(pvar,64) 143 | 144 | 145 | 146 | if test: 147 | half = int(Npts/2.0) 148 | x = ss.mesh.coords[0][:,0,0] 149 | p = ss.var('p')[half,0,:] 150 | fname = testName + '.dat' 151 | numpy.savetxt( fname , (x,p) ) 152 | print(fname) 153 | 154 | -------------------------------------------------------------------------------- /pyranda/pyrandaVar.py: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | # Copyright (c) 2018, Lawrence Livemore National Security, LLC. 3 | # Produced at the Lawrence Livermore National Laboratory. 4 | # 5 | # LLNL-CODE-749864 6 | # This file is part of pyranda 7 | # For details about use and distribution, please read: pyranda/LICENSE 8 | # 9 | # Written by: Britton J. Olson, olson45@llnl.gov 10 | ################################################################################ 11 | import numpy 12 | 13 | class pyrandaVar: 14 | 15 | def __init__(self,name,kind,rank): 16 | 17 | self.name = name 18 | self.kind = kind 19 | self.rank = rank 20 | 21 | self.rhs = None # RHS for algebraic closure 22 | self.dt = None # dt for temporal integration 23 | 24 | self.data = None # Need to allocate 25 | self.allocated = False 26 | self.PyMPI = None 27 | 28 | def __allocate__(self,pympi): # Make this private 29 | 30 | 31 | if self.allocated: 32 | return 33 | 34 | self.PyMPI = pympi 35 | 36 | # Inherit the mesh size 37 | if self.rank == 'scalar': 38 | self.data = pympi.emptyScalar() 39 | elif self.rank == 'vector': 40 | self.data = pympi.emptyVector() 41 | else: 42 | raise ValueError('Error: rank: %s not recognized' % self.rank) 43 | 44 | self.allocated = True 45 | 46 | 47 | def sum(self,axis=None,idata=None): 48 | 49 | if ( type(idata) != type(self.data) ): 50 | idata = self.data 51 | 52 | # Vector variables not fully supported with axis 53 | if self.rank == 'vector': 54 | return [ self.PyMPI.sum3D( idata[:,:,:,0] ) , 55 | self.PyMPI.sum3D( idata[:,:,:,1] ) , 56 | self.PyMPI.sum3D( idata[:,:,:,2] ) ] 57 | 58 | # For no axis, return global sum 59 | if (axis==None): 60 | return self.PyMPI.sum3D( idata ) 61 | 62 | # Sum along 2 directions 63 | if ( type(axis) == type( () ) or type(axis) == type( [] ) ): 64 | if ( len(axis) == 2 ): 65 | if ( (0 in axis) and (1 in axis) ): 66 | return self.PyMPI.xysum( idata ) 67 | elif ( (0 in axis) and (2 in axis) ): 68 | return self.PyMPI.xzsum( idata ) 69 | elif ( (1 in axis) and (2 in axis) ): 70 | return self.PyMPI.yzsum( idata ) 71 | else: 72 | self.PyMPI.iprint("Error: length of axis argument cant be larger than 2") 73 | return None 74 | # Sum along 1 directions 75 | elif ( type(axis) == type(0) ): 76 | if ( axis==0 ): 77 | return self.PyMPI.xsum( idata ) 78 | if ( axis==1 ): 79 | return self.PyMPI.ysum( idata ) 80 | if ( axis==2 ): 81 | return self.PyMPI.zsum( idata ) 82 | else: 83 | self.PyMPI.iprint("Error: unknown type given as axis") 84 | return None 85 | 86 | 87 | def mean(self,axis=None,idata=None): 88 | 89 | npts = float(self.PyMPI.nx * self.PyMPI.ny * self.PyMPI.nz ) 90 | rdata = self.sum(axis=axis,idata=idata) 91 | return rdata * rdata.size / npts 92 | 93 | def var(self,axis=None): 94 | 95 | bar = self.mean(axis=axis) 96 | bar2 = self.mean(axis=axis, idata = self.data**2) 97 | 98 | return bar2 - bar*bar 99 | 100 | 101 | 102 | 103 | # Allow global access via indices 104 | def __getitem__(self, given): 105 | 106 | # Check length of indices 107 | slen = len( given ) 108 | 109 | # Only 3D arguments 110 | if ( slen != 3 ): 111 | self.PyMPI.iprint("Error: 3 index ranges must be given") 112 | return None 113 | 114 | indices = [None]*3 115 | 116 | NX = [self.PyMPI.nx,self.PyMPI.ny,self.PyMPI.nz] 117 | for i in range(slen): 118 | 119 | if isinstance( given[i], slice): 120 | start = given[i].start 121 | stop = given[i].stop 122 | if start == None: 123 | start = 0 124 | if stop == None: 125 | stop = NX[i] 126 | else: 127 | start = given[i] 128 | stop = start + 1 129 | indices[i] = [ start, stop ] 130 | 131 | gdata = self.PyMPI.getIJK( self.data, indices[0],indices[1],indices[2] ) 132 | return numpy.squeeze( gdata ) 133 | 134 | 135 | 136 | 137 | -------------------------------------------------------------------------------- /examples/shu_osher.py: -------------------------------------------------------------------------------- 1 | import re 2 | import sys 3 | import time 4 | import numpy 5 | import matplotlib.pyplot as plt 6 | from matplotlib import cm 7 | 8 | from pyranda import pyrandaSim, pyrandaIBM, pyrandaBC, pyrandaTimestep 9 | 10 | 11 | # Try to get args 12 | try: 13 | test = bool(int(sys.argv[1])) 14 | except: 15 | test = False 16 | 17 | 18 | ## Define a mesh 19 | 20 | def getShu(Npts,viz=False): 21 | 22 | L = 10.0 23 | Lp = L * (Npts-1.0) / Npts 24 | imesh = "xdom = (-Lp/2.0, Lp/2.0, Npts)" 25 | imesh = imesh.replace('Lp',str(Lp)) 26 | imesh = imesh.replace('Npts',str(Npts)) 27 | 28 | # Initialize a simulation object on a mesh 29 | ss = pyrandaSim('sod',imesh) 30 | ss.addPackage( pyrandaBC(ss) ) 31 | ss.addPackage( pyrandaTimestep(ss) ) 32 | 33 | # Define the equations of motion 34 | from equation_library import euler_1d 35 | eom = euler_1d 36 | eom += """ 37 | # Apply constant BCs 38 | bc.const(['u'],['xn'],0.0) 39 | bc.const(['u'],['x1'],2.629369) 40 | bc.const(['rho'],['x1'],3.857143) 41 | bc.const(['p'],['x1'],10.33333) 42 | bc.const(['Et'],['x1'],39.166585) 43 | :rhou: = :rho:*:u: 44 | :cs: = sqrt( :p: / :rho: * :gamma: ) 45 | :dt: = dt.courant(:u:,0.0,0.0,:cs:) 46 | :dt: = numpy.minimum(:dt:,0.2 * dt.diff(:beta:,:rho:)) 47 | """ 48 | 49 | # Add the EOM to the solver 50 | ss.EOM(eom) 51 | 52 | 53 | # Initial conditions Shu-Osher test problem 54 | ic = """ 55 | :gamma: = 1.4 56 | eps = 2.0e-1 57 | :tmp: = (meshx+4.0)/%s 58 | :dum: = tanh(:tmp:) 59 | :dum: = (:dum:+1.0)/2.0 60 | :rho: = 3.857143 + :dum:*(1.0+eps*sin(5.0*meshx) - 3.857143) 61 | :u: = 2.629369*(1.0-:dum:) 62 | :p: = 10.33333 + :dum:*(1.0-10.33333) 63 | :rhou: = :rho: * :u: 64 | :Et: = :p:/(:gamma: -1.0) + .5*:rho:*:u:*:u: 65 | """ 66 | 67 | # Set the initial conditions 68 | ss.setIC(ic % ss.dx) 69 | 70 | 71 | # Write a time loop 72 | time = 0.0 73 | 74 | # Approx a max dt and stopping time 75 | CFL = 0.5 76 | 77 | dt = ss.variables['dt'].data * CFL * .01 78 | 79 | # Mesh for viz on master 80 | x = ss.mesh.coords[0].data 81 | xx = ss.PyMPI.zbar( x ) 82 | 83 | # Start time loop 84 | cnt = 1 85 | viz_freq = 50 86 | pvar = 'rho' 87 | #viz = True 88 | tt = 1.8 89 | while tt > time: 90 | 91 | # Update the EOM and get next dt 92 | time = ss.rk4(time,dt) 93 | dt = min( dt*1.1, ss.variables['dt'].data * CFL ) 94 | dt = min(dt, (tt - time) ) 95 | 96 | # Print some output 97 | ss.iprint("%s -- %s" % (cnt,time) ) 98 | cnt += 1 99 | v = ss.PyMPI.zbar( ss.variables[pvar].data ) 100 | if viz: 101 | if (ss.PyMPI.master and (cnt%viz_freq == 0)) and True: 102 | #raw_input('Poop') 103 | plt.figure(1) 104 | plt.clf() 105 | plt.plot(xx[:,0],v[:,0] ,'k.-') 106 | plt.title(pvar) 107 | plt.pause(.001) 108 | 109 | return [ss,xx[:,0],v[:,0]] 110 | 111 | 112 | Npts = [100,200,400,800] 113 | solution = [] 114 | for Npt in Npts: 115 | [ss,x,rho] = getShu(Npt) 116 | solution.append( numpy.interp( 1.85 , x, rho ) ) 117 | if not test: 118 | plt.plot( x, rho , label='N=%s'%Npt) 119 | 120 | solution = numpy.array( solution ) 121 | diff = numpy.abs( solution[1:] - solution[:-1] ) 122 | cr1 = numpy.log ( diff[-1] / diff[-2] ) / numpy.log( .5 ) 123 | cr2 = numpy.log ( diff[-2] / diff[-3] ) / numpy.log( .5 ) 124 | 125 | print( (cr1 + cr2) / 2.0 ) 126 | 127 | if not test: 128 | 129 | # Make a tex file 130 | ss.setupLatex() 131 | 132 | ss.latex.tMap[":rho:"] = r'\rho ' 133 | ss.latex.tMap[":rhou:"] = r'\rho u' 134 | ss.latex.tMap[":Et:"] = r'E_t ' 135 | 136 | 137 | intro = ss.latex.addSection("Introduction") 138 | intro.body = """ 139 | This brief document shows the ability to integrate the simulation with formal 140 | documentation. The advection equations is solved and plotted below. 141 | """ 142 | 143 | equations = ss.latex.addSection("Equations of Motion") 144 | equations.body = """ 145 | Pyranda solves the following equations using a 10th order compact finite difference 146 | stencil and a 5 stage RK4 temporal integration scheme. 147 | """ 148 | equations.body += ss.latex.renderEqu() 149 | 150 | equations.body += """ 151 | where terms are closed following: 152 | """ 153 | 154 | equations.body += ss.latex.renderEqu('ALG') 155 | 156 | 157 | 158 | 159 | results = ss.latex.addSection("Results") 160 | plt.figure(1) 161 | results.addFigure("Profiles",size=.45) 162 | results.body = "Here in the figure, we see the grid convergence" 163 | 164 | ss.latex.makeDoc() 165 | ss.latex.showPDF() 166 | 167 | plt.legend() 168 | plt.show() 169 | -------------------------------------------------------------------------------- /examples/TBL_data/uvmean.dat: -------------------------------------------------------------------------------- 1 | # u'v' 2 | 0.0, 0.0 3 | 1.0243463855894992, 0.033197044805877596 4 | 1.0561693916639248, 0.03539131741024493 5 | 1.078431877452116, 0.03701592308847834 6 | 1.2036609874854756, 0.046193890231744916 7 | 1.2410546967376985, 0.048556953036448025 8 | 1.2760561210597094, 0.050863752441039356 9 | 1.4301878060747364, 0.06020347685962779 10 | 1.4746189437060695, 0.06273532986466757 11 | 1.5183175221286478, 0.06481988883881584 12 | 1.7040794626892863, 0.07438185368784733 13 | 1.7570194953338656, 0.07682931159271833 14 | 1.8065726577044554, 0.07933303289770155 15 | 2.0247841322929103, 0.09539623362967209 16 | 2.0876873832320704, 0.10071312494025442 17 | 2.1465663610436803, 0.10522357418256467 18 | 2.3991628598864336, 0.12510330888879784 19 | 2.4736968020546044, 0.13025140999904394 20 | 2.5434623906626737, 0.13493064944169042 21 | 2.8427635007887244, 0.15481038414792359 22 | 2.9310786268304816, 0.1626591284635448 23 | 3.009555652192205, 0.16965337238996536 24 | 3.340396930846652, 0.19937099703661199 25 | 3.4441718582703955, 0.2076417168530731 26 | 3.5363864989141014, 0.21479420159230855 27 | 3.925142437108777, 0.24595709232933194 28 | 4.047083445908464, 0.25692845535116815 29 | 4.149665847311188, 0.2658863924118542 30 | 4.573925753934541, 0.30224862414136844 31 | 4.7160222840723085, 0.313304382263373 32 | 4.8355604397429035, 0.3221176420094851 33 | 5.315142528241087, 0.3634350717631474 34 | 5.480266177176809, 0.37617873188851103 35 | 5.611367047641865, 0.3861514195583595 36 | 6.15932093379376, 0.42867248419298853 37 | 6.35067037402989, 0.44293525612137596 38 | 6.493556950036577, 0.45296139402133084 39 | 7.097983446151451, 0.4960197741270296 40 | 7.318493981943558, 0.5105357313559207 41 | 7.483156054609422, 0.5209163286765808 42 | 8.179695382557089, 0.5647173856637577 43 | 8.433811079657207, 0.5789801575921447 44 | 8.623567171043634, 0.58924260177257 45 | 9.452510407494328, 0.6329086265994781 46 | 9.74616819781606, 0.6465806328266899 47 | 9.965451599559911, 0.6560835211056029 48 | 10.923383918956718, 0.6966269272262964 49 | 11.262736815297727, 0.7092017971513243 50 | 11.53216799848618, 0.7186540483701367 51 | 12.728900371786926, 0.7564630532453873 52 | 13.124344607790182, 0.7671812309667199 53 | 13.438309832605421, 0.7755926092834611 54 | 14.874160451091258, 0.8081128545481859 55 | 15.336250721575936, 0.8170587351659906 56 | 15.724982372049817, 0.8240876413656943 57 | 17.477922418083885, 0.8518295164351946 58 | 18.020902838675635, 0.8589187048493043 59 | 18.503396496869026, 0.8648685594111463 60 | 20.65203835765283, 0.8870222732052384 61 | 21.293627913051754, 0.8922547694156528 62 | 21.894171392641248, 0.8966902007911473 63 | 24.53871458557946, 0.9116656424542859 64 | 25.301050133692012, 0.9144506807598289 65 | 26.014614808842662, 0.9164949176305646 66 | 29.238061874438078, 0.9201051524710828 67 | 30.146390379057365, 0.9201051524710828 68 | 30.996608023942816, 0.9196925542035954 69 | 34.728536453963486, 0.9130265134444944 70 | 35.91964950404635, 0.9087118139484067 71 | 36.93269018395665, 0.9061799609433678 72 | 41.39369912881702, 0.8919171890149808 73 | 42.679662507368114, 0.8875286438062462 74 | 43.88335560910442, 0.8835902057984075 75 | 49.047315217109144, 0.8659234981632458 76 | 50.571050773797914, 0.8606910019528318 77 | 51.99730443626462, 0.8558429723098495 78 | 58.11607033524909, 0.834106545399921 79 | 59.92154169270991, 0.8270173569858108 80 | 61.52588771880658, 0.8207721195733813 81 | 68.47964041367186, 0.7907274639135835 82 | 70.60707312931979, 0.7808532371939312 83 | 72.39676766229162, 0.7724981222773022 84 | 79.57694738885209, 0.7314821035956682 85 | 82.04913620678042, 0.7164597757657694 86 | 83.89519645655115, 0.7054715337238999 87 | 91.1955513312268, 0.6551045379436546 88 | 94.02869119953809, 0.6351028992038454 89 | 95.74401715844975, 0.6248910920835211 90 | 102.63814087907922, 0.5691903259726603 91 | 105.38618588582733, 0.5471163186620598 92 | 107.01066325813332, 0.5348415202042962 93 | 113.4469034794136, 0.4743829803214661 94 | 115.83819610383419, 0.4522187171398526 95 | 117.46032878422432, 0.43829352561213764 96 | 124.00664983918921, 0.37435368784737877 97 | 126.44456643189078, 0.3533498572930749 98 | 128.39364861275834, 0.3380321466125884 99 | 135.92682992478896, 0.2726997896950576 100 | 138.7919660888536, 0.250900233910599 101 | 140.73553040132356, 0.23777076761303872 102 | 150.03242028667873, 0.17481202288773234 103 | 154.69342430769262, 0.15109699974053248 104 | 169.56338070274916, 0.0921892198232892 105 | 174.8311461481247, 0.07547898999003078 106 | 178.5163276513719, 0.06649091182214217 107 | 195.4043444461779, 0.034197729565012214 108 | 203.16299610978118, 0.021888101383369385 109 | 208.0231333321674, 0.015896049271443502 110 | 232.17908828695298, 0.0050934764499435126 111 | 239.39211372527495, 0.003996340147759625 112 | 246.48621427241667, 0.00327054228631507 113 | 276.6431194107411, 0.0028992038455761815 114 | 295.73935362723165, 0.0028992038455761815 -------------------------------------------------------------------------------- /examples/unit_test.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import time 3 | import numpy 4 | import matplotlib.pyplot as plt 5 | from pyranda import pyrandaSim 6 | 7 | ERROR = 0.0 8 | ############################## 9 | ######## DERIVATIVES ######## 10 | ############################## 11 | 12 | # Define the domain/mesh 13 | Nx = 32 14 | L = numpy.pi*2.0 * (Nx-1) / Nx 15 | domain = """ 16 | xdom = (0.0 , L , Nx ,periodic=True) 17 | ydom = (0.0 , L , Nx ,periodic=True) 18 | zdom = (0.0 , L , Nx ,periodic=True) 19 | """.replace('L',str(L)).replace('Nx',str(Nx)) 20 | 21 | # Periodic function in X-Y-Z 22 | pysim = pyrandaSim('advection',domain) 23 | 24 | expr = "sum( abs( ddx( sin(meshx) ) - cos(meshx) ))" 25 | errorX = pysim.eval(expr) 26 | errorY = pysim.eval(expr.replace('x','y')) 27 | errorZ = pysim.eval(expr.replace('x','z')) 28 | ERROR += errorX + errorY + errorZ 29 | 30 | print('Error X = %s' % errorX) 31 | print('Error Y = %s' % errorY) 32 | print('Error Z = %s' % errorZ) 33 | 34 | # Non-periodic case 35 | domain = """ 36 | xdom = (0.0 , 1.0 , Nx ) 37 | ydom = (0.0 , 1.0 , Nx ) 38 | zdom = (0.0 , 1.0 , Nx ) 39 | """.replace('Nx',str(Nx)) 40 | pysim2 = pyrandaSim('nonperiodic',domain) 41 | 42 | # Zero 43 | print("Zero ") 44 | expr = "mean( abs(ddx(meshx*0.0)) )" 45 | errorX = pysim2.eval(expr) 46 | errorY = pysim2.eval(expr.replace('x','y')) 47 | errorZ = pysim2.eval(expr.replace('x','z')) 48 | ERROR += errorX + errorY + errorZ 49 | 50 | print('Error X = %s' % errorX) 51 | print('Error Y = %s' % errorY) 52 | print('Error Z = %s' % errorZ) 53 | 54 | # Constant 55 | print("Constant ") 56 | expr = "mean( abs(ddx(meshx*0.0 + 1.0)) )" 57 | errorX = pysim2.eval(expr) 58 | errorY = pysim2.eval(expr.replace('x','y')) 59 | errorZ = pysim2.eval(expr.replace('x','z')) 60 | ERROR += errorX + errorY + errorZ 61 | 62 | print('Error X = %s' % errorX) 63 | print('Error Y = %s' % errorY) 64 | print('Error Z = %s' % errorZ) 65 | 66 | # Powers 67 | powers = [1,2,3,4] 68 | expr = "mean( abs(ddx(meshx**power) - power*meshx**(power-1) ) )" 69 | for power in powers: 70 | print("Power = %s" % power) 71 | exp = expr.replace('power',str(float(power))) 72 | errorX = pysim2.eval(exp) 73 | errorY = pysim2.eval(exp.replace('x','y')) 74 | errorZ = pysim2.eval(exp.replace('x','z')) 75 | ERROR += errorX + errorY + errorZ 76 | print('Error X = %s' % errorX) 77 | print('Error Y = %s' % errorY) 78 | print('Error Z = %s' % errorZ) 79 | 80 | 81 | ############################## 82 | ########## FILTERS ########## 83 | ############################## 84 | print("Filters-fbar") 85 | # Zero 86 | print("Zero ") 87 | expr = "mean( abs(fbar(meshx*0.0)) )" 88 | errorX = pysim2.eval(expr) 89 | print('Error X = %s' % errorX) 90 | ERROR += errorX 91 | 92 | # Constant 93 | print("Constant ") 94 | expr = "mean( abs(fbar(meshx*0.0 + 1.0) - (meshx*0.0 + 1.0) ) )" 95 | errorX = pysim2.eval(expr) 96 | print('Error X = %s' % errorX) 97 | ERROR += errorX 98 | 99 | # Linear 100 | print("Linear ") 101 | expr = "mean( abs(fbar(meshx) - (meshx) ) )" 102 | errorX = pysim2.eval(expr) 103 | print('Error X = %s' % errorX) 104 | ERROR += errorX 105 | 106 | # Periodic 107 | print("sine wave") 108 | expr = "mean( abs(fbar(sin(meshx)) - sin(meshx) ) )" 109 | pysim.PyMPI.setPatch() 110 | errorX = pysim.eval(expr) 111 | print('Error X = %s' % errorX) 112 | ERROR += errorX 113 | 114 | print("periodic constant") 115 | expr = "mean( abs(fbar( meshx*0.0 + 1.0) - 1.0 ) )" 116 | errorX = pysim.eval(expr) 117 | print('Error X = %s' % errorX) 118 | ERROR += errorX 119 | 120 | print("periodic zero") 121 | expr = "mean( abs(fbar( meshx*0.0 ) ) )" 122 | errorX = pysim.eval(expr) 123 | print('Error X = %s' % errorX) 124 | ERROR += errorX 125 | 126 | 127 | print("Filters-gbar") 128 | # Zero 129 | print("Zero ") 130 | expr = "mean( abs(gbar(meshx*0.0)) )" 131 | pysim2.PyMPI.setPatch() 132 | errorX = pysim2.eval(expr) 133 | print('Error X = %s' % errorX) 134 | ERROR += errorX 135 | 136 | # Constant 137 | print("Constant ") 138 | expr = "mean( abs(gbar(meshx*0.0 + 1.0) - (meshx*0.0 + 1.0) ) )" 139 | errorX = pysim2.eval(expr) 140 | print('Error X = %s' % errorX) 141 | ERROR += errorX 142 | 143 | # Linear 144 | print("Linear ") 145 | expr = "mean( abs(gbar(meshx) - (meshx) ) )" 146 | errorX = pysim2.eval(expr) 147 | print('Error X = %s' % errorX) 148 | ERROR += errorX 149 | 150 | # Periodic 151 | print("sine wave") 152 | expr = "mean( abs(gbar(sin(meshx)) - sin(meshx) ) )" 153 | pysim.PyMPI.setPatch() 154 | errorX = pysim.eval(expr) 155 | print('Error X = %s' % errorX) 156 | ERROR += errorX 157 | 158 | print("periodic constant") 159 | expr = "mean( abs(gbar( meshx*0.0 + 1.0) - 1.0 ) )" 160 | errorX = pysim.eval(expr) 161 | print('Error X = %s' % errorX) 162 | ERROR += errorX 163 | 164 | print("periodic zero") 165 | expr = "mean( abs(gbar( meshx*0.0 ) ) )" 166 | errorX = pysim.eval(expr) 167 | print('Error X = %s' % errorX) 168 | ERROR += errorX 169 | 170 | 171 | #fid = open('unit_test.out','w') 172 | #fid.write(out) 173 | #fid.close() 174 | print(ERROR) 175 | -------------------------------------------------------------------------------- /examples/interface2.py: -------------------------------------------------------------------------------- 1 | from mpi4py import MPI 2 | import numpy 3 | import re 4 | import sys 5 | import time 6 | # TODO: remove 7 | #sys.path.append('/Users/olson45/Research/FloATPy') 8 | import matplotlib.pyplot as plt 9 | from pyranda import pyrandaSim, pyrandaMPI, pyrandaIBM 10 | 11 | 12 | 13 | ## Define a mesh 14 | Npts = 128 15 | L = numpy.pi * 2.0 16 | Lp = L * (Npts-1.0) / Npts 17 | 18 | mesh_options = {} 19 | mesh_options['type'] = 'cartesian' 20 | mesh_options['periodic'] = numpy.array([False, True, True]) 21 | mesh_options['dim'] = 3 22 | mesh_options['x1'] = [ 0.0 , 0.0 , 0.0 ] 23 | mesh_options['xn'] = [ Lp , Lp , Lp ] 24 | mesh_options['nn'] = [ Npts, 1 , 1 ] 25 | #mesh_options['nn'] = [ Npts, Npts , 1 ] 26 | 27 | 28 | # Initialize a simulation object on a mesh 29 | ss = pyrandaSim('advection',mesh_options) 30 | ss.addPackage( pyrandaIBM(ss) ) 31 | 32 | 33 | # Define the equations of motion 34 | eom =""" 35 | # Primary Equations of motion here 36 | ddt(:rho:) = -ddx(:rho:*:u:) - ddy(:rho:*:v:) 37 | ddt(:rhou:) = -ddx(:rhou:*:u: + :p: - :tau:) - ddy(:rhou:*:v:) 38 | ddt(:rhoA:) = -ddx(:rhoA:*:uA:) 39 | ddt(:rhoAuA:) = -ddx(:rhoAuA:*:uA: + :pA: - :tauA:) 40 | ddt(:EtA:) = -ddx( (:EtA: + :pA: - :tauA:)*:uA: ) 41 | ddt(:rhov:) = -ddx(:rhov:*:u:) - ddy(:rhov:*:v: + :p: - :tau:) 42 | ddt(:Et:) = -ddx( (:Et: + :p: - :tau:)*:u: ) - ddy( (:Et: + :p: - :tau:)*:v: ) 43 | ddt(:phi:) = - :gx: * :u1: 44 | #:u1: = .001 * sin( simtime * 0.0 ) 45 | # Conservative filter of the EoM 46 | :rho: = fbar( :rho: ) 47 | :rhou: = fbar( :rhou: ) 48 | :rhoA: = fbar( :rhoA: ) 49 | :rhoAuA: = fbar( :rhoAuA: ) 50 | :EtA: = fbar( :EtA: ) 51 | :rhov: = fbar( :rhov: ) 52 | :Et: = fbar( :Et: ) 53 | # Update the primatives and enforce the EOS 54 | :u: = :rhou: / :rho: * 0.0 + 0.7 55 | :v: = :rhov: / :rho: * 0.0 + 0.7 56 | :uA: = :rhoAuA: / :rhoA: 57 | # Artificial bulk viscosity (old school way) 58 | :div: = ddx(:u:) + ddy(:v:) 59 | :beta: = gbar(abs(lap(lap(:div:))))*:dx6: * :rho: * 0.2 60 | :tau: = :beta:*:div: 61 | :divA: = ddx(:uA:) 62 | :betaA: = gbar(abs(lap(lap(:divA:))))*:dx6: * :rhoA: * 0.2 63 | :tauA: = :betaA:*:divA: 64 | # Immersed boundary method used for MM levelset 65 | [:gx:,:gy:,:gz:] = grad( :phi: ) 66 | [:u:,:v:,:w:] = ibmV( [:u:,:v:,0.0], :phi:, [:gx:,:gy:,:gz:], [:u1:,0.0,0.0] ) 67 | :Et: = ibmS( :Et: , :phi:, [:gx:,:gy:,:gz:] ) 68 | :rho: = ibmS( :rho: , :phi:, [:gx:,:gy:,:gz:] ) 69 | [:uA:,:v:,:w:] = ibmV( [:uA:,:v:,0.0], -:phi:, [-:gx:,-:gy:,-:gz:], [:u1:,0.0,0.0] ) 70 | :EtA: = ibmS( :EtA: , -:phi:, [-:gx:,-:gy:,-:gz:] ) 71 | :rhoA: = ibmS( :rhoA: , -:phi:, [-:gx:,-:gy:,-:gz:] ) 72 | :p: = ( :Et: - .5*:rho:*(:u:*:u: + :v:*:v:) ) * ( 1.4 - 1.0 ) 73 | :pA: = ( :EtA: - .5*:rhoA:*(:uA:*:uA: ) ) * ( 1.4 - 1.0 ) 74 | :uT: = where( :phi: > 0.0, :u:, :uA:) 75 | :pT: = where( :phi: > 0.0, :p:, :pA:) 76 | :rhoB: = where( :phi: > 0.0, :rho:, :rhoA:) 77 | :rhoT: = where( abs(:phi:/:dx:*2.0) > 1.0, :rhoB:, .5*(:phi:/:dx:*2.0 + 1.0)*(:rho:-:rhoA:) + (:rhoA:) ) 78 | """ 79 | ss.EOM(eom) 80 | 81 | #:umag: = numpy.sqrt(:u:*:u: + :v:*:v:) 82 | 83 | # Initialize variables 84 | x = ss.mesh.coords[0].data 85 | y = ss.mesh.coords[1].data 86 | z = ss.mesh.coords[2].data 87 | 88 | 89 | rad = numpy.sqrt( (x-numpy.pi)**2 ) # + (y-numpy.pi)**2 ) #+ (z-numpy.pi)**2 ) 90 | ss.variables['Et'].data += 2.5 91 | ss.variables['rho'].data += 1.0 92 | 93 | ss.variables['EtA'].data += 2.5 94 | ss.variables['rhoA'].data += 10.0e1 * (1.0 + .1*numpy.exp(-(x-numpy.pi*1.5)**2/.01) ) 95 | 96 | # Init momenta 97 | ss.variables['rhou'].data = ss.variables['rho'].data * .70 98 | ss.variables['rhoAuA'].data = ss.variables['rhoA'].data * .70 99 | ss.variables['u1'].data = .70 100 | 101 | ss.variables['dx'].data += (x[1,0,0] - x[0,0,0]) 102 | ss.variables['dx6'].data += (x[1,0,0] - x[0,0,0])**6 103 | 104 | # Define the interface location 105 | ss.variables['phi'].data = 3.14159 - x 106 | 107 | 108 | time = 0.0 109 | viz = True 110 | 111 | v = 1.0 112 | 113 | dt_max = v / ss.mesh.nn[0] * 1.0 114 | 115 | tt = L/v * .25 #dt_max 116 | 117 | xx = ss.PyMPI.zbar( x ) 118 | yy = ss.PyMPI.zbar( y ) 119 | 120 | dt = dt_max 121 | cnt = 1 122 | 123 | 124 | while tt > time: 125 | 126 | time = ss.rk4(time,dt) 127 | dt = min(dt_max, (tt - time) ) 128 | 129 | ss.iprint("%s -- %s" % (cnt,time) ) 130 | cnt += 1 131 | if viz: 132 | #v1 = ss.PyMPI.zbar( ss.variables['rhoA'].data ) 133 | v2 = ss.PyMPI.zbar( ss.variables['rhoT'].data ) 134 | if ss.PyMPI.master and (cnt%5 == 0) and True: 135 | plt.figure(2) 136 | plt.clf() 137 | #plt.contourf( xx,yy,phi ,64 ) 138 | #plt.plot(xx[:,0],v1[:,0] ,'b.-') 139 | plt.plot(xx[:,0],v2[:,0] ,'k.-') 140 | plt.pause(.001) 141 | #import pdb 142 | #pdb.set_trace() 143 | 144 | 145 | 146 | -------------------------------------------------------------------------------- /examples/tutorials/cylinder.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import numpy 3 | from pyranda import pyrandaSim, pyrandaBC, pyrandaTimestep, pyrandaIBM 4 | 5 | 6 | 7 | ## Define a mesh 8 | Npts = 64 9 | L = numpy.pi * 2.0 10 | dim = 2 11 | gamma = 1.4 12 | 13 | problem = 'cylinder' 14 | 15 | Lp = L * (Npts-1.0) / Npts 16 | 17 | sys.path.append('../') 18 | from meshTest import zoomMesh_solve 19 | dxf = 4*Lp / float(Npts) * .3 20 | xS = zoomMesh_solve(Npts,-2.*Lp,2.*Lp,-2.,2.,1.0,dxf) 21 | 22 | def zoomMesh(i,j,k): 23 | x = xS[i] 24 | y = xS[j] 25 | z = 0.0 26 | return x,y,z 27 | 28 | mesh_options = {} 29 | mesh_options['coordsys'] = 3 30 | mesh_options['function'] = zoomMesh 31 | mesh_options['periodic'] = numpy.array([False, False, True]) 32 | mesh_options['gridPeriodic'] = numpy.array([False, False, False]) 33 | mesh_options['dim'] = 3 34 | mesh_options['x1'] = [ -2*Lp , -2*Lp , 0.0 ] 35 | mesh_options['xn'] = [ 2*Lp , 2*Lp , Lp ] 36 | mesh_options['nn'] = [ Npts, Npts , 1 ] 37 | 38 | 39 | # Initialize a simulation object on a mesh 40 | ss = pyrandaSim(problem,mesh_options) 41 | ss.addPackage( pyrandaBC(ss) ) 42 | ss.addPackage( pyrandaIBM(ss) ) 43 | ss.addPackage( pyrandaTimestep(ss) ) 44 | 45 | 46 | rho0 = 1.0 47 | p0 = 1.0 48 | gamma = 1.4 49 | mach = 2.0 50 | s0 = numpy.sqrt( p0 / rho0 * gamma ) 51 | u0 = s0 * mach 52 | e0 = p0/(gamma-1.0) + rho0*.5*u0*u0 53 | 54 | 55 | # Define the equations of motion 56 | eom =""" 57 | # Primary Equations of motion here 58 | ddt(:rho:) = -div(:rho:*:u:, :rho:*:v:) 59 | ddt(:rhou:) = -div(:rhou:*:u: + :p: - :tau:, :rhou:*:v:) 60 | ddt(:rhov:) = -div(:rhov:*:u:, :rhov:*:v: + :p: - :tau:) 61 | ddt(:Et:) = -div( (:Et: + :p: - :tau:)*:u: - :tx:*:kappa:, (:Et: + :p: - :tau:)*:v: - :ty:*:kappa: ) 62 | # Level set equation 63 | #ddt(:phi:) = - :gx: * :u1: - :gy: * :v1: 64 | # Conservative filter of the EoM 65 | :rho: = fbar( :rho: ) 66 | :rhou: = fbar( :rhou: ) 67 | :rhov: = fbar( :rhov: ) 68 | :Et: = fbar( :Et: ) 69 | # Update the primatives and enforce the EOS 70 | :u: = :rhou: / :rho: 71 | :v: = :rhov: / :rho: 72 | :p: = ( :Et: - .5*:rho:*(:u:*:u: + :v:*:v:) ) * ( :gamma: - 1.0 ) 73 | :T: = :p: / (:rho: * :R: ) 74 | # Artificial bulk viscosity (old school way) 75 | :div: = div(:u:,:v:) 76 | :beta: = gbar( ring(:div:) * :rho: ) * 7.0e-3 77 | :tau: = :beta: * :div: 78 | [:tx:,:ty:,:tz:] = grad(:T:) 79 | :kappa: = gbar( ring(:T:)* :rho:*:cv:/(:T: * :dt: ) ) * 1.0e-3 80 | # Apply BCs and internal IBM 81 | [:u:,:v:,:w:] = ibmV( [:u:,:v:,0.0], :phi:, [:gx:,:gy:,:gz:], [:u1:,:u2:,0.0] ) 82 | :rho: = ibmS( :rho: , :phi:, [:gx:,:gy:,:gz:] ) 83 | :p: = ibmS( :p: , :phi:, [:gx:,:gy:,:gz:] ) 84 | bc.extrap(['rho','p','u'],['xn']) 85 | bc.const(['u'],['x1','y1','yn'],u0) 86 | bc.const(['v'],['x1','xn','y1','yn'],0.0) 87 | bc.const(['rho'],['x1','y1','yn'],rho0) 88 | bc.const(['p'],['x1','y1','yn'],p0) 89 | :Et: = :p: / ( :gamma: - 1.0 ) + .5*:rho:*(:u:*:u: + :v:*:v:) 90 | :rhou: = :rho:*:u: 91 | :rhov: = :rho:*:v: 92 | :cs: = sqrt( :p: / :rho: * :gamma: ) 93 | :dt: = dt.courant(:u:,:v:,:w:,:cs:) 94 | :dtB: = 0.2* dt.diff(:beta:,:rho:) 95 | :dt: = numpy.minimum(:dt:,:dtB:) 96 | :umag: = sqrt( :u:*:u: + :v:*:v: ) 97 | """ 98 | eom = eom.replace('u0',str(u0)).replace('p0',str(p0)).replace('rho0',str(rho0)) 99 | 100 | 101 | # Add the EOM to the solver 102 | ss.EOM(eom) 103 | 104 | 105 | # Initialize variables 106 | ic = """ 107 | :gamma: = 1.4 108 | :R: = 1.0 109 | :cp: = :R: / (1.0 - 1.0/:gamma: ) 110 | :cv: = :cp: - :R: 111 | #rad = sqrt( (meshx-pi)**2 + (meshy-pi)**2 ) 112 | rad = sqrt( meshx**2 + meshy**2 ) 113 | :phi: = rad - pi/4.0 114 | :rho: = 1.0 + 3d() 115 | :p: = 1.0 + 3d() #exp( -(meshx-1.5)**2/.25**2)*.1 116 | :u: = where( :phi:>0.5, mach * sqrt( :p: / :rho: * :gamma:) , 0.0 ) 117 | #:u: = mach * sqrt( :p: / :rho: * :gamma:) 118 | :u: = gbar( gbar( :u: ) ) 119 | :v: = 0.0 + 3d() 120 | :Et: = :p:/( :gamma: - 1.0 ) + .5*:rho:*(:u:*:u: + :v:*:v:) 121 | :rhou: = :rho:*:u: 122 | :rhov: = :rho:*:v: 123 | :cs: = sqrt( :p: / :rho: * :gamma: ) 124 | :dt: = dt.courant(:u:,:v:,:w:,:cs:) 125 | [:gx:,:gy:,:gz:] = grad( :phi: ) 126 | :gx: = gbar( :gx: ) 127 | :gy: = gbar( :gy: ) 128 | """ 129 | ic = ic.replace('mach',str(mach)) 130 | 131 | # Set the initial conditions 132 | ss.setIC(ic) 133 | 134 | 135 | # Write a time loop 136 | time = 0.0 137 | viz = True 138 | 139 | # Approx a max dt and stopping time 140 | tt = 3.0 # 141 | 142 | # Start time loop 143 | cnt = 1 144 | viz_freq = 100 145 | pvar = 'umag' 146 | 147 | CFL = 1.0 148 | dt = ss.var('dt').data * CFL*.01 149 | wvars = ['p','rho','u','v','phi'] 150 | ss.write( wvars ) 151 | while tt > time: 152 | 153 | # Update the EOM and get next dt 154 | time = ss.rk4(time,dt) 155 | dt = min( ss.variables['dt'].data * CFL, dt*1.1) 156 | dt = min(dt, (tt - time) ) 157 | 158 | # Print some output 159 | ss.iprint("%s -- %s --- %f" % (cnt,time,dt) ) 160 | cnt += 1 161 | if (cnt%viz_freq == 1) : 162 | ss.write(wvars) 163 | 164 | 165 | ss.writeRestart() 166 | 167 | 168 | -------------------------------------------------------------------------------- /examples/euler.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function 2 | import re 3 | import sys 4 | import time 5 | import numpy 6 | import matplotlib.pyplot as plt 7 | from matplotlib import cm 8 | 9 | from pyranda import pyrandaSim, pyrandaBC 10 | 11 | 12 | 13 | # Try to get args for testing 14 | try: 15 | Npts = int(sys.argv[1]) 16 | except: 17 | Npts = 128 18 | 19 | #import pdb 20 | #pdb.set_trace() 21 | try: 22 | test = bool(int(sys.argv[2])) 23 | except: 24 | test = False 25 | 26 | try: 27 | testName = (sys.argv[3]) 28 | except: 29 | testName = None 30 | 31 | 32 | 33 | 34 | ## Define a mesh 35 | L = numpy.pi * 2.0 36 | gamma = 1.4 37 | dim = 2 38 | 39 | problem = 'sod' 40 | 41 | Lp = L * (Npts-1.0) / Npts 42 | mesh_options = {} 43 | mesh_options['coordsys'] = 0 44 | mesh_options['periodic'] = numpy.array([False, False, True]) 45 | mesh_options['dim'] = 3 46 | mesh_options['x1'] = [ 0.0 , 0.0 , 0.0 ] 47 | mesh_options['xn'] = [ Lp , Lp , Lp ] 48 | mesh_options['nn'] = [ Npts, 1 , 1 ] 49 | if dim == 2: 50 | mesh_options['nn'] = [ Npts, Npts , 1 ] 51 | 52 | 53 | # Initialize a simulation object on a mesh 54 | ss = pyrandaSim('advection',mesh_options) 55 | ss.addPackage( pyrandaBC(ss) ) 56 | 57 | # Define the equations of motion 58 | eom =""" 59 | # Primary Equations of motion here 60 | ddt(:rho:) = -ddx(:rho:*:u:) - ddy(:rho:*:v:) 61 | ddt(:rhou:) = -ddx(:rhou:*:u: + :p: - :tau:) - ddy(:rhou:*:v:) 62 | ddt(:rhov:) = -ddx(:rhov:*:u:) - ddy(:rhov:*:v: + :p: - :tau:) 63 | ddt(:Et:) = -ddx( (:Et: + :p: - :tau:)*:u: ) - ddy( (:Et: + :p: - :tau:)*:v: ) 64 | # Conservative filter of the EoM 65 | :rho: = fbar( :rho: ) 66 | :rhou: = fbar( :rhou: ) 67 | :rhov: = fbar( :rhov: ) 68 | :Et: = fbar( :Et: ) 69 | # Update the primatives and enforce the EOS 70 | :u: = :rhou: / :rho: 71 | :v: = :rhov: / :rho: 72 | :p: = ( :Et: - .5*:rho:*(:u:*:u: + :v:*:v:) ) * ( :gamma: - 1.0 ) 73 | # Artificial bulk viscosity (old school way) 74 | :div: = ddx(:u:) + ddy(:v:) 75 | :beta: = gbar(abs(ring(:div:))) * :rho: * 7.0e-2 76 | :tau: = :beta:*:div: 77 | """ 78 | if dim == 2: 79 | eom += """# Apply constant BCs 80 | bc.extrap(['rho','Et'],['x1','xn','y1','yn']) 81 | bc.const(['u','v'],['x1','xn','y1','yn'],0.0) 82 | """ 83 | else: 84 | eom += """# Apply constant BCs 85 | bc.extrap(['rho','Et'],['x1']) 86 | bc.const(['u','v'],['x1','xn'],0.0) 87 | """ 88 | 89 | print(eom) 90 | 91 | # Add the EOM to the solver 92 | ss.EOM(eom) 93 | 94 | 95 | # Initialize variables 96 | ic = "rad = sqrt( (meshx-pi)**2 ) " 97 | if dim == 2: 98 | ic = "rad = sqrt( (meshx-pi)**2 + (meshy-pi)**2 ) " 99 | 100 | # Linear wave propagation in 1d and 2d 101 | if (problem == 'linear'): 102 | pvar = 'p' 103 | ic += """ 104 | :gamma: = 1.4 105 | ratio = 1.0 + 0.01 * exp( -(rad)**2/(.2**2) ) 106 | :Et: = ratio 107 | :rho: = 1.0 108 | """ 109 | 110 | # SOD shock tube in 1d and 2d 111 | if (problem == 'sod'): 112 | pvar = 'rho' 113 | if dim == 1: 114 | ic = 'rad = meshx / 2.0' 115 | ic += """ 116 | :gamma: = 1.4 117 | :Et: = gbar( where( rad < pi/2.0, 1.0/(:gamma:-1.0) , .1 /(:gamma:-1.0) ) ) 118 | :rho: = gbar( where( rad < pi/2.0, 1.0 , .125 ) ) 119 | """ 120 | 121 | # Set the initial conditions 122 | ss.setIC(ic) 123 | 124 | # Length scale for art. viscosity 125 | # Initialize variables 126 | x = ss.mesh.coords[0].data 127 | y = ss.mesh.coords[1].data 128 | z = ss.mesh.coords[2].data 129 | #ss.variables['dx6'].data += (x[1,0,0] - x[0,0,0])**6 130 | #ss.variables['dx2'].data += (x[1,0,0] - x[0,0,0])**2 131 | 132 | 133 | # Write a time loop 134 | time = 0.0 135 | viz = True 136 | 137 | # Approx a max dt and stopping time 138 | v = 1.0 139 | dt_max = v / ss.mesh.nn[0] * 0.75 140 | tt = L/v * .125 #dt_max 141 | 142 | # Mesh for viz on master 143 | xx = ss.PyMPI.zbar( x ) 144 | yy = ss.PyMPI.zbar( y ) 145 | ny = ss.PyMPI.ny 146 | 147 | # Start time loop 148 | dt = dt_max 149 | cnt = 1 150 | viz_freq = 25 151 | 152 | while tt > time: 153 | 154 | # Update the EOM and get next dt 155 | time = ss.rk4(time,dt) 156 | dt = min(dt_max, (tt - time) ) 157 | 158 | 159 | # Print some output 160 | ss.iprint("%s -- %s" % (cnt,time) ) 161 | cnt += 1 162 | if viz and (not test): 163 | v = ss.PyMPI.zbar( ss.variables[pvar].data ) 164 | if (ss.PyMPI.master and (cnt%viz_freq == 1)) and True: 165 | plt.figure(1) 166 | plt.clf() 167 | if ( ny > 1): 168 | plt.plot(xx[:,int(ny/2)],v[:,int(ny/2)] ,'k.-') 169 | plt.title(pvar) 170 | plt.pause(.001) 171 | plt.figure(2) 172 | plt.clf() 173 | plt.contourf( xx,yy,v ,64 , cmap=cm.jet) 174 | else: 175 | plt.plot(xx[:,0],v[:,0] ,'k.-') 176 | plt.title(pvar) 177 | plt.pause(.001) 178 | 179 | 180 | 181 | # Curve test. Write file and print its name at the end 182 | if test: 183 | v = ss.PyMPI.zbar( ss.variables[pvar].data ) 184 | v1d = v[:,int(ny/2)] 185 | x1d = xx[:,int(ny/2)] 186 | fname = testName + '.dat' 187 | numpy.savetxt( fname , (x1d,v1d) ) 188 | print(fname) 189 | -------------------------------------------------------------------------------- /examples/cylinder.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import numpy 3 | import matplotlib.pyplot as plt 4 | from matplotlib import cm 5 | 6 | from pyranda import pyrandaSim, pyrandaBC, pyrandaTimestep, pyrandaIBM 7 | 8 | 9 | # Try to get args for testing 10 | try: 11 | Npts = int(sys.argv[1]) 12 | except: 13 | Npts = 64 14 | 15 | try: 16 | test = bool(int(sys.argv[2])) 17 | except: 18 | test = False 19 | 20 | try: 21 | testName = (sys.argv[3]) 22 | except: 23 | testName = None 24 | 25 | 26 | ## Define a mesh 27 | #Npts = 32 28 | L = numpy.pi * 2.0 29 | dim = 2 30 | gamma = 1.4 31 | 32 | problem = 'cylinder_test' 33 | 34 | Lp = L * (Npts-1.0) / Npts 35 | mesh_options = {} 36 | mesh_options['coordsys'] = 0 37 | mesh_options['periodic'] = numpy.array([False, False, False]) 38 | mesh_options['dim'] = 3 39 | mesh_options['x1'] = [ 0.0 , 0.0 , 0.0 ] 40 | mesh_options['xn'] = [ Lp , Lp , Lp ] 41 | mesh_options['nn'] = [ Npts , Npts , 1 ] 42 | 43 | 44 | # Initialize a simulation object on a mesh 45 | ss = pyrandaSim(problem,mesh_options) 46 | ss.addPackage( pyrandaBC(ss) ) 47 | ss.addPackage( pyrandaIBM(ss) ) 48 | ss.addPackage( pyrandaTimestep(ss) ) 49 | 50 | 51 | rho0 = 1.0 52 | p0 = 1.0 53 | gamma = 1.4 54 | mach = 2.0 55 | s0 = numpy.sqrt( p0 / rho0 * gamma ) 56 | u0 = s0 * mach 57 | e0 = p0/(gamma-1.0) + rho0*.5*u0*u0 58 | 59 | 60 | # Define the equations of motion 61 | eom =""" 62 | # Primary Equations of motion here 63 | ddt(:rho:) = -ddx(:rho:*:u:) - ddy(:rho:*:v:) 64 | ddt(:rhou:) = -ddx(:rhou:*:u: + :p: - :tau:) - ddy(:rhou:*:v:) 65 | ddt(:rhov:) = -ddx(:rhov:*:u:) - ddy(:rhov:*:v: + :p: - :tau:) 66 | ddt(:Et:) = -ddx( (:Et: + :p: - :tau:)*:u: - :tx:*:kappa:) - ddy( (:Et: + :p: - :tau:)*:v: - :ty:*:kappa: ) 67 | # Level set equation 68 | #ddt(:phi:) = - :gx: * :u1: - :gy: * :v1: 69 | # Conservative filter of the EoM 70 | :rho: = fbar( :rho: ) 71 | :rhou: = fbar( :rhou: ) 72 | :rhov: = fbar( :rhov: ) 73 | :Et: = fbar( :Et: ) 74 | # Update the primatives and enforce the EOS 75 | :u: = :rhou: / :rho: 76 | :v: = :rhov: / :rho: 77 | :p: = ( :Et: - .5*:rho:*(:u:*:u: + :v:*:v:) ) * ( :gamma: - 1.0 ) 78 | :T: = :p: / (:rho: * :R: ) 79 | # Artificial bulk viscosity (old school way) 80 | :div: = ddx(:u:) + ddy(:v:) 81 | :beta: = gbar( ring(:div:) * :rho: ) * 7.0e-2 82 | :tau: = :beta:*:div: 83 | [:tx:,:ty:,:tz:] = grad(:T:) 84 | :kappa: = gbar( ring(:T:)* :rho:*:cv:/(:T: * :dt: ) ) * 1.0e-3 85 | # Apply constant BCs 86 | [:u:,:v:,:w:] = ibmV( [:u:,:v:,:w:], :phi:, [:gx:,:gy:,:gz:], [:u1:,:u2:,0.0] ) 87 | :rho: = ibmS( :rho: , :phi:, [:gx:,:gy:,:gz:] ) 88 | :p: = ibmS( :p: , :phi:, [:gx:,:gy:,:gz:] ) 89 | bc.extrap(['rho','p','u'],['xn']) 90 | bc.const(['u'],['x1','y1','yn'],u0) 91 | bc.const(['v'],['x1','xn','y1','yn'],0.0) 92 | bc.const(['rho'],['x1','y1','yn'],rho0) 93 | bc.const(['p'],['x1','y1','yn'],p0) 94 | :Et: = :p: / ( :gamma: - 1.0 ) + .5*:rho:*(:u:*:u: + :v:*:v:) 95 | :rhou: = :rho:*:u: 96 | :rhov: = :rho:*:v: 97 | :cs: = sqrt( :p: / :rho: * :gamma: ) 98 | :dt: = dt.courant(:u:,:v:,:w:,:cs:) 99 | :dtB: = 0.2* dt.diff(:beta:,:rho:) 100 | :dt: = numpy.minimum(:dt:,:dtB:) 101 | :umag: = sqrt( :u:*:u: + :v:*:v: ) 102 | """ 103 | eom = eom.replace('u0',str(u0)).replace('p0',str(p0)).replace('rho0',str(rho0)) 104 | 105 | 106 | # Add the EOM to the solver 107 | ss.EOM(eom) 108 | 109 | 110 | # Initialize variables 111 | ic = """ 112 | :gamma: = 1.4 113 | :R: = 1.0 114 | :cp: = :R: / (1.0 - 1.0/:gamma: ) 115 | :cv: = :cp: - :R: 116 | rad = sqrt( (meshx-pi)**2 + (meshy-pi)**2 ) 117 | :phi: = rad - pi/4.0 118 | :rho: = 1.0 + 3d() 119 | :p: = 1.0 + 3d() #exp( -(meshx-1.5)**2/.25**2)*.1 120 | :u: = where( :phi:>0.5, mach * sqrt( :p: / :rho: * :gamma:) , 0.0 ) 121 | #:u: = mach * sqrt( :p: / :rho: * :gamma:) 122 | :u: = gbar( gbar( :u: ) ) 123 | :v: = 0.0 + 3d() 124 | :Et: = :p:/( :gamma: - 1.0 ) + .5*:rho:*(:u:*:u: + :v:*:v:) 125 | :rhou: = :rho:*:u: 126 | :rhov: = :rho:*:v: 127 | :cs: = sqrt( :p: / :rho: * :gamma: ) 128 | :dt: = dt.courant(:u:,:v:,:w:,:cs:)*.1 129 | [:gx:,:gy:,:gz:] = grad( :phi: ) 130 | :gx: = gbar( :gx: ) 131 | :gy: = gbar( :gy: ) 132 | """ 133 | ic = ic.replace('mach',str(mach)) 134 | 135 | # Set the initial conditions 136 | ss.setIC(ic) 137 | 138 | 139 | # Write a time loop 140 | time = 0.0 141 | viz = True 142 | 143 | # Approx a max dt and stopping time 144 | tt = 1.5 # 145 | 146 | # Start time loop 147 | cnt = 1 148 | viz_freq = 25 149 | 150 | wvars = ['p','rho','u','v','phi'] 151 | if not test: 152 | ss.write( wvars ) 153 | CFL = 1.0 154 | dt = ss.variables['dt'].data * CFL * .1 155 | 156 | while tt > time: 157 | 158 | # Update the EOM and get next dt 159 | time = ss.rk4(time,dt) 160 | dt = min(ss.variables['dt'].data * CFL, 1.1*dt) 161 | dt = min(dt, (tt - time) ) 162 | 163 | # Print some output 164 | ss.iprint("%s -- %s --- %f" % (cnt,time,dt) ) 165 | cnt += 1 166 | if viz and (not test): 167 | if (cnt%viz_freq == 1): 168 | ss.write( wvars ) 169 | 170 | 171 | # Curve test. Write file and print its name at the end 172 | if test: 173 | x = ss.mesh.coords[0].data 174 | xx = ss.PyMPI.zbar( x ) 175 | pvar = 'p' 176 | v = ss.PyMPI.zbar( ss.variables[pvar].data ) 177 | ny = ss.PyMPI.ny 178 | v1d = v[:,int(ny/2)] 179 | x1d = xx[:,int(ny/2)] 180 | fname = testName + '.dat' 181 | numpy.savetxt( fname , (x1d,v1d) ) 182 | print(fname) 183 | -------------------------------------------------------------------------------- /examples/eulerSpherical.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function 2 | import re 3 | import sys 4 | import time 5 | import numpy 6 | import matplotlib.pyplot as plt 7 | from matplotlib import cm 8 | 9 | from pyranda import pyrandaSim, pyrandaBC, pyrandaTimestep 10 | from pyranda.pyrandaMesh import defaultMeshOptions 11 | 12 | 13 | # Try to get args for testing 14 | try: 15 | Npts = int(sys.argv[1]) 16 | except: 17 | Npts = 128 18 | 19 | try: 20 | test = bool(int(sys.argv[2])) 21 | except: 22 | test = False 23 | 24 | try: 25 | testName = (sys.argv[3]) 26 | except: 27 | testName = None 28 | 29 | 30 | ## Define a mesh 31 | L = numpy.pi * 2.0 32 | dx2 = L / (Npts-1) / 2.0 33 | gamma = 1.4 34 | spike_angle = numpy.pi / 16 35 | problem = '2dSpherical' 36 | mesh_options = defaultMeshOptions() 37 | mesh_options['coordsys'] = 2 38 | mesh_options['periodic'] = numpy.array([False, False, True]) 39 | #mesh_options['dim'] = 2 40 | mesh_options['x1'] = [ L/10 , numpy.pi/2-.01 , 0*numpy.pi - spike_angle ] 41 | mesh_options['xn'] = [ L , numpy.pi/2+.01 , 0*numpy.pi + spike_angle ] 42 | mesh_options['nn'] = [ Npts*4, 1 , Npts] 43 | #mesh_options['symmetric'][0][0] = True 44 | 45 | # Initialize a simulation object on a mesh 46 | ss = pyrandaSim(problem,mesh_options) 47 | ss.addPackage( pyrandaBC(ss) ) 48 | ss.addPackage( pyrandaTimestep(ss) ) 49 | 50 | # Define the equations of motion 51 | eom =""" 52 | # Primary Equations of motion here 53 | ddt(:rho:) = -:mass: 54 | ddt(:rhou:) = -:xmom: 55 | ddt(:rhow:) = -:zmom: 56 | ddt(:Et:) = -div( (:Et: + :p: - :tau:)*:u:,:v:, (:Et: + :p: - :tau:)*:w: ) 57 | # Conservative filter of the EoM 58 | :rho: = fbar( :rho: ) 59 | :rhou: = fbar( :rhou: ) 60 | :rhow: = fbar( :rhow: ) 61 | :Et: = fbar( :Et: ) 62 | # Update the primatives and enforce the EOS 63 | :u: = :rhou: / :rho: 64 | :w: = :rhow: / :rho: 65 | :p: = ( :Et: - .5*:rho:*(:u:*:u: + :w:*:w:) ) * ( :gamma: - 1.0 ) 66 | # Artificial bulk viscosity (old school way) 67 | :div: = div(:u:,:v:,:w:) 68 | :beta: = gbar(abs(ring(:div:))) * :rho: * 7.0e-2 69 | :tau: = :beta:*:div: 70 | :v: = :v: * 0.0 71 | # Compute divT of momentum 72 | :mass: = div(:rho:*:u: , :v:, :rho:*:w:) 73 | [:fxx:,:fxy:,:fxz:] = [:rhou:*:u: + :p: - :tau:, :v: , :rhou:*:w:] 74 | [:fyx:,:fyy:,:fyz:] = [ :v: , :p:-:tau: , :v: ] 75 | [:fzx:,:fzy:,:fzz:] = [:rhow:*:u:, :v: , :rhow:*:w: + :p: - :tau:] 76 | [:xmom:,:ymom:,:zmom:] = divT(:fxx:,:fxy:,:fxz:,:fyx:,:fyy:,:fyz:,:fzx:,:fzy:,:fzz:) 77 | # Boundary conditions 78 | bc.const(['u'],['x1','xn'],0.0) 79 | # Compute some max time steps 80 | :cs: = sqrt( :p: / :rho: * :gamma: ) 81 | :dt: = dt.courant(:u:,:v:,:w:,:cs:) 82 | """ 83 | 84 | #eom += """# Apply constant BCs 85 | #bc.extrap(['rho','Et'],['x1','xn','z1','zn'],order=1) 86 | #bc.const(['u','w'],['x1','xn','z1','zn'],0.0) 87 | #""" 88 | 89 | print(eom) 90 | 91 | # Add the EOM to the solver 92 | ss.EOM(eom) 93 | 94 | 95 | # Initialize variables 96 | ic = "rad = sqrt( (meshx-pi)**2 + (meshy-0.0)**2 ) " 97 | 98 | 99 | # SOD shock tube in 1d and 2d 100 | ic += """ 101 | :gamma: = 1.4 102 | wgt = .5*(1.0-tanh( (rad-pi/16.0)/.1) ) # [0,1] 103 | :Et: = 1.0/(:gamma:-1.0) * (wgt*.9 + .1) 104 | #:Et: = gbar( where( rad < pi/2.0, 1.0/(:gamma:-1.0) , .1 /(:gamma:-1.0) ) ) 105 | #:rho: = gbar( where( rad < pi/2.0, 1.0 , .125 ) ) 106 | :rho: = 1.0*wgt + (1.0-wgt)*.125 107 | """ 108 | 109 | # Set the initial conditions 110 | ss.setIC(ic) 111 | 112 | # Write a time loop 113 | time = 0.0 114 | viz = True 115 | 116 | # Approx a max dt and stopping time 117 | v = 1.0 118 | dt_max = v / ss.mesh.nn[0] * 0.05 119 | tt = 2.0 120 | 121 | if test: 122 | tt = 0.1 123 | 124 | 125 | # Start time loop 126 | dt = dt_max 127 | cnt = 1 128 | viz_freq = 50 129 | viz_per = tt/20.0 130 | viz_time = 0.0 131 | 132 | pvar = 'rho' 133 | 134 | 135 | 136 | while tt > time: 137 | 138 | # Update the EOM and get next dt 139 | time = ss.rk4(time,dt) 140 | dt = min(dt_max, ss.var('dt').data ) 141 | dt = min(dt , (tt - time) ) 142 | 143 | # Print some output 144 | ss.iprint("%s -- %s" % (cnt,time) ) 145 | cnt += 1 146 | if viz and (not test): 147 | #if (cnt%viz_freq == 0) and True: 148 | if ( time >= viz_time ): 149 | viz_time += viz_per 150 | ss.write() 151 | ss.plot.figure(1) 152 | ss.plot.clf() 153 | #ss.plot.plot(pvar,slice2d="j=0;k=50",style='k.-') 154 | #ss.plot.figure(2) 155 | #ss.plot.clf() 156 | #ss.plot.contourf(pvar,64) 157 | 158 | y1d = ss.var(pvar)[:,0,:].mean(axis=1) 159 | x1d = ss.mesh.coordsNative[0][:,0,int(Npts/2)] 160 | if ss.PyMPI.master: 161 | plt.plot(x1d,y1d,'k-o') 162 | 163 | ss.plot.figure(2) 164 | ss.plot.clf() 165 | x2d = ss.var('meshx')[:,0,:] 166 | y2d = ss.var('meshy')[:,0,:] 167 | v2d = ss.var(pvar)[:,0,:] 168 | if ss.PyMPI.master: 169 | plt.contourf(x2d,y2d,v2d,64) 170 | plt.axis('equal') 171 | plt.pause(.1) 172 | 173 | 174 | 175 | if test: 176 | p = ss.var(pvar)[:,0,:].mean(axis=1) 177 | x = ss.mesh.coordsNative[0][:,0,int(Npts/2)] 178 | fname = testName + '.dat' 179 | numpy.savetxt( fname , (x,p) ) 180 | print(fname) 181 | 182 | -------------------------------------------------------------------------------- /pyranda/parcop/makefile: -------------------------------------------------------------------------------- 1 | #=================================================================================================== 2 | # Copyright (c) 2018, Lawrence Livemore National Security, LLC. 3 | # Produced at the Lawrence Livermore National Laboratory. 4 | # 5 | # LLNL-CODE-749864 6 | # This file is part of pyranda 7 | # For details about use and distribution, please read: pyranda/LICENSE 8 | # 9 | # Written by: Britton J. Olson, olson45@llnl.gov 10 | #=================================================================================================== 11 | # 12 | 13 | # return the first argument if it's defined, otherwise return the second argument 14 | # usage: $(call use-if,a,b) 15 | use-if = $(if $1,$1,$2) 16 | 17 | chaos_5_x86_64_ib.gnu.mpif90 = /collab/usr/gapps/python/build/spack/opt/spack/chaos_5_x86_64_ib/gcc-4.4.7/mpich-3.0.4-evwtvwqv5i2ujysfnivcdtrnppmpcsrg/bin/mpif90 18 | chaos_5_x86_64_ib.intel.mpif90 = /usr/local/tools/mvapich2-intel-2.2/bin/mpif90 19 | chaos_5_x86_64_ib.python = /usr/local/bin/python 20 | 21 | toss_3_x86_64_ib.gnu.mpif90 = /usr/tce/packages/mvapich2/mvapich2-2.2-gcc-6.1.0/bin/mpif90 22 | toss_3_x86_64_ib.intel.mpif90 = /usr/tce/packages/mvapich2/mvapich2-2.2-intel-16.0.3/bin/mpif90 23 | toss_3_x86_64_ib.clang.mpif90 = /usr/tce/packages/mvapich2/mvapich2-2.2-clang-4.0.0/bin/mpif90 24 | toss_3_x86_64_ib.pgi.mpif90 = /usr/tce/packages/mvapich2/mvapich2-2.2-pgi-18.1/bin/mpif90 25 | toss_3_x86_64_ib.python = /usr/tce/bin/python 26 | 27 | blueos_3_ppc64le_ib.ibm.mpif90 = /usr/tce/packages/spectrum-mpi/spectrum-mpi-2018.04.27-xl-beta-2018.06.01/bin/mpif90 28 | blueos_3_ppc64le_ib.gnu.mpif90 = /usr/tcetmp/bin/mpigfortran 29 | blueos_3_ppc64le_ib.python = /usr/tcetmp/bin/python 30 | 31 | gopt = -funroll-loops -Ofast 32 | gnu.fflags = -fPIC -ffree-form -ffree-line-length-0 -fbackslash $(gopt) -std=legacy 33 | intel.fflags = -fPIC -O3 -cpp 34 | # it's likely that mpiclang is using gfortran 35 | clang.fflags = $(gnu.fflags) 36 | ibm.linkflags = -qoffload -W@,-v -qsmp=omp -qinfo=omperrtrace 37 | ibm.fflags = -fPIC -qxlf2003=polymorphic $(ibm.linkflags) -qsuffix=cpp=f90:f=f90 38 | ibm.lopts = -qmkshrobj 39 | pgi.fflags = -fPIC 40 | 41 | sys_type = $(call use-if,$(SYS_TYPE),$(shell uname)) 42 | python ?= $(call use-if,$($(compiler).$(sys_type).python),$(shell which python)) 43 | mpif90 ?= $(call use-if,$($(sys_type).$(compiler).mpif90),$(shell which mpif90)) 44 | fcomp ?= $(call use-if,$(compiler),$(shell ./vendor.sh $(mpif90))) 45 | mpicc ?= $(dir $(mpif90))mpicc 46 | ccomp ?= $(call use-if,$(compiler),$(shell ./vendor.sh $(mpicc))) 47 | # make sure we use this python's f2py unless the user wants something else 48 | f2py ?= $(python) -c 'import numpy.f2py; numpy.f2py.main()' 49 | fflags ?= $($(fcomp).fflags) 50 | lopts ?= $(call use-if,$($(fcomp).lopts),-shared) 51 | 52 | # 53 | # Python and numpy directories for use when building the f2py wrapped module 54 | # 55 | python.Iflags = -I$(shell $(python) -c "from sysconfig import get_config_var; print(get_config_var('INCLUDEPY'))") 56 | python.libdir = $(shell $(python) -c "from sysconfig import get_config_var; print(get_config_var('LIBDIR'))") 57 | python.version = $(shell $(python) -c "from sysconfig import get_config_var; print(get_config_var('VERSION'))") 58 | python.abiflag = $(shell $(python) -c "import sys; print(getattr(sys,'abiflags',''))") 59 | #python.Lflags = -L$(python.libdir) -Wl,-R$(python.libdir) 60 | python.Lflags = -L$(python.libdir) -Wl,-rpath $(python.libdir) 61 | python.lflags = -lpython$(python.version)$(python.abiflag) 62 | 63 | numpy.dir = $(shell $(python) -c "import numpy; print(numpy.__path__[0])") 64 | numpy.Iflags = -I$(numpy.dir)/core/include 65 | f2py.dir = $(numpy.dir)/f2py/src 66 | f2py.Iflags = -I$(f2py.dir) 67 | 68 | # 69 | # source order is important because of mod file dependencies 70 | # 71 | source = blockmath.o ompsync.o stencils.o nrtype.o nrutil.o patch.o pentadiagonal.o \ 72 | comm.o compact_basetype.o compact_d1.o compact_r3.o compact_r4.o \ 73 | compact.o mesh.o objects.o compact_operators.o operators.o 74 | 75 | vpath %.c $(f2py.dir) 76 | 77 | .PHONY: clean info 78 | 79 | %.o: %.f90 80 | $(mpif90) $(fflags) -c $< 81 | 82 | %.o: %.c 83 | $(mpicc) -fPIC $(python.Iflags) $(numpy.Iflags) $(f2py.Iflags) -c $^ 84 | 85 | all: parcop.so test_pent 86 | 87 | libparcop.a: $(source) 88 | @ar -ur $@ $(source) 89 | 90 | # 91 | # TODO: is the '2' in of the f2pywrappers2.f90 the major python version? 92 | # 93 | # f2py ended up not working well with certain compilers (ibm, pgi) so 94 | # instead build the wrapper components using above flags 95 | # 96 | parcopmodule.c parcop-f2pywrappers2.f90: libparcop.a parcop.o 97 | @$(f2py) --lower --wrap-functions -m parcop parcop.f90 --verbose 98 | 99 | parcop.so: parcopmodule.o fortranobject.o parcop-f2pywrappers2.o 100 | $(mpif90) $(lopts) $(python.Lflags) \ 101 | parcopmodule.o fortranobject.o parcop.o parcop-f2pywrappers2.o libparcop.a $(python.lflags) \ 102 | -o parcop.so 103 | 104 | test_pent: libparcop.a parcop.o test_pent.o 105 | $(mpif90) test_pent.o parcop.o libparcop.a -o $@ 106 | 107 | miniApp: libparcop.a parcop.o miniApp.o 108 | $(mpif90) miniApp.o parcop.o libparcop.a -o $@ 109 | 110 | miniAppGPU: libparcop.a parcop.o miniApp.o 111 | $(mpif90) $(ibm.linkflags) miniApp.o parcop.o libparcop.a -o $@ 112 | 113 | info: 114 | @echo "sys_type: $(sys_type)" 115 | @echo "python: $(python)" 116 | @echo "mpif90: $(mpif90)" 117 | @echo "mpicc: $(mpicc)" 118 | @echo "f2py: $(f2py)" 119 | @echo "fflags: $(fflags)" 120 | @echo "fcompiler: $(fcomp)" 121 | @echo "ccompiler: $(ccomp)" 122 | 123 | clean: 124 | rm -rf *.o *.mod test_pent *.so *.pyf *.pyc libparcop.a *.dSYM parcopmodule.c parcop-f2pywrappers*.f90 125 | -------------------------------------------------------------------------------- /examples/TBL3D.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import numpy 3 | from pyranda import pyrandaSim, pyrandaBC, pyrandaTimestep, pyrandaIBM, pyrandaTBL 4 | 5 | 6 | 7 | ## Define a mesh 8 | problem = 'myTBL' 9 | 10 | nx = 100 11 | ny = 64 12 | nz = 16 13 | 14 | Lx = 10.0 15 | Ly = 5.0 16 | Lz = 0.5 17 | 18 | 19 | problem = 'myTBL_long' 20 | nx = 400 21 | ny = 128 22 | nz = 32 23 | 24 | Lx = 25.0 25 | Ly = 10.0 26 | Lz = 1.0 27 | 28 | 29 | 30 | delBL = 2.5 31 | Re = 1.0e12 32 | mach = 0.3 33 | p0 = 1.0 34 | rho0 = .1 35 | gamma = 1.4 36 | u0 = mach * numpy.sqrt( p0 / rho0 * gamma) 37 | mu0 = u0 * delBL * rho0 / Re 38 | 39 | #Re = u0 del0 den / ( mu0 40 | def wallMesh(i,j,k): 41 | 42 | alpha = numpy.log( Ly + 1.0 ) / ( float(ny) - 1.0 ) 43 | 44 | x = Lx * ( float(i) / (nx-1) ) 45 | y = numpy.exp( alpha* float( j ) ) - 1.0 46 | z = Lz * ( float(k) / (nz-1) ) 47 | return x,y,z 48 | 49 | mesh_options = {} 50 | mesh_options['coordsys'] = 3 51 | mesh_options['function'] = wallMesh 52 | mesh_options['periodic'] = numpy.array([False, False, True]) 53 | mesh_options['periodicGrid'] = True # (grid linked to flow periodicity) 54 | mesh_options['x1'] = [ 0.0 , 0.0 , 0.0 ] 55 | mesh_options['xn'] = [ Lx , Ly , Lz ] 56 | mesh_options['nn'] = [ nx , ny , nz ] 57 | 58 | 59 | # Initialize a simulation object on a mesh 60 | ss = pyrandaSim(problem,mesh_options) 61 | ss.addPackage( pyrandaBC(ss) ) 62 | ss.addPackage( pyrandaTimestep(ss) ) 63 | 64 | TBL = pyrandaTBL(ss) 65 | # Incoming BL data 66 | BL_data = {} 67 | BL_data['umean'] = 'TBL_data/umean.dat' 68 | BL_data['uumean'] = 'TBL_data/uumean.dat' 69 | BL_data['vvmean'] = 'TBL_data/vvmean.dat' 70 | BL_data['wwmean'] = 'TBL_data/wwmean.dat' 71 | BL_data['uvmean'] = 'TBL_data/uvmean.dat' 72 | # Setup the 2d filters ( 6 total. Inner (u,v,w) and outer (u,v,w) ) 73 | TBL.UIx = 10 74 | TBL.UIy = [ 10, 15 ] 75 | TBL.UIz = 10 76 | 77 | TBL.VIx = 8 78 | TBL.VIy = [ 15, 20 ] 79 | TBL.VIz = 10 80 | 81 | TBL.WIx = 8 82 | TBL.WIy = [ 10, 20 ] 83 | TBL.WIz = 10 84 | 85 | TBL.Nbuff = 20 * 2 86 | TBL.BL_data = BL_data 87 | TBL.U_in = u0 / 18.93 # Max val data / mean flow u0 in pyranda 88 | TBL.del_BL = 2.5 / 100.0 # Data val at BL / physical location 89 | TBL.tauX = 2.5 90 | ss.addPackage( TBL ) 91 | 92 | 93 | # Import 3D Euler-curvilinear 94 | #from equation_library import euler_3d 95 | from equation_library import euler_3d_dir as euler_3d 96 | 97 | euler_3d += """ 98 | bc.const(['u','v','w'],['y1'],0.0) 99 | bc.extrap(['rho','p'],['y1','yn']) 100 | bc.extrap(['rho','p'],['xn']) 101 | bc.const(['rho'],['x1'],rho0) 102 | bc.const(['p'],['x1'],p0) 103 | TBL.inflow() 104 | # Sponge outflow 105 | :wgt: = ( 1.0 + tanh( (meshx-Lx*(1.0-0.025))/ (.025*Lx) ) ) * 0.5 106 | :u: = :u:*(1-:wgt:) + gbarx(:u:)*:wgt: 107 | :v: = :v:*(1-:wgt:) + gbarx(:v:)*:wgt: 108 | :w: = :w:*(1-:wgt:) + gbarx(:w:)*:wgt: 109 | bc.extrap(['u','v','w'],['xn']) 110 | :rhou: = :rho:*:u: 111 | :rhov: = :rho:*:v: 112 | :rhow: = :rho:*:w: 113 | :Et: = .5*:rho:*(:u:*:u: + :v:*:v: + :w:*:w:) + :p: / ( :gamma: - 1.0 ) 114 | """ 115 | euler_3d = euler_3d.replace('mu0',str(mu0)) 116 | euler_3d = euler_3d.replace('rho0',str(rho0)) 117 | euler_3d = euler_3d.replace('p0',str(p0)) 118 | euler_3d = euler_3d.replace('Lx',str(Lx)) 119 | 120 | # Add the EOM to the solver 121 | ss.EOM(euler_3d) 122 | 123 | # Initialize variables 124 | ic = """ 125 | :gamma: = gam0 126 | #:R: = 1.0 127 | #:cp: = :R: / (1.0 - 1.0/:gamma: ) 128 | #:cv: = :cp: - :R: 129 | :rho: = 3d(rho0) 130 | :p: = 3d(p0) 131 | :u: = mach * sqrt( :p: / :rho: * :gamma:) 132 | bc.const( ['u','v','w'] , ['y1'] , 0.0 ) 133 | :u: = gbar( gbar( :u: ) ) 134 | :Et: = :p:/( :gamma: - 1.0 ) + .5*:rho:*(:u:*:u: + :v:*:v: + :w:*:w:) 135 | :rhou: = :rho:*:u: 136 | :rhov: = :rho:*:v: 137 | :rhov: = :rho:*:w: 138 | :cs: = sqrt( :p: / :rho: * :gamma: ) 139 | :dt: = dt.courant(:u:,:v:,:w:,:cs:) 140 | TBL.setup() 141 | # Mesh metrics from parcops 142 | :dAdx: = meshVar('dAx') 143 | :dAdy: = meshVar('dAy') 144 | :dAdz: = meshVar('dAz') 145 | :dBdx: = meshVar('dBx') 146 | :dBdy: = meshVar('dBy') 147 | :dBdz: = meshVar('dBz') 148 | :dCdx: = meshVar('dCx') 149 | :dCdy: = meshVar('dCy') 150 | :dCdz: = meshVar('dCz') 151 | :detJ: = meshVar('dtJ') 152 | :dA: = meshVar('d1') 153 | :dB: = meshVar('d2') 154 | :dC: = meshVar('d3') 155 | """ 156 | ic = ic.replace('mach',str(mach)) 157 | ic = ic.replace('rho0',str(rho0)) 158 | ic = ic.replace('p0',str(p0)) 159 | ic = ic.replace('gam0',str(gamma)) 160 | ic = ic.replace('BL_data',str(BL_data)) 161 | 162 | # Set the initial conditions 163 | ss.setIC(ic) 164 | 165 | 166 | # Write a time loop 167 | time = 0.0 168 | viz = True 169 | 170 | # Approx a max dt and stopping time 171 | tt = 60.0 # 172 | 173 | # Start time loop 174 | viz_freq = 250 175 | pvar = 'umag' 176 | 177 | #TBL.DFinflow() 178 | wvars = ['p','rho','u','v','w','Et','cs'] 179 | 180 | #for i in range(1,nx): 181 | # ss.var('u').data[i,:,:] = ss.var('u').data[0,:,:] 182 | 183 | 184 | TBL.DFinflow() 185 | 186 | ss.parse(":rhou: = :rho:*:u:") 187 | ss.write(wvars) 188 | 189 | if 1: 190 | CFL = 0.9 191 | dt = ss.var('dt').data * CFL 192 | while tt > time: 193 | 194 | # Update the EOM and get next dt 195 | time = ss.rk4(time,dt) 196 | #time = time + dt 197 | #ss.time = time*1.0 198 | #TBL.DFinflow() 199 | #ss.cycle += 1 200 | dt = min( ss.variables['dt'].data * CFL, dt) 201 | dt = min(dt, (tt - time) ) 202 | dtCFL = ss.variables['dtC'].data 203 | 204 | # Print some output 205 | ss.iprint("%s -- %.6e --- %.4e --- CFL: %.4e" % (ss.cycle,time,dt,dt/dtCFL) ) 206 | 207 | if (ss.cycle%viz_freq == 0) : 208 | ss.write(wvars) 209 | ss.writeRestart() 210 | 211 | 212 | 213 | 214 | #ss.writeRestart() 215 | 216 | 217 | -------------------------------------------------------------------------------- /examples/TaylorGreen.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function 2 | import re 3 | import sys 4 | import time 5 | import numpy 6 | import matplotlib.pyplot as plt 7 | from matplotlib import cm 8 | 9 | from pyranda import pyrandaSim, pyrandaTimestep 10 | 11 | 12 | # Try to get args for testing 13 | try: 14 | Npts = int(sys.argv[1]) 15 | except: 16 | Npts = 32 17 | 18 | try: 19 | test = bool(int(sys.argv[2])) 20 | except: 21 | test = False 22 | 23 | problem = 'TGvortex' 24 | 25 | ## Define a mesh 26 | #Npts = 32 27 | imesh = """ 28 | xdom = (0.0, 2*pi*FF, Npts, periodic=True) 29 | ydom = (0.0, 2*pi*FF, Npts, periodic=True) 30 | zdom = (0.0, 2*pi*FF, Npts, periodic=True) 31 | """.replace('Npts',str(Npts)).replace('pi',str(numpy.pi)).replace('FF',str( float(Npts-1)/Npts ) ) 32 | 33 | 34 | # Initialize a simulation object on a mesh 35 | ss = pyrandaSim(problem,imesh) 36 | ss.addPackage( pyrandaTimestep(ss) ) 37 | 38 | 39 | # Define the equations of motion 40 | eom =""" 41 | # Primary Equations of motion here 42 | ddt(:rho:) = -ddx(:rho:*:u:) - ddy(:rho:*:v:) - ddz(:rho:*:w:) 43 | ddt(:rhou:) = -ddx(:rhou:*:u: - :tauxx:) - ddy(:rhou:*:v: - :tauxy:) - ddz(:rhou:*:w: - :tauxz:) 44 | ddt(:rhov:) = -ddx(:rhov:*:u: - :tauxy:) - ddy(:rhov:*:v: - :tauyy:) - ddz(:rhov:*:w: - :tauyz:) 45 | ddt(:rhow:) = -ddx(:rhow:*:u: - :tauxz:) - ddy(:rhow:*:v: - :tauyz:) - ddz(:rhow:*:w: - :tauzz:) 46 | ddt(:Et:) = -ddx( (:Et: - :tauxx:)*:u: - :tauxy:*:v: - :tauxz:*:w: ) - ddy( (:Et: - :tauyy:)*:v: -:tauxy:*:u: - :tauyz:*:w:) - ddz( (:Et: - :tauzz:)*:w: - :tauxz:*:u: - :tauyz:*:v: ) 47 | # Conservative filter of the EoM 48 | :rho: = fbar( :rho: ) 49 | :rhou: = fbar( :rhou: ) 50 | :rhov: = fbar( :rhov: ) 51 | :rhow: = fbar( :rhow: ) 52 | :Et: = fbar( :Et: ) 53 | # Update the primatives and enforce the EOS 54 | :u: = :rhou: / :rho: 55 | :v: = :rhov: / :rho: 56 | :w: = :rhow: / :rho: 57 | :p: = ( :Et: - .5*:rho:*(:u:*:u: + :v:*:v: + :w:*:w:) ) * ( :gamma: - 1.0 ) 58 | # Artificial bulk viscosity 59 | :ux: = ddx(:u:) 60 | :vy: = ddy(:v:) 61 | :wz: = ddz(:w:) 62 | :div: = :ux: + :vy: + :wz: 63 | # Remaining cross derivatives 64 | :uy: = ddy(:u:) 65 | :uz: = ddz(:u:) 66 | :vx: = ddx(:v:) 67 | :vz: = ddz(:v:) 68 | :wy: = ddy(:w:) 69 | :wx: = ddx(:w:) 70 | :enst: = sqrt( (:uy:-:vx:)**2 + (:uz: - :wx:)**2 + (:vz:-:wy:)**2 ) 71 | :tke: = :rho:*(:u:*:u: + :v:*:v: + :w:*:w:) 72 | :S: = sqrt( :ux:*:ux: + :vy:*:vy: + :wz:*:wz: + .5*((:uy:+:vx:)**2 + (:uz: + :wx:)**2 + (:vz:+:wy:)**2) ) 73 | :mu: = gbar( abs(ring(:S: )) ) * :rho: * 1.0e-4 74 | :beta: = gbar( abs(ring(:div:)) * :rho: ) * 7.0e-3 75 | :taudia: = (:beta:-2./3.*:mu:) *:div: - :p: 76 | :tauxx: = 2.0*:mu:*:ux: + :taudia: 77 | :tauyy: = 2.0*:mu:*:vy: + :taudia: 78 | :tauzz: = 2.0*:mu:*:wz: + :taudia: 79 | :tauxy: = :mu:*(:uy:+:vx:) 80 | :tauxz: = :mu:*(:uz:+:wx:) 81 | :tauyz: = :mu:*(:vz:+:wz:) 82 | :cs: = sqrt( :p: / :rho: * :gamma: ) 83 | :dt: = dt.courant(:u:,:v:,:w:,:cs:)*1.0 84 | :dt: = numpy.minimum(:dt:,0.2 * dt.diff(:beta:,:rho:)) 85 | :dt: = numpy.minimum(:dt:,0.2 * dt.diff(:mu:,:rho:)) 86 | """ 87 | 88 | # Add the EOM to the solver 89 | ss.EOM(eom) 90 | 91 | 92 | # Initialize variables 93 | ic = """ 94 | :gamma: = 1.4 95 | u0 = 1.0 96 | p0 = 100.0 97 | rho0 = 1.0 98 | L = 1.0 99 | :u: = u0*sin(meshx/L)*cos(meshy/L)*cos(meshz/L) 100 | :v: = -u0*cos(meshx/L)*sin(meshy/L)*cos(meshz/L) 101 | :w: = 0.0*:u: 102 | :p: = p0 + rho0/16.0*( ( cos(2.*meshx/L) + cos(2.*meshy/L) ) * ( cos(2.*meshz/L) + 2.0 ) - 2.0 ) 103 | :rho: = rho0 + 0.0*:u: 104 | :rhou: = :rho:*:u: 105 | :rhov: = :rho:*:v: 106 | :rhow: = :rho:*:w: 107 | :Et: = :p: / (:gamma:-1.0) + 0.5*:rho:*(:u:*:u: + :v:*:v: + :w:*:w:) 108 | :cs: = sqrt( :p: / :rho: * :gamma: ) 109 | :tke: = :rho:*(:u:*:u: + :v:*:v: + :w:*:w:) 110 | :dt: = dt.courant(:u:,:v:,:w:,:cs:) 111 | """ 112 | 113 | # Set the initial conditions 114 | ss.setIC(ic) 115 | 116 | # Length scale for art. viscosity 117 | # Initialize variables 118 | x = ss.mesh.coords[0].data 119 | y = ss.mesh.coords[1].data 120 | z = ss.mesh.coords[2].data 121 | 122 | # Write a time loop 123 | time = 0.0 124 | viz = True 125 | 126 | # Start time loop 127 | CFL = 0.5 128 | dt = ss.variables['dt'].data * CFL 129 | 130 | # Viz 131 | cnt = 1 132 | viz_freq = 20 133 | pvar = 'u' 134 | 135 | tke0 = ss.var('tke').sum() 136 | enst0 = ss.var('enst').sum() 137 | TKE = [] 138 | ENST = [] 139 | TIME = [] 140 | 141 | tstop = 25.0 142 | if test: 143 | tstop = .1 144 | 145 | while time < tstop: 146 | 147 | # Update the EOM and get next dt 148 | time = ss.rk4(time,dt) 149 | dt = ss.variables['dt'].data * CFL 150 | 151 | # Print some output 152 | tke = ss.var('tke').sum()/tke0 153 | enst = ss.var('enst').sum()/enst0 154 | 155 | TIME.append(time) 156 | ENST.append(enst) 157 | TKE.append(tke) 158 | 159 | 160 | ss.iprint("%s -- %s --- TKE: %s " % (cnt,time,tke) ) 161 | cnt += 1 162 | if viz: 163 | 164 | # Write viz data and plot 165 | if (cnt%viz_freq == 0): 166 | ss.write() 167 | 168 | ss.plot.figure(2) 169 | ss.plot.clf() 170 | ss.plot.contourf(pvar ,64 , slice3d='k=16', cmap=cm.jet) 171 | ss.plot.title(pvar+',Time=%f' % time) 172 | 173 | 174 | 175 | data = ss.PyMPI.subsum3xz( ss.mesh.coords[1].data ) / (Npts*Npts) 176 | if ss.PyMPI.master: 177 | print(data) 178 | 179 | if test: 180 | print(enst) 181 | else: 182 | if (ss.PyMPI.master): 183 | plt.figure() 184 | plt.plot(TIME,TKE,'k--') 185 | plt.plot(TIME,ENST,'b--') 186 | plt.show() 187 | 188 | -------------------------------------------------------------------------------- /examples/KH.py: -------------------------------------------------------------------------------- 1 | # KH.py - Kelvin-Helmholtz paper of McNally et. al. 2 | from pyranda import * 3 | import sys,numpy 4 | 5 | problem = "KelvinHelmholtz" 6 | 7 | # Some global problem definitions 8 | gamma = 5./3. # Ratio of specific heats 9 | p0 = 2.5 # Constant initial pressure value 10 | u1 = 0.5 # Forward velocity 11 | u2 = -0.5 # Backward velocity 12 | rho1 = 1.0 # Density of light 13 | rho2 = 2.0 # Density of heavy 14 | L = 0.025 # Length scale of transition 15 | Vmean = 0.0 # Convective offset 16 | tFinal = 1.5 # Final time 17 | R = 1.0 # Gas constant 18 | test = False # Run in test mode? 19 | 20 | cp = R / (1.0 - 1.0/gamma ) 21 | cv = cp - R 22 | 23 | # Grid size 24 | Npts = 128 25 | 26 | dt_max = 1.0 #e-3 27 | 28 | try: 29 | Npts = int(sys.argv[1]) 30 | except: 31 | pass 32 | 33 | try: 34 | Vmean = float(sys.argv[2]) * 1.0 / tFinal 35 | except: 36 | pass 37 | 38 | try: 39 | problem += sys.argv[3] 40 | except: 41 | pass 42 | try: 43 | test = bool(int(sys.argv[4])) 44 | except: 45 | pass 46 | 47 | 48 | # Make a mesh and a pyrandaSim object 49 | mesh = """ 50 | xdom = (0.0, len, Npts, periodic=True) 51 | ydom = (0.0, len, Npts, periodic=True) 52 | """.replace('Npts',str(Npts)).replace('len',str(1.0*(Npts-1.0)/Npts)) 53 | 54 | ss = pyrandaSim(problem,mesh) 55 | 56 | # Add "Timestep" package for dt.* functions 57 | ss.addPackage( pyrandaTimestep(ss) ) 58 | 59 | # Define the 2D Euler equations with AFLES terms 60 | 61 | eom =""" 62 | # Primary Equations of motion here 63 | ddt(:rho:) = -ddx(:rho:*:u:) - ddy(:rho:*:v:) 64 | ddt(:rhou:) = -ddx(:rhou:*:u: - :tauxx:) - ddy(:rhou:*:v: - :tauxy:) 65 | ddt(:rhov:) = -ddx(:rhov:*:u: - :tauxy:) - ddy(:rhov:*:v: - :tauyy:) 66 | ddt(:Et:) = -ddx( (:Et: - :tauxx:)*:u: - :tauxy:*:v: - :tx:*:kappa: ) - ddy( (:Et: - :tauyy:)*:v: -:tauxy:*:u:- :ty:*:kappa: ) 67 | # Conservative filter of the EoM 68 | :rho: = fbar( :rho: ) 69 | :rhou: = fbar( :rhou: ) 70 | :rhov: = fbar( :rhov: ) 71 | :Et: = fbar( :Et: ) 72 | # Update the primatives and enforce the EOS 73 | :u: = :rhou: / :rho: 74 | :v: = :rhov: / :rho: 75 | :p: = ( :Et: - .5*:rho:*(:u:*:u: + :v:*:v:) ) * ( gamma - 1.0 ) 76 | # Artificial bulk viscosity 77 | :ux: = ddx(:u:) 78 | :vy: = ddy(:v:) 79 | :div: = :ux: + :vy: 80 | # Remaining cross derivatives 81 | :uy: = ddy(:u:) 82 | :vx: = ddx(:v:) 83 | :enst: = sqrt( (:uy:-:vx:)**2 ) 84 | :tke: = :rho:*(:u:*:u: + :v:*:v: ) 85 | :S: = sqrt( :ux:*:ux: + :vy:*:vy: + .5*((:uy:+:vx:)**2 ) ) 86 | :mu: = gbar( abs(ring(:S: )) ) * :rho: * 1.0e-4 87 | :beta: = gbar( abs(ring(:div:)) * :rho: ) * 7.0e-3 88 | :taudia: = (:beta:-2./3.*:mu:) *:div: - :p: 89 | :tauxx: = 2.0*:mu:*:ux: + :taudia: 90 | :tauyy: = 2.0*:mu:*:vy: + :taudia: 91 | :tauxy: = :mu:*(:uy:+:vx:) 92 | :T: = :p: / (:rho: * R0 ) 93 | [:tx:,:ty:,:tz:] = grad(:T:) 94 | :kappa: = gbar( ring(:T:)* :rho:*cv/(:T: * :dt: ) ) * 1.0e-3 95 | :cs: = sqrt( :p: / :rho: * gamma ) 96 | :dt: = dt.courant(:u:,:v:,:w:,:cs:)*1.0 97 | :dt: = numpy.minimum(:dt:,0.2 * dt.diff(:beta:,:rho:)) 98 | :dt: = numpy.minimum(:dt:,0.2 * dt.diff(:mu:,:rho:)) 99 | """ 100 | 101 | # Add the EOM to the solver 102 | ss.EOM(eom,{'gamma':gamma,'R0':R,'cv':cv}) 103 | 104 | 105 | # Define the initial conditions here 106 | ic = """ 107 | Um = (u1-u2)/2.0 108 | rhoM = (rho1-rho2)/2.0 109 | :u: = u1-Um*exp( -(meshy-.75)/L) 110 | :u: = where( meshy < .75, u2+Um*exp( -(.75-meshy)/L) , :u: ) 111 | :u: = where( meshy < .50, u2+Um*exp( (-meshy+.25)/L) , :u: ) 112 | :u: = where( meshy < .25, u1-Um*exp( (meshy-.25)/L) , :u: ) 113 | :v: = 0.01*sin( 4.*pi*meshx ) + Vmean 114 | :rho: = rho1-rhoM*exp( -(meshy-.75)/L) 115 | :rho: = where( meshy < .75, rho2+rhoM*exp( -(.75-meshy)/L) , :rho: ) 116 | :rho: = where( meshy < .50, rho2+rhoM*exp( (-meshy+.25)/L) , :rho: ) 117 | :rho: = where( meshy < .25, rho1-rhoM*exp( (meshy-.25)/L) , :rho: ) 118 | :p: += p0 119 | # Form conserved variables 120 | :Et: = :p:/( gamma - 1.0 ) + .5*:rho:*(:u:*:u: + :v:*:v:) 121 | :rhou: = :rho:*:u: 122 | :rhov: = :rho:*:v: 123 | :cs: = sqrt( :p: / :rho: * gamma ) 124 | :dt: = dt.courant(:u:,:v:,:w:,:cs:)*.1 125 | """ 126 | icDict = {'gamma':gamma,'u1':u1,'u2':u2,'p0':p0, 127 | 'rho1':rho1,'rho2':rho2,'L':L,'Vmean':Vmean} 128 | 129 | ss.setIC(ic,icDict) 130 | 131 | 132 | # Main time stepping loop 133 | viz_freq = .1 134 | 135 | # Variables to write to viz. 136 | wvars = ['rho','u','v','p','beta','kappa','mu','enst'] 137 | 138 | 139 | time = 0.0 140 | dt = ss.var('dt').data 141 | viz_dump = viz_freq 142 | 143 | if not test: 144 | ss.write( wvars ) 145 | 146 | while tFinal > time: 147 | 148 | time = ss.rk4(time,dt) 149 | dt = min(ss.variables['dt'].data , 1.1*dt) 150 | dt = min( dt_max, dt) 151 | dt = min(dt, (tFinal - time) ) 152 | 153 | # Simulation heart-beat 154 | ss.iprint("Cycle: %5d --- Time: %10.4e --- deltat: %10.4e" % (ss.cycle,time,dt) ) 155 | 156 | # Constant time 157 | if (time > viz_dump) and (not test): 158 | ss.write( wvars ) 159 | viz_dump += viz_freq 160 | 161 | #ss.plot.figure(1) 162 | #ss.plot.clf() 163 | #ss.plot.contourf('rho',64 ) 164 | if not test: 165 | ss.write( wvars ) 166 | ss.plot.figure(1) 167 | ss.plot.clf() 168 | ss.plot.contourf('rho',64 ) 169 | 170 | # Curve test. Write file and print its name at the end 171 | if test: 172 | ny = ss.PyMPI.ny 173 | x = ss.mesh.coords[0] 174 | rho = ss.variables['rho'] 175 | islice = "j=%s;k=0" % (int(3*ny/4)) 176 | x1d = ss.plot.getLine( x.data , islice ) 177 | v1d = ss.plot.getLine( rho.data, islice ) 178 | fname = problem + '.dat' 179 | numpy.savetxt( fname , (x1d,v1d) ) 180 | print(fname) 181 | -------------------------------------------------------------------------------- /pyranda/pyrandaUtils.py: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | # Copyright (c) 2018, Lawrence Livemore National Security, LLC. 3 | # Produced at the Lawrence Livermore National Laboratory. 4 | # 5 | # LLNL-CODE-749864 6 | # This file is part of pyranda 7 | # For details about use and distribution, please read: pyranda/LICENSE 8 | # 9 | # Written by: Britton J. Olson, olson45@llnl.gov 10 | ################################################################################ 11 | import re 12 | import subprocess 13 | import signal 14 | import time 15 | 16 | 17 | scalar_key = ":" 18 | vector_key = [':[',']:'] 19 | tensor_key = [':{','}:'] 20 | 21 | 22 | def fortran3d(form,sMap,latex=False): 23 | """ 24 | Formula translator: Take in a string and return 25 | the mapped string for evaluation 26 | """ 27 | keyS = scalar_key 28 | 29 | # Eliminate useless whitespace 30 | form = form.replace(' ','').strip() 31 | 32 | var_data = 'self.variables["%s"].data' 33 | # Latex parser 34 | if latex: 35 | var_data = '%s' 36 | 37 | 38 | # Fill in form with variable data arrays (scalars) 39 | varList = findVar(form,'scalar') 40 | for ivar in varList: 41 | kvar = '%s%s%s' % (keyS,ivar,keyS) 42 | if kvar not in sMap: 43 | sMap[kvar] = var_data%ivar 44 | 45 | keyT = vector_key[:] 46 | vecList = findVar(form,'vector') 47 | for ivar in vecList: 48 | kvar = '%s%s%s' % (keyT[0],ivar,keyT[1]) 49 | if kvar not in sMap: 50 | sMap[kvar] = var_data%ivar 51 | 52 | 53 | # 54 | for mvar in sMap: 55 | if "#arg#" in mvar: 56 | eMap = sMap[mvar] 57 | prefix = mvar.split('(')[0] 58 | try: 59 | args = re.findall(prefix+'\(.*?\)',form)[0].replace('(','').replace(')','').replace(prefix,'') 60 | form = form.replace(mvar.replace('#arg#',args) ,eMap.replace("#arg#",args)) 61 | except: 62 | pass 63 | else: 64 | form = form.replace(mvar,sMap[mvar]) 65 | # 66 | return form 67 | 68 | def splitLines(aLongString): 69 | """ 70 | Take in a long string and split into lines for parsing 71 | """ 72 | ics = aLongString 73 | ic_lines = filter(None,ics.split('\n')) 74 | ic_lines = [el.replace(' ','') for el in ic_lines ] # Comments work 75 | ic_lines = filter(None,ic_lines) 76 | ic_lines = [el for el in ic_lines if el.strip()[0] != '#'] # Comments work 77 | return ic_lines 78 | 79 | 80 | 81 | 82 | def findVar(string,kind,unique=True): 83 | """ 84 | Return a list of the variable names to replace 85 | """ 86 | if kind == "scalar": 87 | varStr = findVarScalar(string) 88 | elif kind == "vector": 89 | varStr = findVarVecTen(string,vector_key) 90 | elif kind == "tensor": 91 | varStr = findVarVecTen(string,tensor_key) 92 | else: 93 | varStr = [] 94 | # 95 | # list(set makes LHS our of order 96 | if unique: 97 | varStr = list(set(varStr)) 98 | 99 | return varStr 100 | 101 | 102 | def findVarScalar(string): 103 | 104 | keyS = scalar_key 105 | 106 | # Tags to exclude for scalars 107 | excluded_chars = "[]{}#%*@" 108 | 109 | svars = re.findall('%s.*?%s'%(keyS,keyS),string) 110 | nvars = [] 111 | for nv in svars: 112 | skip = False 113 | for ev in excluded_chars: 114 | if ev in nv: 115 | skip = True 116 | if not skip: 117 | nvars.append(nv.replace(keyS,'')) 118 | return nvars 119 | 120 | 121 | def findVarVecTen(string,keyS): 122 | 123 | 124 | # Fix for regEq escapes 125 | exMap = {} 126 | exMap['['] = '\[' 127 | exMap[']'] = '\]' 128 | exMap['{'] = '\{' 129 | exMap['}'] = '\}' 130 | 131 | keyL = keyS[0] 132 | keyR = keyS[1] 133 | for em in exMap: 134 | keyL = keyL.replace(em,exMap[em]) 135 | keyR = keyR.replace(em,exMap[em]) 136 | 137 | svars = re.findall('%s.*?%s'%(keyL,keyR),string) 138 | for isv in range(len(svars)): 139 | svars[isv] = svars[isv].replace(keyS[0],'') 140 | svars[isv] = svars[isv].replace(keyS[1],'') 141 | return svars 142 | 143 | 144 | 145 | 146 | def code(): 147 | # From patorjk.com (Doom) 148 | return """ 149 | _ 150 | | | 151 | _ __ _ _ _ __ __ _ _ __ __| | __ _ 152 | | '_ \| | | | '__/ _` | '_ \ / _` |/ _` | 153 | | |_) | |_| | | | (_| | | | | (_| | (_| | 154 | | .__/ \__, |_| \__,_|_| |_|\__,_|\__,_| 155 | | | __/ | 156 | |_| |___/ 157 | """ 158 | 159 | def version(): 160 | return "Version 1.0" 161 | 162 | 163 | 164 | def icopyright(): 165 | return """ 166 | Copyright (c) 2020 Lawrence Livermore National Laboratory (LLNL-CODE-749864) 167 | All rights reserved. 168 | For details about use and distribution, please read: pyranda/LICENSE 169 | """ 170 | 171 | 172 | def runCMD(command_arg_list): 173 | output = subprocess.Popen(command_arg_list, 174 | stdout=subprocess.PIPE).communicate()[0] 175 | return output 176 | 177 | def test_request(arg=None): 178 | """Your http request.""" 179 | time.sleep(2) 180 | return arg 181 | 182 | class Timeout(): 183 | """Timeout class using ALARM signal.""" 184 | class Timeout(Exception): 185 | pass 186 | 187 | def __init__(self, sec): 188 | self.sec = sec 189 | 190 | def __enter__(self): 191 | signal.signal(signal.SIGALRM, self.raise_timeout) 192 | signal.alarm(self.sec) 193 | 194 | def __exit__(self, *args): 195 | signal.alarm(0) # disable alarm 196 | 197 | def raise_timeout(self, *args): 198 | raise Timeout.Timeout() 199 | 200 | -------------------------------------------------------------------------------- /examples/interface.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import time 3 | import numpy 4 | import matplotlib.pyplot as plt 5 | 6 | from pyranda import pyrandaSim, pyrandaIBM 7 | 8 | 9 | # Try to get args 10 | try: 11 | Npts = int(sys.argv[1]) 12 | except: 13 | Npts = 128 14 | 15 | #import pdb 16 | #pdb.set_trace() 17 | try: 18 | test = bool(int(sys.argv[2])) 19 | except: 20 | test = False 21 | 22 | try: 23 | diffusive = bool(int(sys.argv[3])) 24 | except: 25 | diffusive = False 26 | 27 | 28 | #print sys.argv[2] 29 | 30 | ## Define a mesh 31 | L = numpy.pi * 2.0 32 | Lp = L * (Npts-1.0) / Npts 33 | twoD = False 34 | 35 | mesh_options = {} 36 | mesh_options['coordsys'] = 0 37 | mesh_options['periodic'] = numpy.array([twoD, twoD, True]) 38 | mesh_options['dim'] = 3 39 | mesh_options['x1'] = [ 0.0 , 0.0 , 0.0 ] 40 | mesh_options['xn'] = [ Lp , Lp , Lp ] 41 | mesh_options['nn'] = [ Npts, 1 , 1 ] 42 | if twoD: 43 | mesh_options['nn'] = [ Npts, Npts , 1 ] 44 | 45 | 46 | # Initialize a simulation object on a mesh 47 | ss = pyrandaSim('advection',mesh_options) 48 | ss.addPackage( pyrandaIBM(ss) ) 49 | 50 | 51 | # Define the equations of motion 52 | eom =""" 53 | # Primary Equations of motion here 54 | ddt(:rho:) = -ddx(:rho:*:u: - :tau:) - ddy(:rho:*:v: - :tau:) 55 | ddt(:rhoA:) = -ddx(:rhoA:*:uA: - :tauA:) -ddy(:rhoA:*:vA: - :tauA:) 56 | ddt(:phi:) = - :gx: * :u1: - :gy: * :v1: #- sign(:phi:)*(:mgp:-1.0) 57 | # Conservative filter of the EoM 58 | :rho: = fbar( :rho: ) 59 | :rhoA: = fbar( :rhoA: ) 60 | # Update the primatives and enforce the EOS 61 | :dr: = ddx(:rho:) 62 | :drA: = ddx(:rhoA:) 63 | :tau: = 5.0e-7*gbar(abs(lap(lap(:rho:)))) * :dx4: * :u: * :dr: * :dx: 64 | :tauA: = 5.0e-7*gbar(abs(lap(lap(:rhoA:)))) * :dx4: * :uA: * :drA: * :dx: 65 | # Immersed boundary method used for MM levelset 66 | [:gx:,:gy:,:gz:] = grad( :phi: ) 67 | :mgp: = sqrt( :gx:**2 + :gy:**2 + :gz:**2 ) 68 | #[:u:,:v:,:w:] = ibmV( [:u:,:v:,0.0], :phi:, [:gx:,:gy:,:gz:], [:u1:,0.0,0.0] ) 69 | :rho: = ibmS( :rho: , :phi:, [:gx:,:gy:,:gz:] ) 70 | #[:uA:,:v:,:w:] = ibmV( [:uA:,:v:,0.0], -:phi:, [-:gx:,-:gy:,-:gz:], [:u1:,0.0,0.0] ) 71 | :rhoA: = ibmS( :rhoA: , -:phi:, [-:gx:,-:gy:,-:gz:] ) 72 | :uT: = where( :phi: > 0.0, :u:, :uA:) 73 | :rhoB: = where( :phi: > 0.0, :rho:, :rhoA:) 74 | :rhoT: = where( abs(:phi:/:dx:*2.0) > 1.0, :rhoB:, .5*(:phi:/:dx:*2.0 + 1.0)*(:rho:-:rhoA:) + (:rhoA:) ) 75 | """ 76 | ss.EOM(eom) 77 | 78 | #:umag: = numpy.sqrt(:u:*:u: + :v:*:v:) 79 | 80 | # Initialize variables 81 | x = ss.mesh.coords[0].data 82 | y = ss.mesh.coords[1].data 83 | z = ss.mesh.coords[2].data 84 | 85 | dx = (x[1,0,0] - x[0,0,0]) 86 | 87 | rad = numpy.sqrt( (x-numpy.pi)**2 ) # + (y-numpy.pi)**2 ) #+ (z-numpy.pi)**2 ) 88 | 89 | diffAmp = 1.0 90 | if diffusive: 91 | diffAmp = 1.0e6 92 | 93 | 94 | if not twoD: 95 | ss.variables['rho'].data += ss.gfilter( numpy.where( x < numpy.pi*.25, diffAmp, 1.0 ) ) 96 | ss.variables['rhoA'].data += 1.0e6 * (1.0 + .1*numpy.exp(-(x-numpy.pi*1.5)**2/.01) ) 97 | ss.variables['phi'].data = 3.14159 - x 98 | ss.variables['uA'].data += 1.0 99 | ss.variables['u'].data += 1.0 100 | ss.variables['u1'].data += 1.0 101 | 102 | else: 103 | ss.variables['rho'].data += 1.0 * numpy.sin( 4.0*x ) 104 | ss.variables['rhoA'].data += 1.0e6 * numpy.cos( 4.*y ) 105 | r = numpy.sqrt( (x-numpy.pi)**2 + (y-numpy.pi)**2 ) 106 | ss.variables['phi'].data = ss.gfilter( numpy.minimum( r - numpy.pi/4.0 , 10.0*dx ) ) 107 | ss.variables['vA'].data += 1.0 108 | ss.variables['v'].data += 1.0 109 | ss.variables['v1'].data += 1.0 110 | ss.variables['uA'].data += 1.0 111 | ss.variables['u'].data += 1.0 112 | ss.variables['u1'].data += 1.0 113 | 114 | 115 | # Try circles 116 | 117 | 118 | # Init momenta 119 | ss.variables['u1'].data = 1.0 120 | 121 | ss.variables['dx'].data += (x[1,0,0] - x[0,0,0]) 122 | ss.variables['dx4'].data += (x[1,0,0] - x[0,0,0])**4 123 | 124 | 125 | ss.updateVars() 126 | 127 | time = 0.0 128 | viz = True 129 | 130 | v = 1.0 131 | 132 | dt_max = v / ss.mesh.nn[0] * L * .25 133 | 134 | tt = L/v * 1.0 #dt_max 135 | if not twoD: 136 | tt *= .2 137 | 138 | 139 | xx = ss.PyMPI.zbar( x ) 140 | yy = ss.PyMPI.zbar( y ) 141 | 142 | dt = dt_max 143 | cnt = 1 144 | 145 | v2 = ss.PyMPI.zbar( ss.variables['rhoT'].data ) 146 | #plt.figure(2) 147 | #plt.plot( xx[:,0],v2[:,0] ) 148 | #plt.contourf( xx,yy,v2 ,64 ) 149 | #plt.pause(.001) 150 | #import pdb 151 | #pdb.set_trace() 152 | 153 | viz_freq = 5 154 | if twoD: 155 | viz_freq = 5 156 | 157 | while tt > time: 158 | 159 | time = ss.rk4(time,dt) 160 | dt = min(dt_max, (tt - time) ) 161 | 162 | # Poor man's boundary condition 163 | if not twoD: 164 | ss.variables['rho'].data[0,:,:] = diffAmp 165 | 166 | ss.iprint("%s -- %s" % (cnt,time) ) 167 | cnt += 1 168 | if viz and (not test): 169 | v1 = ss.PyMPI.zbar( ss.variables['rhoA'].data ) 170 | v2 = ss.PyMPI.zbar( ss.variables['rhoT'].data ) 171 | v = ss.PyMPI.zbar( ss.variables['rho'].data ) 172 | vA = ss.PyMPI.zbar( ss.variables['rhoA'].data ) 173 | if ss.PyMPI.master and (cnt%viz_freq == 0) and True: 174 | plt.figure(1) 175 | plt.clf() 176 | plt.plot(xx[:,0],v2[:,0] ,'k.-') 177 | #plt.plot(xx[:,0],v[:,0] ,'r.-') 178 | #plt.plot(xx[:,0],vA[:,0] ,'b.-') 179 | plt.pause(.001) 180 | if twoD: 181 | plt.figure(2) 182 | plt.clf() 183 | plt.contourf( xx,yy,v2 , 8 ) 184 | plt.contour( xx,yy,v2 , 1 ) 185 | plt.pause(.001) 186 | 187 | #import pdb 188 | #pdb.set_trace() 189 | 190 | 191 | v2 = ss.PyMPI.zbar( ss.variables['rhoT'].data ) 192 | error = numpy.min( v2[int(Npts/2):,0] ) 193 | ss.iprint( error ) 194 | -------------------------------------------------------------------------------- /examples/3Dadvect.py: -------------------------------------------------------------------------------- 1 | import re 2 | import sys 3 | import time 4 | import numpy 5 | import matplotlib.pyplot as plt 6 | from matplotlib import cm 7 | 8 | from pyranda import pyrandaSim, pyrandaBC, pyrandaTimestep 9 | 10 | 11 | 12 | 13 | 14 | problem = '3D Advection' 15 | 16 | ## Define a mesh 17 | Npts = 32 18 | imesh = """ 19 | xdom = (0.0, 2*pi*FF, Npts, periodic=True) 20 | ydom = (0.0, 2*pi*FF, Npts, periodic=True) 21 | zdom = (0.0, 2*pi*FF, Npts, periodic=True) 22 | """.replace('Npts',str(Npts)).replace('pi',str(numpy.pi)).replace('FF',str( float(Npts-1)/Npts ) ) 23 | 24 | 25 | # Initialize a simulation object on a mesh 26 | ss = pyrandaSim(problem,imesh) 27 | ss.addPackage( pyrandaTimestep(ss) ) 28 | 29 | 30 | # Define the equations of motion 31 | eom =""" 32 | # Primary Equations of motion here 33 | ddt(:rho:) = -ddx(:rho:*:u:) - ddy(:rho:*:v:) - ddz(:rho:*:w:) 34 | ddt(:rhou:) = -ddx(:rhou:*:u: + :p: - :tauxx:) - ddy(:rhou:*:v: - :tauxy:) - ddz(:rhou:*:w: - :tauxz:) 35 | ddt(:rhov:) = -ddx(:rhov:*:u: - :tauxy:) - ddy(:rhov:*:v: + :p: - :tauyy:) - ddz(:rhov:*:w: - :tauyz:) 36 | ddt(:rhow:) = -ddx(:rhow:*:u: - :tauxz:) - ddy(:rhow:*:v: - :tauyz:) - ddz(:rhow:*:w: + :p: - :tauzz:) 37 | ddt(:Et:) = -ddx( (:Et: - :tauxx:)*:u: - :tauxy:*:v: - :tauxz:*:w: ) - ddy( (:Et: - :tauyy:)*:v: -:tauxy:*:u: - :tauyz:*:w:) - ddz( (:Et: - :tauzz:)*:w: - :tauxz:*:u: - :tauyz:*:v: ) 38 | # Conservative filter of the EoM 39 | :rho: = fbar( :rho: ) 40 | :rhou: = fbar( :rhou: ) 41 | :rhov: = fbar( :rhov: ) 42 | :rhow: = fbar( :rhow: ) 43 | :Et: = fbar( :Et: ) 44 | # Update the primatives and enforce the EOS 45 | :u: = :rhou: / :rho: 46 | :v: = :rhov: / :rho: 47 | :w: = :rhow: / :rho: 48 | :p: = ( :Et: - .5*:rho:*(:u:*:u: + :v:*:v: + :w:*:w:) ) * ( :gamma: - 1.0 ) 49 | # Artificial bulk viscosity 50 | :ux: = ddx(:u:) 51 | :vy: = ddy(:v:) 52 | :wz: = ddz(:w:) 53 | :div: = :ux: + :vy: + :wz: 54 | # Remaining cross derivatives 55 | :uy: = ddy(:u:) 56 | :uz: = ddz(:u:) 57 | :vx: = ddx(:v:) 58 | :vz: = ddz(:v:) 59 | :wy: = ddy(:w:) 60 | :wx: = ddx(:w:) 61 | :enst: = sqrt( (:uy:-:vx:)**2 + (:uz: - :wx:)**2 + (:vz:-:wy:)**2 ) 62 | :tke: = :rho:*(:u:*:u: + :v:*:v: + :w:*:w:) 63 | :S: = sqrt( :ux:*:ux: + :vy:*:vy: + :wz:*:wz: + .5*((:uy:+:vx:)**2 + (:uz: + :wx:)**2 + (:vz:+:wy:)**2) ) 64 | :mu: = gbar( abs(ring(:S: )) ) * :rho: * 0.0e-4 65 | :beta: = gbar( abs(ring(:div:)) * :rho: ) * 0.0e-4 66 | :taudia: = (:beta:-2./3.*:mu:) *:div: 67 | :tauxx: = 2.0*:mu:*:ux: + :taudia: - :p: 68 | :tauyy: = 2.0*:mu:*:vy: + :taudia: - :p: 69 | :tauzz: = 2.0*:mu:*:wz: + :taudia: - :p: 70 | :tauxy: = :mu:*(:uy:+:vx:) + :taudia: 71 | :tauxz: = :mu:*(:uz:+:wx:) + :taudia: 72 | :tauyz: = :mu:*(:vz:+:wz:) + :taudia: 73 | :cs: = sqrt( :p: / :rho: * :gamma: ) 74 | :dt: = dt.courant(:u:,:v:,:w:,:cs:)*.5 75 | :dt: = numpy.minimum(:dt:,0.2 * dt.diff(:beta:,:rho:)) 76 | :dt: = numpy.minimum(:dt:,0.2 * dt.diff(:mu:,:rho:)) 77 | """ 78 | 79 | # Add the EOM to the solver 80 | ss.EOM(eom) 81 | 82 | 83 | # Initialize variables 84 | ic = """ 85 | :gamma: = 1.4 86 | u0 = 1.0 87 | p0 = 1.0 88 | rho0 = 1.0 89 | L = 1.0 90 | rad = sqrt( (meshx-pi)**2 + (meshy-pi)**2 + (meshz-pi)**2 ) 91 | :w: += u0 92 | :p: += p0 93 | :rho: += rho0*(1.0+ .01* (1.0+tanh( -(rad-.5)/(.5) )) ) 94 | :rhou: = :rho:*:u: 95 | :rhov: = :rho:*:v: 96 | :rhow: = :rho:*:w: 97 | :Et: = :p: / (:gamma:-1.0) + 0.5*:rho:*(:u:*:u: + :v:*:v: + :w:*:w:) 98 | :cs: = sqrt( :p: / :rho: * :gamma: ) 99 | :tke: = :rho:*(:u:*:u: + :v:*:v: + :w:*:w:) 100 | :dt: = dt.courant(:u:,:v:,:w:,:cs:) 101 | """ 102 | 103 | # Set the initial conditions 104 | ss.setIC(ic) 105 | 106 | # Length scale for art. viscosity 107 | # Initialize variables 108 | x = ss.mesh.coords[0].data 109 | y = ss.mesh.coords[1].data 110 | z = ss.mesh.coords[2].data 111 | 112 | 113 | # Write a time loop 114 | time = 0.0 115 | viz = True 116 | 117 | # Approx a max dt and stopping time 118 | 119 | 120 | # Mesh for viz on master 121 | xx = ss.PyMPI.zbar( x ) / Npts 122 | yy = ss.PyMPI.zbar( y ) / Npts 123 | #xx = x[:,:,16] / Npts 124 | #yy = y[:,:,16] / Npts 125 | ny = ss.PyMPI.ny 126 | 127 | # Start time loop 128 | CFL = 0.5 129 | dt = ss.variables['dt'].data * CFL 130 | 131 | # Viz 132 | cnt = 1 133 | viz_freq = 10 134 | pvar = 'rho' 135 | 136 | tke0 = ss.var('tke').sum() 137 | enst0 = ss.var('enst').sum() 138 | TKE = [] 139 | ENST = [] 140 | TIME = [] 141 | 142 | 143 | f1 = numpy.sin( x ) 144 | ddx1 = numpy.cos( x ) 145 | ddx2 = ss.ddx( f1 ) 146 | f2 = ss.gfilter( f1 ) 147 | 148 | error = ( ddx1 - ddx2 ) 149 | Ferror = ( f1 - f2 ) 150 | 151 | 152 | e1d = ss.PyMPI.zbar( error )[:,0] / Npts 153 | f1d = ss.PyMPI.zbar( Ferror )[:,0] / Npts 154 | x1d = ss.PyMPI.zbar( x )[:,0] / Npts 155 | if (ss.PyMPI.master): 156 | plt.figure() 157 | plt.plot( x1d, e1d ,'b') 158 | plt.plot( x1d, f1d , 'k' ) 159 | 160 | while time < 10.0: 161 | 162 | # Update the EOM and get next dt 163 | time = ss.rk4(time,dt) 164 | dt = ss.variables['dt'].data * CFL 165 | 166 | # Print some output 167 | tke = ss.var('tke').sum()/tke0 168 | enst = ss.var('enst').sum()/enst0 169 | 170 | TIME.append(time) 171 | ENST.append(enst) 172 | TKE.append(tke) 173 | 174 | 175 | ss.iprint("%s -- %s --- TKE: %s " % (cnt,time,tke) ) 176 | cnt += 1 177 | if viz: 178 | 179 | dd = numpy.where( z == 0.0, 1.0, 0.0 ) 180 | v = ss.PyMPI.zbar( dd*ss.variables[pvar].data ) 181 | #v = ss.variables[pvar].data[:,:,16] 182 | if (ss.PyMPI.master and (cnt%viz_freq == 0)) and True: 183 | plt.figure(2) 184 | plt.clf() 185 | plt.contourf( xx,yy,v ,64 , cmap=cm.jet) 186 | plt.title(pvar) 187 | plt.pause(.001) 188 | 189 | 190 | 191 | if (ss.PyMPI.master): 192 | plt.figure() 193 | plt.plot(TIME,TKE,'k--') 194 | plt.plot(TIME,ENST,'b--') 195 | plt.show() 196 | 197 | -------------------------------------------------------------------------------- /tests/baselines/euler-2d-128.dat: -------------------------------------------------------------------------------- 1 | 0.000000000000000000e+00 4.908738521234051744e-02 9.817477042468103487e-02 1.472621556370215523e-01 1.963495408493620697e-01 2.454369260617025594e-01 2.945243112740431046e-01 3.436116964863835666e-01 3.926990816987241395e-01 4.417864669110646014e-01 4.908738521234051744e-01 5.399612373357456363e-01 5.890486225480862092e-01 6.381360077604266712e-01 6.872233929727672441e-01 7.363107781851077061e-01 7.853981633974482790e-01 8.344855486097887409e-01 8.835729338221293139e-01 9.326603190344697758e-01 9.817477042468102377e-01 1.030835089459150922e+00 1.079922474671491495e+00 1.129009859883832068e+00 1.178097245096172418e+00 1.227184630308512991e+00 1.276272015520853564e+00 1.325359400733194137e+00 1.374446785945534488e+00 1.423534171157875061e+00 1.472621556370215634e+00 1.521708941582556207e+00 1.570796326794896558e+00 1.619883712007237131e+00 1.668971097219577704e+00 1.718058482431918277e+00 1.767145867644258628e+00 1.816233252856599201e+00 1.865320638068939774e+00 1.914408023281280347e+00 1.963495408493620697e+00 2.012582793705961492e+00 2.061670178918301843e+00 2.110757564130642194e+00 2.159844949342982989e+00 2.208932334555323340e+00 2.258019719767663691e+00 2.307107104980004486e+00 2.356194490192344837e+00 2.405281875404685632e+00 2.454369260617025983e+00 2.503456645829366334e+00 2.552544031041707129e+00 2.601631416254047480e+00 2.650718801466387831e+00 2.699806186678728626e+00 2.748893571891068976e+00 2.797980957103409771e+00 2.847068342315750122e+00 2.896155727528090473e+00 2.945243112740431268e+00 2.994330497952771619e+00 3.043417883165111970e+00 3.092505268377452765e+00 3.141592653589793116e+00 3.190680038802133911e+00 3.239767424014474262e+00 3.288854809226814613e+00 3.337942194439155408e+00 3.387029579651495759e+00 3.436116964863836110e+00 3.485204350076176905e+00 3.534291735288517255e+00 3.583379120500858050e+00 3.632466505713198401e+00 3.681553890925538752e+00 3.730641276137879547e+00 3.779728661350219898e+00 3.828816046562560249e+00 3.877903431774901044e+00 3.926990816987241395e+00 3.976078202199581746e+00 4.025165587411922097e+00 4.074252972624263336e+00 4.123340357836603687e+00 4.172427743048944038e+00 4.221515128261284389e+00 4.270602513473624740e+00 4.319689898685965979e+00 4.368777283898306329e+00 4.417864669110646680e+00 4.466952054322987031e+00 4.516039439535327382e+00 4.565126824747668621e+00 4.614214209960008972e+00 4.663301595172349323e+00 4.712388980384689674e+00 4.761476365597030025e+00 4.810563750809370376e+00 4.859651136021711615e+00 4.908738521234051966e+00 4.957825906446392317e+00 5.006913291658732668e+00 5.056000676871073019e+00 5.105088062083414258e+00 5.154175447295754608e+00 5.203262832508094959e+00 5.252350217720435310e+00 5.301437602932775661e+00 5.350524988145116900e+00 5.399612373357457251e+00 5.448699758569797602e+00 5.497787143782137953e+00 5.546874528994478304e+00 5.595961914206818655e+00 5.645049299419159894e+00 5.694136684631500245e+00 5.743224069843840596e+00 5.792311455056180947e+00 5.841398840268521298e+00 5.890486225480862537e+00 5.939573610693202887e+00 5.988660995905543238e+00 6.037748381117883589e+00 6.086835766330223940e+00 6.135923151542565179e+00 6.185010536754905530e+00 6.234097921967245881e+00 2 | 1.244872208748640519e-01 1.250078695179304422e-01 1.255285181609968326e-01 1.285783568487172401e-01 1.363304672169070864e-01 1.622077244318518852e-01 2.048491835045055942e-01 2.331761751813538619e-01 2.376057743277571188e-01 2.364964978560324116e-01 2.352707831566414887e-01 2.334691696240877024e-01 2.322121977837667550e-01 2.301970943416692394e-01 2.296116797786095509e-01 2.278729086505391077e-01 2.252893697733924783e-01 2.390593068652224207e-01 2.757646336437234447e-01 3.115573508008105952e-01 3.283472193363765612e-01 3.358793565616112198e-01 3.419396883467877291e-01 3.427219419853819171e-01 3.401371890413053545e-01 3.378439343808324336e-01 3.358744457491231739e-01 3.353453484800175688e-01 3.354865164593062721e-01 3.348207200676714401e-01 3.366583199717818053e-01 3.446993573810777090e-01 3.584009721022754502e-01 3.757194407451288631e-01 3.954419721941469512e-01 4.169343721007026105e-01 4.399198007141992273e-01 4.642810992746620458e-01 4.899423997967359834e-01 5.168733294495233554e-01 5.450449836317815544e-01 5.744430225356754738e-01 6.050477320373032208e-01 6.368346779236954136e-01 6.697651343440660376e-01 7.037596247147500650e-01 7.386935225433122199e-01 7.743810043672073595e-01 8.105452744662898779e-01 8.467715851780068803e-01 8.824386982280580938e-01 9.165886674220335983e-01 9.477966211258302964e-01 9.737535930080583046e-01 9.912305329862588499e-01 9.988438978855836980e-01 1.000027034234767909e+00 9.998567891945655539e-01 1.000022443672189620e+00 1.000015744168731402e+00 9.999642136421456051e-01 1.000029008986137447e+00 1.000016562465396275e+00 1.000000377899569859e+00 1.000022316548103252e+00 1.000000378100924792e+00 1.000016562165249256e+00 1.000029009319907125e+00 9.999642135519595243e-01 1.000015743949699054e+00 1.000022443484611445e+00 9.998567907961580792e-01 1.000027029539688694e+00 9.988438966878030456e-01 9.912305567152152053e-01 9.737536855988273565e-01 9.477966232137383651e-01 9.165885670569682286e-01 8.824386075616200698e-01 8.467715986531444416e-01 8.105453895606932191e-01 7.743810096204769566e-01 7.386936019077710025e-01 7.037595590361094278e-01 6.697651117893504980e-01 6.368347719894786874e-01 6.050479228379023189e-01 5.744435039407650434e-01 5.450452787437415347e-01 5.168734606898415240e-01 4.899420823139185033e-01 4.642804663738899218e-01 4.399194933606880853e-01 4.169357062571282246e-01 3.954441291788390878e-01 3.757202716884123772e-01 3.583971878746187167e-01 3.446945715594068038e-01 3.366578439600370620e-01 3.348228377275621059e-01 3.354873927691057189e-01 3.353397493313607924e-01 3.358769647987966955e-01 3.378474665065918647e-01 3.401438489729037284e-01 3.427271822054728245e-01 3.419294236670814002e-01 3.358828637851744570e-01 3.283415572646248837e-01 3.115737303293257265e-01 2.757723349362712351e-01 2.390528365710576364e-01 2.252991635611339416e-01 2.278389244565018623e-01 2.296439426099304848e-01 2.301960200664591449e-01 2.321880577661359357e-01 2.335357465605520377e-01 2.352989719061911456e-01 2.362457330436850689e-01 2.371859683763087867e-01 2.333316081009622345e-01 2.053821521429906871e-01 1.627008554532388684e-01 1.359854157809959052e-01 1.283465285346080675e-01 1.253040018153814550e-01 1.222614750961548424e-01 3 | --------------------------------------------------------------------------------