diff --git a/README.md b/README.md index efe063a..cb6f896 100644 --- a/README.md +++ b/README.md @@ -4,10 +4,7 @@ [![Documentation Status](https://readthedocs.org/projects/puma-nasa/badge/?version=latest)](https://puma-nasa.readthedocs.io/en/latest/?badge=latest) [![Anaconda-Server Badge](https://anaconda.org/conda-forge/puma/badges/version.svg)](https://anaconda.org/conda-forge/puma) -[![Anaconda-Server Badge](https://anaconda.org/conda-forge/puma/badges/latest_release_date.svg)](https://anaconda.org/conda-forge/puma) -[![Anaconda-Server Badge](https://anaconda.org/conda-forge/puma/badges/platforms.svg)](https://anaconda.org/conda-forge/puma) -[![Anaconda-Server Badge](https://anaconda.org/conda-forge/puma/badges/license.svg)](https://anaconda.org/conda-forge/puma) -[![Anaconda-Server Badge](https://anaconda.org/conda-forge/puma/badges/downloads.svg)](https://anaconda.org/conda-forge/puma) +[![PyPI version](https://badge.fury.io/py/pumapy.svg)](https://badge.fury.io/py/pumapy) ----- @@ -25,9 +22,9 @@ images obtained from X-ray microtomography or to generate artificial microstruct that mimic real materials. PuMA also provides a module for interactive 3D visualizations. Version 3 includes modules to compute simple morphological properties such as porosity, volume fractions, pore diameter, and specific surface area. Additional capabilities include -the determination of effective thermal and electrical conductivity (including the ability -to simulate local anisotropy), effective diffusivity and tortuosity from the continuum to -the rarefied regime, and techniques to determine local material orientation. +the determination of effective thermal and electrical conductivity (both radiative and solid conduction - +including the ability to simulate local anisotropy for the latter); effective diffusivity and +tortuosity from the continuum to the rarefied regime; techniques to determine the local material orientation, as well as the mechanical properties (elasticity coefficient), and the permeability of a material. Some examples of microstructures that have been run in the past are shown in the pictures below, together with PuMA's software architecture schematic. @@ -37,91 +34,79 @@ together with PuMA's software architecture schematic.

## System requirements -UNIX (Tested on MacOS 10.14.1+, Ubuntu 12.04+, RHEL, and CentOS) +UNIX (tested on MacOS 10.14.1+, Ubuntu 12.04+, RHEL, and CentOS). +On Windows, only the python distribution (pumapy) is available. -Recommended specs: +Indicative recommended specs (varies depending on the material property): - 8 GB of ram for small simulations (5003 or smaller) - 16-32 GB of ram for medium simulations (8003 range) - 32+ GB of ram for large simulations (above 10003) ## Installation -### Installation from source +To install PuMA, a conda distribution must be installed on your machine. +To test whether conda is installed, run "conda" from a terminal to see if the command is recognized. +If not, conda can be installed by following the instructions +[here](https://docs.anaconda.com/anaconda/install/index.html). -Installing PuMA from source is currently the most stable installation method. It has been tested successfully on MacOS systems, and a variety of Linux distributions. In the future, this installation method will be replaced by the conda-forge installation, detailed in the next section. +### Binaries (UNIX and Windows) -The installation is roughly equivalent for MacOS and Linux systems and is broken into three sections: -1. Installation of basic dependencies that may be missing from your system -1. Downloading the repository from Github -1. Installing the software via. Conda - -Step 1 of the installation varies slightly based on the system, so we have split the installation into three separate sections based on the system on which you are installing PuMA. - -#### MacOS Installation - -Open a terminal, navigate the the directory you would like PuMA installed, and execute the following: - - xcode-select --install - git clone https://github.com/nasa/puma.git - cd puma; chmod +x installer.sh; ./installer.sh +Once the conda command is working, all the PuMA components can be installed by executing +the following command in a terminal: -Note: If XCode command line tools are already installed, the first line will result in an error. This error is not a problem, so simply move on to the second line. + conda create -y --name puma conda-forge::puma -#### Debian (Ubuntu) Installation +If only the pumapy python package is needed, it can be installed directly using: -Open a terminal, navigate the the directory you would like PuMA installed, and execute the following: + pip install pumapy - sudo apt-get install git build-essential mesa-common-dev - git clone https://github.com/nasa/puma.git - cd puma; chmod +x installer.sh; ./installer.sh +On UNIX (i.e. Mac or Linux), the conda command installs the PuMA C++ library, pumapy python package and GUI. -#### Fedora (CentOS, RHEL) Installation +On Windows, only the pumapy python package is available, so both commands are equivalent. -Open a terminal, navigate the the directory you would like PuMA installed, and execute the following: +### Build from source (UNIX-only) - sudo yum group install "Development Tools" - sudo yum install git mesa-libGL-devel - git clone https://github.com/nasa/puma.git - cd puma; chmod +x installer.sh; ./installer.sh +This is the recommended installation for developers that need to make modifications to PuMA. +The installation is broken into two sections: +1. Installation of basic dependencies that may be missing from your system +2. Download the repository, build the source code and install the binaries -#### Running PuMA +Step 1 of the installation varies slightly based on the system. +Open a terminal, navigate to the directory you would like PuMA installed, and execute one of the following lines: -After installation, close the terminal and open a new terminal. The PuMA GUI can then be launched by running: + xcode-select --install # run this on MacOS + sudo apt-get install git build-essential mesa-common-dev # Debian (Ubuntu) + sudo yum group install "Development Tools"; sudo yum install git mesa-libGL-devel # Fedora (CentOS, RHEL) - conda activate puma; pumaGUI +Note: If XCode command line tools are already installed, the command will result in an error, which is not a problem. -The [jupyter notebook](https://github.com/nasa/puma/tree/main/tutorial) shows the typical function usage for both PuMA C++ and pumapy. -This can be run directly in Google Colaboratory by following [this link](https://colab.research.google.com/github/nasa/puma/blob/main/tutorial/puma_tutorial.ipynb). +Now that the necessary dependencies have been installed, you can go ahead with Step 2 of the installation: + git clone https://github.com/nasa/puma.git + cd puma; chmod +x installer.sh; ./installer.sh -### Installation from conda-forge +After installation, close the terminal and open a new one. -PuMA can also be directly installed from conda-forge, without the need to clone the repository from gitlab or github. The conda-forge installation currently works on MacOS systems and some linux distributions, but is less tested than the source installation. +### Uninstalling PuMA -In order to install PuMA from conda-forge, a conda distribution must be installed on your machine. To test whether conda is installed, run "conda" from a terminal to see if the command is recognized. Conda can be installed by following the instructions here: https://docs.anaconda.com/anaconda/install/index.html. +To uninstall PuMA and all the installed dependencies, execute the following: -Once conda is installed, PuMA can be installed by executing the following command in a terminal: + conda remove -y --name puma --all - conda create -yn puma conda-forge::puma +## Running PuMA -This installs the PuMA C++ library, pumapy python package and GUI in a conda environment called "puma". PuMA relies on a conda environment in order to manage its software dependencies and environment variables. -It is therefore important to always activate the environment before using any of PuMA's functionalities. - -After installation, the PuMA GUI can be launched by running: - - conda activate puma; pumaGUI - -If the conda-forge installation does not work, try again with the source installation. If issues persist, reference the "common errors" section, then reach out to the authors listed at the bottom of the README. - -### Uninstalling PuMA - -To uninstall PuMA and all the installed dependencies, execute the following - - conda remove --name puma --all +It is therefore important to always activate the environment before using any of PuMA's functionalities. +Once the installation is complete, the PuMA GUI can be launched by running: + conda activate puma + pumaGUI +You can follow the [jupyter notebook tutorial](https://github.com/nasa/puma/tree/main/tutorial), +which shows the typical function usage for both PuMA C++ and pumapy. +This can also be run directly in Google Colaboratory by following +[this link](https://colab.research.google.com/github/nasa/puma/blob/main/tutorial/puma_tutorial.ipynb). ### How to setup PuMA on the NAS cluster: In order to install PuMA on the NASA supercomputing cluster, some modules need to be loaded and environment @@ -159,17 +144,15 @@ If you use PuMA in your research, please use the following BibTeX entries to cit } ``` -See the [publications](https://github.com/nasa/puma/blob/main/publications.md) file for a full list of papers on PuMA and its numerical methods. +See the [publications](https://github.com/nasa/puma/blob/main/publications.md) file for a full list of papers on PuMA +and its numerical methods. ## Common errors and bug reporting This is a list of the common errors encountered during the setup and how to solve them: - If PuMA was partially installed but was interrupted, this can cause errors when trying to install the software. To fix this, first follow the instructions to uninstall puma, and then repeat the installation procedure -- When importing pumapy, if an "MPI_Init_thread" error is displayed, add "export MPICH_INTERFACE_HOSTNAME=localhost" - to ~/.bashrc (Linux) or ~/.bash_profile (Mac) - If an error "make: Warning: File ... has modification time ... s in the future" is displayed, then run "sudo apt install ntp" (or equivalent for your distribution) - If any bugs are found, or if the software crashes for any reason, please open an issue at [this link](https://github.com/nasa/puma/issues) and/or contact either of the authors mentioned below. diff --git a/cpp/src/import/3D_Tiff/import_3DTiff.cpp b/cpp/src/import/3D_Tiff/import_3DTiff.cpp index d1b1eeb..027bbd3 100644 --- a/cpp/src/import/3D_Tiff/import_3DTiff.cpp +++ b/cpp/src/import/3D_Tiff/import_3DTiff.cpp @@ -10,3 +10,23 @@ bool puma::import_3DTiff(Workspace *work, std::string fileName, int xMin, int xM Import_3DTiff_Workspace importer(work,std::move(fileName),xMin,xMax,yMin,yMax,zMin,zMax, numThreads); return importer.import(); } + +std::string puma::path_to_example_file(std::string example_filename){ + std::string path = __FILE__; + std::string filepathname = path.substr(0, path.rfind("\\")); + + std::size_t last_slash = filepathname.find_last_of("/"); + std::string dir = filepathname.substr(0, last_slash); + last_slash = dir.find_last_of("/"); + dir = filepathname.substr(0, last_slash); + last_slash = dir.find_last_of("/"); + dir = filepathname.substr(0, last_slash); + last_slash = dir.find_last_of("/"); + dir = filepathname.substr(0, last_slash); + last_slash = dir.find_last_of("/"); + dir = filepathname.substr(0, last_slash); + + + std::cout << dir << std::endl; + return dir + "/python/pumapy/data/" + example_filename; +} diff --git a/cpp/src/import/3D_Tiff/import_3DTiff.h b/cpp/src/import/3D_Tiff/import_3DTiff.h index ff65f5a..96fabca 100644 --- a/cpp/src/import/3D_Tiff/import_3DTiff.h +++ b/cpp/src/import/3D_Tiff/import_3DTiff.h @@ -5,6 +5,7 @@ #include "import_3DTiff_Workspace.h" #include "workspace.h" #include "tiffio.h" +#include #include @@ -38,6 +39,8 @@ namespace puma { */ template bool import_3DTiff(puma::Matrix *matrix, std::string fileName, int numThreads = 0); + + std::string path_to_example_file(std::string example_filename); } // Import 3D Tiff Matrix Class diff --git a/cpp/test/testsuites/ejelectricalconductivity_test.cpp b/cpp/test/testsuites/ejelectricalconductivity_test.cpp index 2a8929f..496c535 100644 --- a/cpp/test/testsuites/ejelectricalconductivity_test.cpp +++ b/cpp/test/testsuites/ejelectricalconductivity_test.cpp @@ -951,7 +951,7 @@ class EJElectricalConductivity_Test : public SubTest { TestResult result(suiteName, testName, 31, testDescription); puma::Workspace grayWS(1e-6,false); - puma::import_3DTiff(&grayWS,"python/pumapy/data/200_fiberform.tif"); + puma::import_3DTiff(&grayWS,puma::path_to_example_file("200_fiberform.tif")); grayWS.setMaterialID(&grayWS,puma::Cutoff(0,89),0); grayWS.setMaterialID(&grayWS,puma::Cutoff(90,255),1); @@ -990,7 +990,7 @@ class EJElectricalConductivity_Test : public SubTest { TestResult result(suiteName, testName, 32, testDescription); puma::Workspace grayWS(1e-6,false); - puma::import_3DTiff(&grayWS,"python/pumapy/data/200_fiberform.tif"); + puma::import_3DTiff(&grayWS,puma::path_to_example_file("200_fiberform.tif")); puma::Matrix T; std::map matCond; diff --git a/cpp/test/testsuites/ejthermalconductivity_test.cpp b/cpp/test/testsuites/ejthermalconductivity_test.cpp index 38f8327..daa3b34 100644 --- a/cpp/test/testsuites/ejthermalconductivity_test.cpp +++ b/cpp/test/testsuites/ejthermalconductivity_test.cpp @@ -952,7 +952,7 @@ class EJThermalConductivity_Test : public SubTest { TestResult result(suiteName, testName, 31, testDescription); puma::Workspace grayWS(1e-6,false); - puma::import_3DTiff(&grayWS,"python/pumapy/data/200_fiberform.tif"); + puma::import_3DTiff(&grayWS,puma::path_to_example_file("200_fiberform.tif")); grayWS.setMaterialID(&grayWS,puma::Cutoff(0,89),0); grayWS.setMaterialID(&grayWS,puma::Cutoff(90,255),1); @@ -991,7 +991,7 @@ class EJThermalConductivity_Test : public SubTest { TestResult result(suiteName, testName, 32, testDescription); puma::Workspace grayWS(1e-6,false); - puma::import_3DTiff(&grayWS,"python/pumapy/data/200_fiberform.tif"); + puma::import_3DTiff(&grayWS,puma::path_to_example_file("200_fiberform.tif")); puma::Matrix T; std::map matCond; diff --git a/cpp/test/testsuites/export3dtiff_test.cpp b/cpp/test/testsuites/export3dtiff_test.cpp index bb434b5..bef6b6d 100644 --- a/cpp/test/testsuites/export3dtiff_test.cpp +++ b/cpp/test/testsuites/export3dtiff_test.cpp @@ -68,7 +68,7 @@ class Export3DTiff_Test : public SubTest { puma::Workspace grayWS(1e-6,false); - bool success = puma::import_3DTiff(&grayWS,"python/pumapy/data/1300_Spheres.tif",0); + bool success = puma::import_3DTiff(&grayWS,puma::path_to_example_file("1300_Spheres.tif"),0); if(!assertEquals((bool)true,(bool)success, &result)) { return result; } @@ -102,7 +102,7 @@ class Export3DTiff_Test : public SubTest { puma::Workspace grayWS(1e-6,false); - bool success = puma::import_3DTiff(&grayWS,"python/pumapy/data/200_fiberform.tif",0); + bool success = puma::import_3DTiff(&grayWS,puma::path_to_example_file("200_fiberform.tif"),0); if(!assertEquals((bool)true,(bool)success, &result)) { return result; } @@ -123,7 +123,7 @@ class Export3DTiff_Test : public SubTest { TestResult result(suiteName, testName, 4, testDescription); puma::Workspace grayWS(1e-6,false); - bool success = puma::import_3DTiff(&grayWS,"python/pumapy/data/200_fiberform.tif",0); + bool success = puma::import_3DTiff(&grayWS,puma::path_to_example_file("200_fiberform.tif"),0); if(!assertEquals((bool)true,(bool)success, &result)) { return result; } @@ -156,7 +156,7 @@ class Export3DTiff_Test : public SubTest { TestResult result(suiteName, testName, 5, testDescription); puma::Workspace grayWS(1e-6,false); - bool success = puma::import_3DTiff(&grayWS,"python/pumapy/data/200_fiberform.tif",0); + bool success = puma::import_3DTiff(&grayWS,puma::path_to_example_file("200_fiberform.tif"),0); if(!assertEquals((bool)true,(bool)success, &result)) { return result; } @@ -207,7 +207,7 @@ class Export3DTiff_Test : public SubTest { puma::Workspace segWS(1e-6,false); - bool success = puma::import_3DTiff(&segWS,"python/pumapy/data/1300_Spheres.tif",0); + bool success = puma::import_3DTiff(&segWS,puma::path_to_example_file("1300_Spheres.tif"),0); if(!assertEquals((bool)true,(bool)success, &result)) { return result; } @@ -243,7 +243,7 @@ class Export3DTiff_Test : public SubTest { puma::Workspace segWS(1e-6,false); - bool success = puma::import_3DTiff(&segWS,"python/pumapy/data/200_fiberform_segmented.tif",0); + bool success = puma::import_3DTiff(&segWS,puma::path_to_example_file("200_fiberform_segmented.tif"),0); if(!assertEquals((bool)true,(bool)success, &result)) { return result; } @@ -264,7 +264,7 @@ class Export3DTiff_Test : public SubTest { TestResult result(suiteName, testName, 9, testDescription); puma::Workspace segWS(1e-6,false); - bool success = puma::import_3DTiff(&segWS,"python/pumapy/data/200_fiberform_segmented.tif",0); + bool success = puma::import_3DTiff(&segWS,puma::path_to_example_file("200_fiberform_segmented.tif"),0); if(!assertEquals((bool)true,(bool)success, &result)) { return result; } @@ -299,7 +299,7 @@ class Export3DTiff_Test : public SubTest { TestResult result(suiteName, testName, 10, testDescription); puma::Workspace segWS(1e-6,false); - bool success = puma::import_3DTiff(&segWS,"python/pumapy/data/200_fiberform_segmented.tif",0); + bool success = puma::import_3DTiff(&segWS,puma::path_to_example_file("200_fiberform_segmented.tif"),0); if(!assertEquals((bool)true,(bool)success, &result)) { return result; } @@ -338,7 +338,7 @@ class Export3DTiff_Test : public SubTest { puma::Matrix sMatrix; - bool success = puma::import_3DTiff(&sMatrix,"python/pumapy/data/1300_Spheres.tif",0); + bool success = puma::import_3DTiff(&sMatrix,puma::path_to_example_file("1300_Spheres.tif"),0); if(!assertEquals((bool)true,(bool)success, &result)) { return result; } @@ -374,7 +374,7 @@ class Export3DTiff_Test : public SubTest { puma::Matrix sMatrix; - bool success = puma::import_3DTiff(&sMatrix,"python/pumapy/data/200_fiberform.tif",0); + bool success = puma::import_3DTiff(&sMatrix,puma::path_to_example_file("200_fiberform.tif"),0); if(!assertEquals((bool)true,(bool)success, &result)) { return result; } @@ -396,7 +396,7 @@ class Export3DTiff_Test : public SubTest { puma::Matrix sMatrix; - bool success = puma::import_3DTiff(&sMatrix,"python/pumapy/data/200_fiberform.tif",0); + bool success = puma::import_3DTiff(&sMatrix,puma::path_to_example_file("200_fiberform.tif"),0); if(!assertEquals((bool)true,(bool)success, &result)) { return result; } @@ -431,7 +431,7 @@ class Export3DTiff_Test : public SubTest { TestResult result(suiteName, testName, 15, testDescription); puma::Matrix sMatrix; - bool success = puma::import_3DTiff(&sMatrix,"python/pumapy/data/200_fiberform.tif",0); + bool success = puma::import_3DTiff(&sMatrix,puma::path_to_example_file("200_fiberform.tif"),0); if(!assertEquals((bool)true,(bool)success, &result)) { return result; } @@ -471,7 +471,7 @@ class Export3DTiff_Test : public SubTest { puma::Matrix sMatrix; - bool success = puma::import_3DTiff(&sMatrix,"python/pumapy/data/1300_Spheres.tif",0); + bool success = puma::import_3DTiff(&sMatrix,puma::path_to_example_file("1300_Spheres.tif"),0); if(!assertEquals((bool)true,(bool)success, &result)) { return result; } @@ -507,7 +507,7 @@ class Export3DTiff_Test : public SubTest { puma::Matrix sMatrix; - bool success = puma::import_3DTiff(&sMatrix,"python/pumapy/data/200_fiberform.tif",0); + bool success = puma::import_3DTiff(&sMatrix,puma::path_to_example_file("200_fiberform.tif"),0); if(!assertEquals((bool)true,(bool)success, &result)) { return result; } @@ -529,7 +529,7 @@ class Export3DTiff_Test : public SubTest { puma::Matrix sMatrix; - bool success = puma::import_3DTiff(&sMatrix,"python/pumapy/data/200_fiberform.tif",0); + bool success = puma::import_3DTiff(&sMatrix,puma::path_to_example_file("200_fiberform.tif"),0); if(!assertEquals((bool)true,(bool)success, &result)) { return result; } @@ -564,7 +564,7 @@ class Export3DTiff_Test : public SubTest { TestResult result(suiteName, testName, 20, testDescription); puma::Matrix sMatrix; - bool success = puma::import_3DTiff(&sMatrix,"python/pumapy/data/200_fiberform.tif",0); + bool success = puma::import_3DTiff(&sMatrix,puma::path_to_example_file("200_fiberform.tif"),0); if(!assertEquals((bool)true,(bool)success, &result)) { return result; } @@ -604,7 +604,7 @@ class Export3DTiff_Test : public SubTest { puma::Matrix sMatrix; - bool success = puma::import_3DTiff(&sMatrix,"python/pumapy/data/1300_Spheres.tif",0); + bool success = puma::import_3DTiff(&sMatrix,puma::path_to_example_file("1300_Spheres.tif"),0); if(!assertEquals((bool)true,(bool)success, &result)) { return result; } @@ -640,7 +640,7 @@ class Export3DTiff_Test : public SubTest { puma::Matrix sMatrix; - bool success = puma::import_3DTiff(&sMatrix,"python/pumapy/data/200_fiberform.tif",0); + bool success = puma::import_3DTiff(&sMatrix,puma::path_to_example_file("200_fiberform.tif"),0); if(!assertEquals((bool)true,(bool)success, &result)) { return result; } @@ -662,7 +662,7 @@ class Export3DTiff_Test : public SubTest { puma::Matrix sMatrix; - bool success = puma::import_3DTiff(&sMatrix,"python/pumapy/data/200_fiberform.tif",0); + bool success = puma::import_3DTiff(&sMatrix,puma::path_to_example_file("200_fiberform.tif"),0); if(!assertEquals((bool)true,(bool)success, &result)) { return result; } @@ -697,7 +697,7 @@ class Export3DTiff_Test : public SubTest { TestResult result(suiteName, testName, 25, testDescription); puma::Matrix sMatrix; - bool success = puma::import_3DTiff(&sMatrix,"python/pumapy/data/200_fiberform.tif",0); + bool success = puma::import_3DTiff(&sMatrix,puma::path_to_example_file("200_fiberform.tif"),0); if(!assertEquals((bool)true,(bool)success, &result)) { return result; } @@ -737,7 +737,7 @@ class Export3DTiff_Test : public SubTest { puma::Matrix sMatrix; - bool success = puma::import_3DTiff(&sMatrix,"python/pumapy/data/1300_Spheres.tif",0); + bool success = puma::import_3DTiff(&sMatrix,puma::path_to_example_file("1300_Spheres.tif"),0); if(!assertEquals((bool)true,(bool)success, &result)) { return result; } @@ -773,7 +773,7 @@ class Export3DTiff_Test : public SubTest { puma::Matrix sMatrix; - bool success = puma::import_3DTiff(&sMatrix,"python/pumapy/data/200_fiberform.tif",0); + bool success = puma::import_3DTiff(&sMatrix,puma::path_to_example_file("200_fiberform.tif"),0); if(!assertEquals((bool)true,(bool)success, &result)) { return result; } @@ -795,7 +795,7 @@ class Export3DTiff_Test : public SubTest { puma::Matrix sMatrix; - bool success = puma::import_3DTiff(&sMatrix,"python/pumapy/data/200_fiberform.tif",0); + bool success = puma::import_3DTiff(&sMatrix,puma::path_to_example_file("200_fiberform.tif"),0); if(!assertEquals((bool)true,(bool)success, &result)) { return result; } @@ -830,7 +830,7 @@ class Export3DTiff_Test : public SubTest { TestResult result(suiteName, testName, 30, testDescription); puma::Matrix sMatrix; - bool success = puma::import_3DTiff(&sMatrix,"python/pumapy/data/200_fiberform.tif",0); + bool success = puma::import_3DTiff(&sMatrix,puma::path_to_example_file("200_fiberform.tif"),0); if(!assertEquals((bool)true,(bool)success, &result)) { return result; } diff --git a/cpp/test/testsuites/exportstl_test.cpp b/cpp/test/testsuites/exportstl_test.cpp index 3a76a12..92cdb71 100644 --- a/cpp/test/testsuites/exportstl_test.cpp +++ b/cpp/test/testsuites/exportstl_test.cpp @@ -42,7 +42,7 @@ class ExportSTL_Test : public SubTest { TestResult result(suiteName, testName, 2, testDescription); puma::Workspace grayWS(1e-6,false); - puma::import_3DTiff(&grayWS,"python/pumapy/data/200_fiberform.tif",0,50,0,50,0,50,0); + puma::import_3DTiff(&grayWS,puma::path_to_example_file("200_fiberform.tif"),0,50,0,50,0,50,0); std::vector< puma::Triangle > Triangles; puma::isosurface_MarchingCubes(&Triangles,&grayWS,puma::Cutoff(90,255),true,1,false,0); @@ -67,7 +67,7 @@ class ExportSTL_Test : public SubTest { TestResult result(suiteName, testName, 3, testDescription); puma::Workspace grayWS(1e-6,false); - puma::import_3DTiff(&grayWS,"python/pumapy/data/200_fiberform.tif",0); + puma::import_3DTiff(&grayWS,puma::path_to_example_file("200_fiberform.tif"),0); std::vector< puma::Triangle > Triangles; puma::isosurface_MarchingCubes(&Triangles,&grayWS,puma::Cutoff(90,255),true,1,false,0); @@ -92,7 +92,7 @@ class ExportSTL_Test : public SubTest { TestResult result(suiteName, testName, 4, testDescription); puma::Workspace grayWS(1e-6,false); - puma::import_3DTiff(&grayWS,"python/pumapy/data/200_fiberform.tif",0); + puma::import_3DTiff(&grayWS,puma::path_to_example_file("200_fiberform.tif"),0); grayWS.crop(0,49,0,49,0,49); @@ -137,7 +137,7 @@ class ExportSTL_Test : public SubTest { TestResult result(suiteName, testName, 5, testDescription); puma::Workspace grayWS(1e-6,false); - puma::import_3DTiff(&grayWS,"python/pumapy/data/200_fiberform.tif",0); + puma::import_3DTiff(&grayWS,puma::path_to_example_file("200_fiberform.tif"),0); std::vector< puma::Triangle > Triangles; puma::isosurface_MarchingCubes(&Triangles,&grayWS,puma::Cutoff(0,89),true,1,false,0); diff --git a/cpp/test/testsuites/fvanisotropicthermalconductivity_test.cpp b/cpp/test/testsuites/fvanisotropicthermalconductivity_test.cpp index 3bf5d43..f6636c0 100644 --- a/cpp/test/testsuites/fvanisotropicthermalconductivity_test.cpp +++ b/cpp/test/testsuites/fvanisotropicthermalconductivity_test.cpp @@ -2144,7 +2144,7 @@ class FVanisotropicThermalConductivity_Test : public SubTest { TestResult result(suiteName, testName, 57, testDescription); puma::Workspace ws(1e-6, false); - puma::import_3DTiff(&ws,"python/pumapy/data/100_fiberform.tif"); + puma::import_3DTiff(&ws,puma::path_to_example_file("100_fiberform.tif")); // Computing orientations using Structure Tensor (ST) method puma::MatVec3< double> tangents; diff --git a/cpp/test/testsuites/fvelectricalconductivity_test.cpp b/cpp/test/testsuites/fvelectricalconductivity_test.cpp index 55f43fc..5f460a5 100644 --- a/cpp/test/testsuites/fvelectricalconductivity_test.cpp +++ b/cpp/test/testsuites/fvelectricalconductivity_test.cpp @@ -1880,7 +1880,7 @@ class FVElectricalConductivity_Test : public SubTest { TestResult result(suiteName, testName, 61, testDescription); puma::Workspace grayWS(1e-6,false); - puma::import_3DTiff(&grayWS,"python/pumapy/data/200_fiberform.tif"); + puma::import_3DTiff(&grayWS,puma::path_to_example_file("200_fiberform.tif")); grayWS.setMaterialID(&grayWS,puma::Cutoff(0,89),0); grayWS.setMaterialID(&grayWS,puma::Cutoff(90,255),1); @@ -1920,7 +1920,7 @@ class FVElectricalConductivity_Test : public SubTest { TestResult result(suiteName, testName, 62, testDescription); puma::Workspace grayWS(1e-6,false); - puma::import_3DTiff(&grayWS,"python/pumapy/data/200_fiberform.tif",40); + puma::import_3DTiff(&grayWS,puma::path_to_example_file("200_fiberform.tif"),40); puma::Matrix T; std::map matCond; diff --git a/cpp/test/testsuites/fvthermalconductivity_test.cpp b/cpp/test/testsuites/fvthermalconductivity_test.cpp index 8c945f9..1d5b5ef 100644 --- a/cpp/test/testsuites/fvthermalconductivity_test.cpp +++ b/cpp/test/testsuites/fvthermalconductivity_test.cpp @@ -1879,7 +1879,7 @@ class FVThermalConductivity_Test : public SubTest { TestResult result(suiteName, testName, 61, testDescription); puma::Workspace grayWS(1e-6,false); - puma::import_3DTiff(&grayWS,"python/pumapy/data/200_fiberform.tif"); + puma::import_3DTiff(&grayWS,puma::path_to_example_file("200_fiberform.tif")); grayWS.setMaterialID(&grayWS,puma::Cutoff(0,89),0); grayWS.setMaterialID(&grayWS,puma::Cutoff(90,255),1); @@ -1919,7 +1919,7 @@ class FVThermalConductivity_Test : public SubTest { TestResult result(suiteName, testName, 62, testDescription); puma::Workspace grayWS(1e-6,false); - puma::import_3DTiff(&grayWS,"python/pumapy/data/200_fiberform.tif"); + puma::import_3DTiff(&grayWS,puma::path_to_example_file("200_fiberform.tif")); puma::Matrix T; std::map matCond; diff --git a/cpp/test/testsuites/import3dtiff_test.cpp b/cpp/test/testsuites/import3dtiff_test.cpp index 0cc779e..b49d010 100644 --- a/cpp/test/testsuites/import3dtiff_test.cpp +++ b/cpp/test/testsuites/import3dtiff_test.cpp @@ -48,7 +48,7 @@ class Import3DTiff_Test : public SubTest { } - puma::import_3DTiff(&grayWS,"python/pumapy/data/200_fiberform.tif",0); + puma::import_3DTiff(&grayWS,puma::path_to_example_file("200_fiberform.tif"),0); if(!assertEquals((long)200*200*200,(long)grayWS.size(), &result)) { return result; @@ -103,7 +103,7 @@ class Import3DTiff_Test : public SubTest { puma::Workspace grayWS(1e-6,false); - bool success = puma::import_3DTiff(&grayWS,"python/pumapy/data/1300_Spheres.tif",0); + bool success = puma::import_3DTiff(&grayWS,puma::path_to_example_file("1300_Spheres.tif"),0); if(!assertEquals((long)1300*1300*1300,(long)grayWS.size(), &result)) { return result; @@ -131,7 +131,7 @@ class Import3DTiff_Test : public SubTest { puma::Workspace grayWS(1e-6,false); - bool success = puma::import_3DTiff(&grayWS,"python/pumapy/data/100_sphere_r40.tif",2147483647); + bool success = puma::import_3DTiff(&grayWS,puma::path_to_example_file("100_sphere_r40.tif"),2147483647); if(!assertEquals((bool)true,(bool)success, &result)) { return result; @@ -145,7 +145,7 @@ class Import3DTiff_Test : public SubTest { return result; } - success = puma::import_3DTiff(&grayWS,"python/pumapy/data/100_sphere_r40.tif",1000); + success = puma::import_3DTiff(&grayWS,puma::path_to_example_file("100_sphere_r40.tif"),1000); if(!assertEquals((bool)true,(bool)success, &result)) { return result; @@ -171,7 +171,7 @@ class Import3DTiff_Test : public SubTest { puma::Workspace grayWS(1e-6,false); - bool success = puma::import_3DTiff(&grayWS,"python/pumapy/data/100_sphere_r40.tif",-10); + bool success = puma::import_3DTiff(&grayWS,puma::path_to_example_file("100_sphere_r40.tif"),-10); if(!assertEquals((bool)true,(bool)success, &result)) { return result; @@ -197,7 +197,7 @@ class Import3DTiff_Test : public SubTest { puma::Workspace grayWS(1e-6,false); - bool success = puma::import_3DTiff(&grayWS,"python/pumapy/data/100_sphere_r40.tif",0); + bool success = puma::import_3DTiff(&grayWS,puma::path_to_example_file("100_sphere_r40.tif"),0); if(!assertEquals((bool)true,(bool)success, &result)) { return result; @@ -223,7 +223,7 @@ class Import3DTiff_Test : public SubTest { puma::Workspace grayWS(1e-6,false); - bool success = puma::import_3DTiff(&grayWS,"python/pumapy/data/100_sphere_r40.tif",10); + bool success = puma::import_3DTiff(&grayWS,puma::path_to_example_file("100_sphere_r40.tif"),10); if(!assertEquals((bool)true,(bool)success, &result)) { return result; @@ -249,7 +249,7 @@ class Import3DTiff_Test : public SubTest { puma::Workspace grayWS(100,100,100,0, 1e-6,false); - bool success = puma::import_3DTiff(&grayWS,"python/pumapy/data/NoFile.tif",0); + bool success = puma::import_3DTiff(&grayWS,puma::path_to_example_file("NoFile.tif"),0); if(!assertEquals((bool)false,(bool)success, &result)) { return result; @@ -281,7 +281,7 @@ class Import3DTiff_Test : public SubTest { } - puma::import_3DTiff(&grayWS,"python/pumapy/data/200_fiberform.tif",0,199,0,199,0,199,0); + puma::import_3DTiff(&grayWS,puma::path_to_example_file("200_fiberform.tif"),0,199,0,199,0,199,0); if(!assertEquals((long)200*200*200,(long)grayWS.size(), &result)) { return result; @@ -336,7 +336,7 @@ class Import3DTiff_Test : public SubTest { puma::Workspace grayWS(1e-6,false); - bool success = puma::import_3DTiff(&grayWS,"python/pumapy/data/1300_Spheres.tif",0,1299,0,1299,0,1299,0); + bool success = puma::import_3DTiff(&grayWS,puma::path_to_example_file("1300_Spheres.tif"),0,1299,0,1299,0,1299,0); if(!assertEquals((long)1300*1300*1300,(long)grayWS.size(), &result)) { return result; @@ -365,7 +365,7 @@ class Import3DTiff_Test : public SubTest { puma::Workspace grayWS(1e-6,false); - bool success = puma::import_3DTiff(&grayWS,"python/pumapy/data/100_sphere_r40.tif",0,99,0,99,0,99,2147483647); + bool success = puma::import_3DTiff(&grayWS,puma::path_to_example_file("100_sphere_r40.tif"),0,99,0,99,0,99,2147483647); if(!assertEquals((bool)true,(bool)success, &result)) { return result; @@ -379,7 +379,7 @@ class Import3DTiff_Test : public SubTest { return result; } - success = puma::import_3DTiff(&grayWS,"python/pumapy/data/100_sphere_r40.tif",0,99,0,99,0,99,1000); + success = puma::import_3DTiff(&grayWS,puma::path_to_example_file("100_sphere_r40.tif"),0,99,0,99,0,99,1000); if(!assertEquals((bool)true,(bool)success, &result)) { return result; @@ -405,7 +405,7 @@ class Import3DTiff_Test : public SubTest { puma::Workspace grayWS(1e-6,false); - bool success = puma::import_3DTiff(&grayWS,"python/pumapy/data/100_sphere_r40.tif",0,99,0,99,0,99,-10); + bool success = puma::import_3DTiff(&grayWS,puma::path_to_example_file("100_sphere_r40.tif"),0,99,0,99,0,99,-10); if(!assertEquals((bool)true,(bool)success, &result)) { return result; @@ -431,7 +431,7 @@ class Import3DTiff_Test : public SubTest { puma::Workspace grayWS(1e-6,false); - bool success = puma::import_3DTiff(&grayWS,"python/pumapy/data/100_sphere_r40.tif",0,99,0,99,0,99,0); + bool success = puma::import_3DTiff(&grayWS,puma::path_to_example_file("100_sphere_r40.tif"),0,99,0,99,0,99,0); if(!assertEquals((bool)true,(bool)success, &result)) { return result; @@ -457,7 +457,7 @@ class Import3DTiff_Test : public SubTest { puma::Workspace grayWS(1e-6,false); - bool success = puma::import_3DTiff(&grayWS,"python/pumapy/data/100_sphere_r40.tif",0,99,0,99,0,99,10); + bool success = puma::import_3DTiff(&grayWS,puma::path_to_example_file("100_sphere_r40.tif"),0,99,0,99,0,99,10); if(!assertEquals((bool)true,(bool)success, &result)) { return result; @@ -483,7 +483,7 @@ class Import3DTiff_Test : public SubTest { puma::Workspace grayWS(100,100,100,0, 1e-6,false); - bool success = puma::import_3DTiff(&grayWS,"python/pumapy/data/NoFile.tif",0,99,0,99,0,99,0); + bool success = puma::import_3DTiff(&grayWS,puma::path_to_example_file("NoFile.tif"),0,99,0,99,0,99,0); if(!assertEquals((bool)false,(bool)success, &result)) { return result; @@ -506,7 +506,7 @@ class Import3DTiff_Test : public SubTest { puma::Workspace grayWS(1e-6,false); - bool success = puma::import_3DTiff(&grayWS,"python/pumapy/data/100_fiberform.tif",50,99,0,99,0,99,0); + bool success = puma::import_3DTiff(&grayWS,puma::path_to_example_file("100_fiberform.tif"),50,99,0,99,0,99,0); if(!assertEquals((bool)true,(bool)success, &result)) { return result; @@ -520,37 +520,37 @@ class Import3DTiff_Test : public SubTest { return result; } - success = puma::import_3DTiff(&grayWS,"python/pumapy/data/100_fiberform.tif",-2147483647,99,0,99,0,99,0); + success = puma::import_3DTiff(&grayWS,puma::path_to_example_file("100_fiberform.tif"),-2147483647,99,0,99,0,99,0); if(!assertEquals((bool)false,(bool)success, &result)) { return result; } - success = puma::import_3DTiff(&grayWS,"python/pumapy/data/100_fiberform.tif",-1,99,0,99,0,99,0); + success = puma::import_3DTiff(&grayWS,puma::path_to_example_file("100_fiberform.tif"),-1,99,0,99,0,99,0); if(!assertEquals((bool)false,(bool)success, &result)) { return result; } - success = puma::import_3DTiff(&grayWS,"python/pumapy/data/100_fiberform.tif",20,100,0,99,0,99,0); + success = puma::import_3DTiff(&grayWS,puma::path_to_example_file("100_fiberform.tif"),20,100,0,99,0,99,0); if(!assertEquals((bool)false,(bool)success, &result)) { return result; } - success = puma::import_3DTiff(&grayWS,"python/pumapy/data/100_fiberform.tif",20,19,0,99,0,99,0); + success = puma::import_3DTiff(&grayWS,puma::path_to_example_file("100_fiberform.tif"),20,19,0,99,0,99,0); if(!assertEquals((bool)false,(bool)success, &result)) { return result; } - success = puma::import_3DTiff(&grayWS,"python/pumapy/data/100_fiberform.tif",20,2147483647,0,99,0,99,0); + success = puma::import_3DTiff(&grayWS,puma::path_to_example_file("100_fiberform.tif"),20,2147483647,0,99,0,99,0); if(!assertEquals((bool)false,(bool)success, &result)) { return result; } - success = puma::import_3DTiff(&grayWS,"python/pumapy/data/100_fiberform.tif",99,99,0,99,0,99,0); + success = puma::import_3DTiff(&grayWS,puma::path_to_example_file("100_fiberform.tif"),99,99,0,99,0,99,0); if(!assertEquals((bool)true,(bool)success, &result)) { return result; @@ -564,7 +564,7 @@ class Import3DTiff_Test : public SubTest { return result; } - success = puma::import_3DTiff(&grayWS,"python/pumapy/data/100_fiberform.tif",0,0,0,99,0,99,0); + success = puma::import_3DTiff(&grayWS,puma::path_to_example_file("100_fiberform.tif"),0,0,0,99,0,99,0); if(!assertEquals((bool)true,(bool)success, &result)) { return result; @@ -590,7 +590,7 @@ class Import3DTiff_Test : public SubTest { puma::Workspace grayWS(1e-6,false); - bool success = puma::import_3DTiff(&grayWS,"python/pumapy/data/100_fiberform.tif",0,99,50,99,0,99,0); + bool success = puma::import_3DTiff(&grayWS,puma::path_to_example_file("100_fiberform.tif"),0,99,50,99,0,99,0); if(!assertEquals((bool)true,(bool)success, &result)) { return result; @@ -604,37 +604,37 @@ class Import3DTiff_Test : public SubTest { return result; } - success = puma::import_3DTiff(&grayWS,"python/pumapy/data/100_fiberform.tif",0,99,-2147483647,99,0,99,0); + success = puma::import_3DTiff(&grayWS,puma::path_to_example_file("100_fiberform.tif"),0,99,-2147483647,99,0,99,0); if(!assertEquals((bool)false,(bool)success, &result)) { return result; } - success = puma::import_3DTiff(&grayWS,"python/pumapy/data/100_fiberform.tif",0,99,-1,99,0,99,0); + success = puma::import_3DTiff(&grayWS,puma::path_to_example_file("100_fiberform.tif"),0,99,-1,99,0,99,0); if(!assertEquals((bool)false,(bool)success, &result)) { return result; } - success = puma::import_3DTiff(&grayWS,"python/pumapy/data/100_fiberform.tif",0,99,20,100,0,99,0); + success = puma::import_3DTiff(&grayWS,puma::path_to_example_file("100_fiberform.tif"),0,99,20,100,0,99,0); if(!assertEquals((bool)false,(bool)success, &result)) { return result; } - success = puma::import_3DTiff(&grayWS,"python/pumapy/data/100_fiberform.tif",0,99,20,19,0,99,0); + success = puma::import_3DTiff(&grayWS,puma::path_to_example_file("100_fiberform.tif"),0,99,20,19,0,99,0); if(!assertEquals((bool)false,(bool)success, &result)) { return result; } - success = puma::import_3DTiff(&grayWS,"python/pumapy/data/100_fiberform.tif",0,99,20,2147483647,0,99,0); + success = puma::import_3DTiff(&grayWS,puma::path_to_example_file("100_fiberform.tif"),0,99,20,2147483647,0,99,0); if(!assertEquals((bool)false,(bool)success, &result)) { return result; } - success = puma::import_3DTiff(&grayWS,"python/pumapy/data/100_fiberform.tif",0,99,99,99,0,99,0); + success = puma::import_3DTiff(&grayWS,puma::path_to_example_file("100_fiberform.tif"),0,99,99,99,0,99,0); if(!assertEquals((bool)true,(bool)success, &result)) { return result; @@ -648,7 +648,7 @@ class Import3DTiff_Test : public SubTest { return result; } - success = puma::import_3DTiff(&grayWS,"python/pumapy/data/100_fiberform.tif",0,99,0,0,0,99,0); + success = puma::import_3DTiff(&grayWS,puma::path_to_example_file("100_fiberform.tif"),0,99,0,0,0,99,0); if(!assertEquals((bool)true,(bool)success, &result)) { return result; @@ -673,7 +673,7 @@ class Import3DTiff_Test : public SubTest { puma::Workspace grayWS(1e-6,false); - bool success = puma::import_3DTiff(&grayWS,"python/pumapy/data/100_fiberform.tif",0,99,0,99,50,99,0); + bool success = puma::import_3DTiff(&grayWS,puma::path_to_example_file("100_fiberform.tif"),0,99,0,99,50,99,0); if(!assertEquals((bool)true,(bool)success, &result)) { return result; @@ -687,37 +687,37 @@ class Import3DTiff_Test : public SubTest { return result; } - success = puma::import_3DTiff(&grayWS,"python/pumapy/data/100_fiberform.tif",0,99,0,99,-2147483647,99,0); + success = puma::import_3DTiff(&grayWS,puma::path_to_example_file("100_fiberform.tif"),0,99,0,99,-2147483647,99,0); if(!assertEquals((bool)false,(bool)success, &result)) { return result; } - success = puma::import_3DTiff(&grayWS,"python/pumapy/data/100_fiberform.tif",0,99,0,99,-1,99,0); + success = puma::import_3DTiff(&grayWS,puma::path_to_example_file("100_fiberform.tif"),0,99,0,99,-1,99,0); if(!assertEquals((bool)false,(bool)success, &result)) { return result; } - success = puma::import_3DTiff(&grayWS,"python/pumapy/data/100_fiberform.tif",0,99,0,99,20,100,0); + success = puma::import_3DTiff(&grayWS,puma::path_to_example_file("100_fiberform.tif"),0,99,0,99,20,100,0); if(!assertEquals((bool)false,(bool)success, &result)) { return result; } - success = puma::import_3DTiff(&grayWS,"python/pumapy/data/100_fiberform.tif",0,99,0,99,20,19,0); + success = puma::import_3DTiff(&grayWS,puma::path_to_example_file("100_fiberform.tif"),0,99,0,99,20,19,0); if(!assertEquals((bool)false,(bool)success, &result)) { return result; } - success = puma::import_3DTiff(&grayWS,"python/pumapy/data/100_fiberform.tif",0,99,0,99,20,2147483647,0); + success = puma::import_3DTiff(&grayWS,puma::path_to_example_file("100_fiberform.tif"),0,99,0,99,20,2147483647,0); if(!assertEquals((bool)false,(bool)success, &result)) { return result; } - success = puma::import_3DTiff(&grayWS,"python/pumapy/data/100_fiberform.tif",0,99,0,99,99,99,0); + success = puma::import_3DTiff(&grayWS,puma::path_to_example_file("100_fiberform.tif"),0,99,0,99,99,99,0); if(!assertEquals((bool)true,(bool)success, &result)) { return result; @@ -731,7 +731,7 @@ class Import3DTiff_Test : public SubTest { return result; } - success = puma::import_3DTiff(&grayWS,"python/pumapy/data/100_fiberform.tif",0,99,0,99,0,0,0); + success = puma::import_3DTiff(&grayWS,puma::path_to_example_file("100_fiberform.tif"),0,99,0,99,0,0,0); if(!assertEquals((bool)true,(bool)success, &result)) { return result; diff --git a/cpp/test/testsuites/isosurface_test.cpp b/cpp/test/testsuites/isosurface_test.cpp index 2e92b70..0ee222e 100644 --- a/cpp/test/testsuites/isosurface_test.cpp +++ b/cpp/test/testsuites/isosurface_test.cpp @@ -179,7 +179,7 @@ class IsoSurface_Test : public SubTest { puma::Workspace grayWS(1e-6,false); - puma::import_3DTiff(&grayWS,"python/pumapy/data/100_sphere_r40.tif",10); + puma::import_3DTiff(&grayWS,puma::path_to_example_file("100_sphere_r40.tif"),10); puma::Matrix newMatrix; @@ -218,7 +218,7 @@ class IsoSurface_Test : public SubTest { puma::Workspace grayWS(1e-6,false); - puma::import_3DTiff(&grayWS,"python/pumapy/data/100_sphere_r40.tif",10); + puma::import_3DTiff(&grayWS,puma::path_to_example_file("100_sphere_r40.tif"),10); grayWS.crop(0,98,0,97,1,96); puma::Matrix newMatrix; @@ -338,7 +338,7 @@ class IsoSurface_Test : public SubTest { puma::Workspace grayWS(1e-6,false); - puma::import_3DTiff(&grayWS,"python/pumapy/data/100_sphere_r40.tif",10); + puma::import_3DTiff(&grayWS,puma::path_to_example_file("100_sphere_r40.tif"),10); puma::Matrix newMatrix; bool success = IsoSurfaceHelper::DownScale(&grayWS.matrix,&newMatrix, 4,8); @@ -576,7 +576,7 @@ class IsoSurface_Test : public SubTest { TestResult result(suiteName, testName, 17, testDescription); puma::Workspace grayWS(1e-6,false); - puma::import_3DTiff(&grayWS,"python/pumapy/data/100_sphere_r40.tif",0); + puma::import_3DTiff(&grayWS,puma::path_to_example_file("100_sphere_r40.tif"),0); std::vector< puma::Triangle > tris(100); bool success = puma::isosurface_MarchingCubes(&tris,&grayWS,puma::Cutoff(128,255),true,1,false,0); @@ -603,7 +603,7 @@ class IsoSurface_Test : public SubTest { TestResult result(suiteName, testName, 18, testDescription); puma::Workspace grayWS(1e-6,false); - puma::import_3DTiff(&grayWS,"python/pumapy/data/100_sphere_r40.tif",0); + puma::import_3DTiff(&grayWS,puma::path_to_example_file("100_sphere_r40.tif"),0); std::vector< puma::Triangle > tris(100); grayWS.crop(0,99,0,98,1,97); @@ -632,7 +632,7 @@ class IsoSurface_Test : public SubTest { TestResult result(suiteName, testName, 19, testDescription); puma::Workspace grayWS(1e-6,false); - puma::import_3DTiff(&grayWS,"python/pumapy/data/100_cylinder_r40.tif",0); + puma::import_3DTiff(&grayWS,puma::path_to_example_file("100_cylinder_r40.tif"),0); std::vector< puma::Triangle > tris(100); bool success = puma::isosurface_MarchingCubes(&tris,&grayWS,puma::Cutoff(128,255),true,1,false,0); @@ -659,7 +659,7 @@ class IsoSurface_Test : public SubTest { TestResult result(suiteName, testName, 20, testDescription); puma::Workspace grayWS(1e-6,false); - puma::import_3DTiff(&grayWS,"python/pumapy/data/100_cylinder_r40.tif",0); + puma::import_3DTiff(&grayWS,puma::path_to_example_file("100_cylinder_r40.tif"),0); std::vector< puma::Triangle > tris(100); bool success = puma::isosurface_MarchingCubes(&tris,&grayWS,puma::Cutoff(128,255),false,1,false,0); @@ -686,7 +686,7 @@ class IsoSurface_Test : public SubTest { TestResult result(suiteName, testName, 21, testDescription); puma::Workspace grayWS(1e-6,false); - puma::import_3DTiff(&grayWS,"python/pumapy/data/100_cylinder_r40.tif",0); + puma::import_3DTiff(&grayWS,puma::path_to_example_file("100_cylinder_r40.tif"),0); std::vector< puma::Triangle > tris(100); bool success = puma::isosurface_MarchingCubes(&tris,&grayWS,puma::Cutoff(0,127),true,1,false,0); @@ -713,7 +713,7 @@ class IsoSurface_Test : public SubTest { TestResult result(suiteName, testName, 22, testDescription); puma::Workspace grayWS(1e-6,false); - puma::import_3DTiff(&grayWS,"python/pumapy/data/100_cylinder_r40.tif",0); + puma::import_3DTiff(&grayWS,puma::path_to_example_file("100_cylinder_r40.tif"),0); std::vector< puma::Triangle > tris(100); bool success = puma::isosurface_MarchingCubes(&tris,&grayWS,puma::Cutoff(0,127),false,1,false,0); @@ -740,7 +740,7 @@ class IsoSurface_Test : public SubTest { TestResult result(suiteName, testName, 23, testDescription); puma::Workspace grayWS(1e-6,false); - puma::import_3DTiff(&grayWS,"python/pumapy/data/100_cylinder_r40.tif",0); + puma::import_3DTiff(&grayWS,puma::path_to_example_file("100_cylinder_r40.tif"),0); std::vector< puma::Triangle > tris(100); bool success = puma::isosurface_MarchingCubes(&tris,&grayWS,puma::Cutoff(0,127),true,1,true,0); @@ -767,7 +767,7 @@ class IsoSurface_Test : public SubTest { TestResult result(suiteName, testName, 24, testDescription); puma::Workspace grayWS(1e-6,false); - puma::import_3DTiff(&grayWS,"python/pumapy/data/200_fiberform.tif",0); + puma::import_3DTiff(&grayWS,puma::path_to_example_file("200_fiberform.tif"),0); std::vector< puma::Triangle > tris(100); bool success = puma::isosurface_MarchingCubes(&tris,&grayWS,puma::Cutoff(90,255),false,1,false,0); @@ -796,7 +796,7 @@ class IsoSurface_Test : public SubTest { TestResult result(suiteName, testName, 25, testDescription); puma::Workspace grayWS(1e-6,false); - puma::import_3DTiff(&grayWS,"python/pumapy/data/200_fiberform.tif",0); + puma::import_3DTiff(&grayWS,puma::path_to_example_file("200_fiberform.tif"),0); std::vector< puma::Triangle > tris(100); bool success = puma::isosurface_MarchingCubes(&tris,&grayWS,puma::Cutoff(90,255),true,1,false,0); @@ -823,7 +823,7 @@ class IsoSurface_Test : public SubTest { TestResult result(suiteName, testName, 26, testDescription); puma::Workspace grayWS(1e-6,false); - puma::import_3DTiff(&grayWS,"python/pumapy/data/200_fiberform.tif",0); + puma::import_3DTiff(&grayWS,puma::path_to_example_file("200_fiberform.tif"),0); std::vector< puma::Triangle > tris(100); bool success = puma::isosurface_MarchingCubes(&tris,&grayWS,puma::Cutoff(90,255),false,1,true,0); @@ -850,7 +850,7 @@ class IsoSurface_Test : public SubTest { TestResult result(suiteName, testName, 27, testDescription); puma::Workspace grayWS(1e-6,false); - puma::import_3DTiff(&grayWS,"python/pumapy/data/200_fiberform.tif",0); + puma::import_3DTiff(&grayWS,puma::path_to_example_file("200_fiberform.tif"),0); std::vector< puma::Triangle > tris(100); bool success = puma::isosurface_MarchingCubes(&tris,&grayWS,puma::Cutoff(90,255),true,1,true,0); @@ -877,7 +877,7 @@ class IsoSurface_Test : public SubTest { TestResult result(suiteName, testName, 28, testDescription); puma::Workspace grayWS(1e-6,false); - puma::import_3DTiff(&grayWS,"python/pumapy/data/200_fiberform.tif",0); + puma::import_3DTiff(&grayWS,puma::path_to_example_file("200_fiberform.tif"),0); std::vector< puma::Triangle > tris(100); bool success = puma::isosurface_MarchingCubes(&tris,&grayWS,puma::Cutoff(90,255),false,2,true,0); @@ -904,7 +904,7 @@ class IsoSurface_Test : public SubTest { TestResult result(suiteName, testName, 29, testDescription); puma::Workspace grayWS(1e-6,false); - puma::import_3DTiff(&grayWS,"python/pumapy/data/200_fiberform.tif",0); + puma::import_3DTiff(&grayWS,puma::path_to_example_file("200_fiberform.tif"),0); std::vector< puma::Triangle > tris(100); bool success = puma::isosurface_MarchingCubes(&tris,&grayWS,puma::Cutoff(90,255),true,2,true,0); @@ -931,7 +931,7 @@ class IsoSurface_Test : public SubTest { TestResult result(suiteName, testName, 30, testDescription); puma::Workspace grayWS(1e-6,false); - puma::import_3DTiff(&grayWS,"python/pumapy/data/200_fiberform.tif",0); + puma::import_3DTiff(&grayWS,puma::path_to_example_file("200_fiberform.tif"),0); std::vector< puma::Triangle > tris(100); bool success = puma::isosurface_MarchingCubes(&tris,&grayWS,puma::Cutoff(90,255),false,2,false,0); @@ -959,7 +959,7 @@ class IsoSurface_Test : public SubTest { TestResult result(suiteName, testName, 31, testDescription); puma::Workspace grayWS(1e-6,false); - puma::import_3DTiff(&grayWS,"python/pumapy/data/200_fiberform.tif",0); + puma::import_3DTiff(&grayWS,puma::path_to_example_file("200_fiberform.tif"),0); std::vector< puma::Triangle > tris(100); bool success = puma::isosurface_MarchingCubes(&tris,&grayWS,puma::Cutoff(90,255),true,2,false,0); @@ -1151,7 +1151,7 @@ class IsoSurface_Test : public SubTest { TestResult result(suiteName, testName, 38, testDescription); puma::Workspace grayWS(1e-6,false); - puma::import_3DTiff(&grayWS,"python/pumapy/data/100_sphere_r40.tif",0); + puma::import_3DTiff(&grayWS,puma::path_to_example_file("100_sphere_r40.tif"),0); puma::Workspace segWS(grayWS.shape(), false); @@ -1184,7 +1184,7 @@ class IsoSurface_Test : public SubTest { TestResult result(suiteName, testName, 39, testDescription); puma::Workspace grayWS(1e-6,false); - puma::import_3DTiff(&grayWS,"python/pumapy/data/100_sphere_r40.tif",0); + puma::import_3DTiff(&grayWS,puma::path_to_example_file("100_sphere_r40.tif"),0); puma::Workspace segWS(grayWS.shape(), false); segWS.setMaterialID(&grayWS,puma::Cutoff(128,255),1); @@ -1217,7 +1217,7 @@ class IsoSurface_Test : public SubTest { TestResult result(suiteName, testName, 40, testDescription); puma::Workspace grayWS(1e-6,false); - puma::import_3DTiff(&grayWS,"python/pumapy/data/100_cylinder_r40.tif",0); + puma::import_3DTiff(&grayWS,puma::path_to_example_file("100_cylinder_r40.tif"),0); puma::Workspace segWS(grayWS.shape(), false); segWS.setMaterialID(&grayWS,puma::Cutoff(128,255),1); @@ -1248,7 +1248,7 @@ class IsoSurface_Test : public SubTest { TestResult result(suiteName, testName,41, testDescription); puma::Workspace grayWS(1e-6,false); - puma::import_3DTiff(&grayWS,"python/pumapy/data/100_cylinder_r40.tif",0); + puma::import_3DTiff(&grayWS,puma::path_to_example_file("100_cylinder_r40.tif"),0); puma::Workspace segWS(grayWS.shape(), false); segWS.setMaterialID(&grayWS,puma::Cutoff(128,255),1); @@ -1279,7 +1279,7 @@ class IsoSurface_Test : public SubTest { TestResult result(suiteName, testName, 42, testDescription); puma::Workspace grayWS(1e-6,false); - puma::import_3DTiff(&grayWS,"python/pumapy/data/100_cylinder_r40.tif",0); + puma::import_3DTiff(&grayWS,puma::path_to_example_file("100_cylinder_r40.tif"),0); puma::Workspace segWS(grayWS.shape(), false); segWS.setMaterialID(&grayWS,puma::Cutoff(128,255),1); @@ -1310,7 +1310,7 @@ class IsoSurface_Test : public SubTest { TestResult result(suiteName, testName, 43, testDescription); puma::Workspace grayWS(1e-6,false); - puma::import_3DTiff(&grayWS,"python/pumapy/data/100_cylinder_r40.tif",0); + puma::import_3DTiff(&grayWS,puma::path_to_example_file("100_cylinder_r40.tif"),0); puma::Workspace segWS(grayWS.shape(), false); segWS.setMaterialID(&grayWS,puma::Cutoff(128,255),1); @@ -1341,7 +1341,7 @@ class IsoSurface_Test : public SubTest { TestResult result(suiteName, testName, 44, testDescription); puma::Workspace grayWS(1e-6,false); - puma::import_3DTiff(&grayWS,"python/pumapy/data/100_cylinder_r40.tif",0); + puma::import_3DTiff(&grayWS,puma::path_to_example_file("100_cylinder_r40.tif"),0); puma::Workspace segWS(grayWS.shape(), false); segWS.setMaterialID(&grayWS,puma::Cutoff(128,255),1); @@ -1372,7 +1372,7 @@ class IsoSurface_Test : public SubTest { TestResult result(suiteName, testName, 45, testDescription); puma::Workspace grayWS(1e-6,false); - puma::import_3DTiff(&grayWS,"python/pumapy/data/200_fiberform.tif",0); + puma::import_3DTiff(&grayWS,puma::path_to_example_file("200_fiberform.tif"),0); puma::Workspace segWS(grayWS.shape(), false); segWS.setMaterialID(&grayWS,puma::Cutoff(90,255),1); @@ -1405,7 +1405,7 @@ class IsoSurface_Test : public SubTest { TestResult result(suiteName, testName, 46, testDescription); puma::Workspace grayWS(1e-6,false); - puma::import_3DTiff(&grayWS,"python/pumapy/data/200_fiberform.tif",0); + puma::import_3DTiff(&grayWS,puma::path_to_example_file("200_fiberform.tif"),0); puma::Workspace segWS(grayWS.shape(), false); segWS.setMaterialID(&grayWS,puma::Cutoff(90,255),1); @@ -1436,7 +1436,7 @@ class IsoSurface_Test : public SubTest { TestResult result(suiteName, testName, 47, testDescription); puma::Workspace grayWS(1e-6,false); - puma::import_3DTiff(&grayWS,"python/pumapy/data/200_fiberform.tif",0); + puma::import_3DTiff(&grayWS,puma::path_to_example_file("200_fiberform.tif"),0); puma::Workspace segWS(grayWS.shape(), false); segWS.setMaterialID(&grayWS,puma::Cutoff(90,255),1); @@ -1467,7 +1467,7 @@ class IsoSurface_Test : public SubTest { TestResult result(suiteName, testName, 48, testDescription); puma::Workspace grayWS(1e-6,false); - puma::import_3DTiff(&grayWS,"python/pumapy/data/200_fiberform.tif",0); + puma::import_3DTiff(&grayWS,puma::path_to_example_file("200_fiberform.tif"),0); puma::Workspace segWS(grayWS.shape(), false); segWS.setMaterialID(&grayWS,puma::Cutoff(90,255),1); @@ -1498,7 +1498,7 @@ class IsoSurface_Test : public SubTest { TestResult result(suiteName, testName, 49, testDescription); puma::Workspace grayWS(1e-6,false); - puma::import_3DTiff(&grayWS,"python/pumapy/data/200_fiberform.tif",0); + puma::import_3DTiff(&grayWS,puma::path_to_example_file("200_fiberform.tif"),0); puma::Workspace segWS(grayWS.shape(), false); segWS.setMaterialID(&grayWS,puma::Cutoff(90,255),1); @@ -1529,7 +1529,7 @@ class IsoSurface_Test : public SubTest { TestResult result(suiteName, testName, 50, testDescription); puma::Workspace grayWS(1e-6,false); - puma::import_3DTiff(&grayWS,"python/pumapy/data/200_fiberform.tif",0); + puma::import_3DTiff(&grayWS,puma::path_to_example_file("200_fiberform.tif"),0); puma::Workspace segWS(grayWS.shape(), false); segWS.setMaterialID(&grayWS,puma::Cutoff(90,255),1); @@ -1560,7 +1560,7 @@ class IsoSurface_Test : public SubTest { TestResult result(suiteName, testName, 51, testDescription); puma::Workspace grayWS(1e-6,false); - puma::import_3DTiff(&grayWS,"python/pumapy/data/200_fiberform.tif",0); + puma::import_3DTiff(&grayWS,puma::path_to_example_file("200_fiberform.tif"),0); puma::Workspace segWS(grayWS.shape(), false); segWS.setMaterialID(&grayWS,puma::Cutoff(90,255),1); @@ -1591,7 +1591,7 @@ class IsoSurface_Test : public SubTest { TestResult result(suiteName, testName, 52, testDescription); puma::Workspace grayWS(1e-6,false); - puma::import_3DTiff(&grayWS,"python/pumapy/data/200_fiberform.tif",0); + puma::import_3DTiff(&grayWS,puma::path_to_example_file("200_fiberform.tif"),0); puma::Workspace segWS(grayWS.shape(), false); segWS.setMaterialID(&grayWS,puma::Cutoff(90,255),1); @@ -1912,7 +1912,7 @@ class IsoSurface_Test : public SubTest { TestResult result(suiteName, testName, 61, testDescription); puma::Workspace grayWS(1e-6,false); - puma::import_3DTiff(&grayWS,"python/pumapy/data/100_cylinder_r40.tif"); + puma::import_3DTiff(&grayWS,puma::path_to_example_file("100_cylinder_r40.tif")); puma::Workspace segWS(grayWS.shape(), false); segWS.setMaterialID(&grayWS,puma::Cutoff(0,127),0); @@ -2119,7 +2119,7 @@ class IsoSurface_Test : public SubTest { - puma::import_3DTiff(&grayWS,"python/pumapy/data/100_cylinder_r40.tif"); + puma::import_3DTiff(&grayWS,puma::path_to_example_file("100_cylinder_r40.tif")); grayWS.setMaterialID(puma::Cutoff(0,67),0); grayWS.setMaterialID(puma::Cutoff(68,127),1); diff --git a/cpp/test/testsuites/meaninterceptlength_test.cpp b/cpp/test/testsuites/meaninterceptlength_test.cpp index ac3660c..c80c816 100644 --- a/cpp/test/testsuites/meaninterceptlength_test.cpp +++ b/cpp/test/testsuites/meaninterceptlength_test.cpp @@ -305,7 +305,7 @@ class MeanInterceptLength_Test : public SubTest { TestResult result(suiteName, testName, 12, testDescription); puma::Workspace segWS(1300,1300,1300,0,1e-6,false); - puma::import_3DTiff(&segWS,"python/pumapy/data/1300_Spheres.tif"); + puma::import_3DTiff(&segWS,puma::path_to_example_file("1300_Spheres.tif")); puma::Vec3 mil = puma::compute_MeanInterceptLength(&segWS,puma::Cutoff(0,0)); @@ -329,7 +329,7 @@ class MeanInterceptLength_Test : public SubTest { TestResult result(suiteName, testName, 13, testDescription); puma::Workspace segWS(130,130,130,0,1e-6,false); - puma::import_3DTiff(&segWS,"python/pumapy/data/1300_Spheres.tif",0,130,0,130,0,130); + puma::import_3DTiff(&segWS,puma::path_to_example_file("1300_Spheres.tif"),0,130,0,130,0,130); puma::Vec3 mil = puma::compute_MeanInterceptLength(&segWS,puma::Cutoff(0,0)); @@ -353,7 +353,7 @@ class MeanInterceptLength_Test : public SubTest { TestResult result(suiteName, testName, 14, testDescription); puma::Workspace segWS(200,200,200,0,1e-6,false); - puma::import_3DTiff(&segWS,"python/pumapy/data/200_fiberform_segmented.tif"); + puma::import_3DTiff(&segWS,puma::path_to_example_file("200_fiberform_segmented.tif")); puma::Vec3 mil = puma::compute_MeanInterceptLength(&segWS,puma::Cutoff(0,0)); @@ -377,7 +377,7 @@ class MeanInterceptLength_Test : public SubTest { TestResult result(suiteName, testName, 15, testDescription); puma::Workspace grayWS(200,200,200,0,1e-6,false); - puma::import_3DTiff(&grayWS,"python/pumapy/data/200_fiberform.tif"); + puma::import_3DTiff(&grayWS,puma::path_to_example_file("200_fiberform.tif")); puma::Vec3 mil = puma::compute_MeanInterceptLength(&grayWS,puma::Cutoff(0,89)); diff --git a/cpp/test/testsuites/surfacearea_test.cpp b/cpp/test/testsuites/surfacearea_test.cpp index 0123f19..dad35f9 100644 --- a/cpp/test/testsuites/surfacearea_test.cpp +++ b/cpp/test/testsuites/surfacearea_test.cpp @@ -217,7 +217,7 @@ class SurfaceArea_Test : public SubTest { TestResult result(suiteName, testName, 9, testDescription); puma::Workspace segWS(1300,1300,1300,0,1e-6,false); - puma::import_3DTiff(&segWS,"python/pumapy/data/1300_Spheres.tif",0); + puma::import_3DTiff(&segWS,puma::path_to_example_file("1300_Spheres.tif"),0); std::pair sa = compute_SurfaceAreaVoxels(&segWS, puma::Cutoff(1, 1), 0); @@ -238,7 +238,7 @@ class SurfaceArea_Test : public SubTest { TestResult result(suiteName, testName, 10, testDescription); puma::Workspace grayWS(1300,1300,1300,0,1e-6,false); - puma::import_3DTiff(&grayWS,"python/pumapy/data/1300_Spheres.tif",0); + puma::import_3DTiff(&grayWS,puma::path_to_example_file("1300_Spheres.tif"),0); std::pair sa = compute_SurfaceAreaVoxels(&grayWS, puma::Cutoff(128, 255), 0); @@ -259,7 +259,7 @@ class SurfaceArea_Test : public SubTest { TestResult result(suiteName, testName, 11, testDescription); puma::Workspace segWS(200,200,200,0,1e-6,false); - puma::import_3DTiff(&segWS,"python/pumapy/data/200_fiberform_segmented.tif",0); + puma::import_3DTiff(&segWS,puma::path_to_example_file("200_fiberform_segmented.tif"),0); std::pair sa = compute_SurfaceAreaVoxels(&segWS, puma::Cutoff(1, 1), 0); @@ -280,7 +280,7 @@ class SurfaceArea_Test : public SubTest { TestResult result(suiteName, testName, 12, testDescription); puma::Workspace grayWS(200,200,200,0,1e-6,false); - puma::import_3DTiff(&grayWS,"python/pumapy/data/200_fiberform.tif",0); + puma::import_3DTiff(&grayWS,puma::path_to_example_file("200_fiberform.tif"),0); std::pair sa = compute_SurfaceAreaVoxels(&grayWS, puma::Cutoff(90, 255), 0); @@ -426,7 +426,7 @@ class SurfaceArea_Test : public SubTest { TestResult result(suiteName, testName, 19, testDescription); puma::Workspace grayWS(1300,1300,1300,0,1e-6,false); - puma::import_3DTiff(&grayWS,"python/pumapy/data/1300_Spheres.tif",0); + puma::import_3DTiff(&grayWS,puma::path_to_example_file("1300_Spheres.tif"),0); std::pair sa = compute_SurfaceAreaMarchingCubes(&grayWS, puma::Cutoff(128, 255), 0, 0); @@ -448,7 +448,7 @@ class SurfaceArea_Test : public SubTest { TestResult result(suiteName, testName, 20, testDescription); puma::Workspace segWS(1300,1300,1300,0,1e-6,false); - puma::import_3DTiff(&segWS,"python/pumapy/data/1300_Spheres.tif",0); + puma::import_3DTiff(&segWS,puma::path_to_example_file("1300_Spheres.tif"),0); std::pair sa = compute_SurfaceAreaMarchingCubes(&segWS, puma::Cutoff(1, 1), 0, 0); if(!assertEquals(3.350938727e-5,sa.first, &result)) { @@ -469,7 +469,7 @@ class SurfaceArea_Test : public SubTest { TestResult result(suiteName, testName, 21, testDescription); puma::Workspace grayWS(200,200,200,0,1e-6,false); - puma::import_3DTiff(&grayWS,"python/pumapy/data/200_fiberform.tif",0); + puma::import_3DTiff(&grayWS,puma::path_to_example_file("200_fiberform.tif"),0); std::pair sa = compute_SurfaceAreaMarchingCubes(&grayWS, puma::Cutoff(90, 255), 0, 0); @@ -491,7 +491,7 @@ class SurfaceArea_Test : public SubTest { TestResult result(suiteName, testName, 22, testDescription); puma::Workspace segWS(200,200,200,0,1e-6,false); - puma::import_3DTiff(&segWS,"python/pumapy/data/200_fiberform_segmented.tif",0); + puma::import_3DTiff(&segWS,puma::path_to_example_file("200_fiberform_segmented.tif"),0); std::pair sa = compute_SurfaceAreaMarchingCubes(&segWS, puma::Cutoff(1, 1), 0, 0); if(!assertEquals(4.479217316e-7,sa.first, &result)) { @@ -556,7 +556,7 @@ class SurfaceArea_Test : public SubTest { TestResult result(suiteName, testName, 25, testDescription); puma::Workspace grayWS(1300,1300,1300,0,1e-6,false); - puma::import_3DTiff(&grayWS,"python/pumapy/data/1300_Spheres.tif",0); + puma::import_3DTiff(&grayWS,puma::path_to_example_file("1300_Spheres.tif"),0); std::pair sa = compute_SurfaceAreaMarchingCubes(&grayWS, puma::Cutoff(128, 255), 1, 0); @@ -578,7 +578,7 @@ class SurfaceArea_Test : public SubTest { TestResult result(suiteName, testName, 26, testDescription); puma::Workspace segWS(1300,1300,1300,0,1e-6,false); - puma::import_3DTiff(&segWS,"python/pumapy/data/1300_Spheres.tif",0); + puma::import_3DTiff(&segWS,puma::path_to_example_file("1300_Spheres.tif"),0); std::pair sa = compute_SurfaceAreaMarchingCubes(&segWS, puma::Cutoff(1, 1), 1, 0); if(!assertEquals(3.130272474e-05,sa.first, &result)) { @@ -599,7 +599,7 @@ class SurfaceArea_Test : public SubTest { TestResult result(suiteName, testName, 27, testDescription); puma::Workspace grayWS(200,200,200,0,1e-6,false); - puma::import_3DTiff(&grayWS,"python/pumapy/data/200_fiberform.tif",0); + puma::import_3DTiff(&grayWS,puma::path_to_example_file("200_fiberform.tif"),0); std::pair sa = compute_SurfaceAreaMarchingCubes(&grayWS, puma::Cutoff(90, 255), 1, 0); @@ -621,7 +621,7 @@ class SurfaceArea_Test : public SubTest { TestResult result(suiteName, testName, 28, testDescription); puma::Workspace segWS(200,200,200,0,1e-6,false); - puma::import_3DTiff(&segWS,"python/pumapy/data/200_fiberform_segmented.tif",0); + puma::import_3DTiff(&segWS,puma::path_to_example_file("200_fiberform_segmented.tif"),0); std::pair sa = compute_SurfaceAreaMarchingCubes(&segWS, puma::Cutoff(1, 1), 1, 0); if(!assertEquals(4.122054032e-7,sa.first, &result)) { diff --git a/install/env/puma-env-linux.lock b/install/env/puma-env-linux.lock deleted file mode 100644 index 72a475e..0000000 --- a/install/env/puma-env-linux.lock +++ /dev/null @@ -1,298 +0,0 @@ -# Generated by conda-lock. -# platform: linux-64 -# env_hash: 09167bff7f5bf22b0fa664bab13e13eaefcc0a9b0534a72ce3aa80274df7fa3a -@EXPLICIT -https://conda.anaconda.org/conda-forge/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2#d7c89558ba9fa0495403155b64376d81 -https://conda.anaconda.org/conda-forge/linux-64/ca-certificates-2021.5.30-ha878542_0.tar.bz2#6a777890e94194dc94a29a76d2a7e721 -https://conda.anaconda.org/conda-forge/noarch/kernel-headers_linux-64-2.6.32-he073ed8_14.tar.bz2#40c41dffc04c17136f02498538db1d2b -https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.36.1-hea4e1c9_2.tar.bz2#bd4f2e711b39af170e7ff15163fe87ee -https://conda.anaconda.org/conda-forge/linux-64/libgcc-devel_linux-64-9.4.0-hd854feb_8.tar.bz2#53f3d06d5c073dfd908416825bcd461a -https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-11.1.0-h6c583b3_8.tar.bz2#478b6358c5d08b7e133a5da71c5c81bd -https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-devel_linux-64-9.4.0-hd854feb_8.tar.bz2#8deec1dee58a9721e9d152e130ecdd0e -https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-ng-11.1.0-h56837e0_8.tar.bz2#930957b6bff66cfd539ada080c5ca3e8 -https://conda.anaconda.org/conda-forge/linux-64/mpi-1.0-mpich.tar.bz2#c1fcff3417b5a22bbc4cf6e8c23648cf -https://conda.anaconda.org/conda-forge/linux-64/mumps-include-5.2.1-ha770c72_10.tar.bz2#ab9f7fddadf12d9cb24bf752682ba101 -https://conda.anaconda.org/conda-forge/linux-64/pandoc-2.14.1-h7f98852_0.tar.bz2#c544898cbced743599b68650e22b8e6b -https://conda.anaconda.org/conda-forge/linux-64/utfcpp-3.2.1-ha770c72_0.tar.bz2#7b60818913cd7d5179ff4cfdd693e52a -https://conda.anaconda.org/conda-forge/linux-64/libgfortran-ng-11.1.0-h69a702a_8.tar.bz2#7bacab270c077a054525e8afe29feaa9 -https://conda.anaconda.org/conda-forge/linux-64/libgomp-11.1.0-hc902ee8_8.tar.bz2#f2dd961d1ae80d9d81b3d5068807f11b -https://conda.anaconda.org/conda-forge/noarch/sysroot_linux-64-2.12-he073ed8_14.tar.bz2#78c8c32c25226732442d101d4fe1d785 -https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-1_gnu.tar.bz2#561e277319a41d4f24f5c05a9ef63c04 -https://conda.anaconda.org/conda-forge/linux-64/binutils_impl_linux-64-2.36.1-h193b22a_2.tar.bz2#32aae4265554a47ea77f7c09f86aeb3b -https://conda.anaconda.org/conda-forge/linux-64/binutils_linux-64-2.36-hf3e587d_0.tar.bz2#bfc07abe5f4f0c66ae0fa55de5b16546 -https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-11.1.0-hc902ee8_8.tar.bz2#da6221956ce8582d8e71acc16dfe4c3e -https://conda.anaconda.org/conda-forge/linux-64/blosc-1.21.0-h9c3ff4c_0.tar.bz2#5e815e5126c6f7e34ab4496fa1b48dca -https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-h7f98852_4.tar.bz2#a1fd65c7ccbf10880423d82bca54eb54 -https://conda.anaconda.org/conda-forge/linux-64/c-ares-1.17.2-h7f98852_0.tar.bz2#a25871010e5104556045aa01850fbddf -https://conda.anaconda.org/conda-forge/linux-64/charls-2.2.0-h9c3ff4c_0.tar.bz2#bc0a1a5c99af57d2821914ab074797f9 -https://conda.anaconda.org/conda-forge/linux-64/double-conversion-3.1.5-h9c3ff4c_2.tar.bz2#933cfc6739b21aa8c799b9a9e71f2bbe -https://conda.anaconda.org/conda-forge/linux-64/eigen-3.3.9-h4bd325d_1.tar.bz2#385d4d5ebf8a471805df2506de5bc2cb -https://conda.anaconda.org/conda-forge/linux-64/expat-2.4.1-h9c3ff4c_0.tar.bz2#16054ef3cb3ec5d8d29d08772662f65d -https://conda.anaconda.org/conda-forge/linux-64/fftw-3.3.9-nompi_h74d3f13_101.tar.bz2#29215ded4cf637130a7674f2a6874922 -https://conda.anaconda.org/conda-forge/linux-64/giflib-5.2.1-h36c2ea0_2.tar.bz2#626e68ae9cc5912d6adb79d318cf962d -https://conda.anaconda.org/conda-forge/linux-64/gmp-6.2.1-h58526e2_0.tar.bz2#b94cf2db16066b242ebd26db2facbd56 -https://conda.anaconda.org/conda-forge/linux-64/icu-64.2-he1b5a44_1.tar.bz2#8e881214a23508f1541eb7a3135d6fcb -https://conda.anaconda.org/conda-forge/linux-64/jpeg-9d-h36c2ea0_0.tar.bz2#ea02ce6037dbe81803ae6123e5ba1568 -https://conda.anaconda.org/conda-forge/linux-64/jsoncpp-1.8.4-hc9558a2_1002.tar.bz2#537e534c07b09a7409e71934878d25fd -https://conda.anaconda.org/conda-forge/linux-64/jxrlib-1.1-h7f98852_2.tar.bz2#8e787b08fe19986d99d034b839df2961 -https://conda.anaconda.org/conda-forge/linux-64/lame-3.100-h7f98852_1001.tar.bz2#60939f1940312bba87bb2e4da5032f99 -https://conda.anaconda.org/conda-forge/linux-64/lerc-2.2.1-h9c3ff4c_0.tar.bz2#ea833dcaeb9e7ac4fac521f1a7abec82 -https://conda.anaconda.org/conda-forge/linux-64/libaec-1.0.5-h9c3ff4c_0.tar.bz2#11edda2c5e2f8910bb7e9bc2bc24f4ba -https://conda.anaconda.org/conda-forge/linux-64/libbrotlicommon-1.0.9-h7f98852_5.tar.bz2#5d270722c33227ae39729426e9ef2d9a -https://conda.anaconda.org/conda-forge/linux-64/libdeflate-1.7-h7f98852_5.tar.bz2#10e242842cd30c59c12d79371dc0f583 -https://conda.anaconda.org/conda-forge/linux-64/libev-4.33-h516909a_1.tar.bz2#6f8720dff19e17ce5d48cfe7f3d2f0a3 -https://conda.anaconda.org/conda-forge/linux-64/libffi-3.2.1-he1b5a44_1007.tar.bz2#11389072d7d6036fd811c3d9460475cd -https://conda.anaconda.org/conda-forge/linux-64/libglu-9.0.0-he1b5a44_1001.tar.bz2#8208602aec4826053c116552369a394c -https://conda.anaconda.org/conda-forge/linux-64/libiconv-1.16-h516909a_0.tar.bz2#5c0f338a513a2943c659ae619fca9211 -https://conda.anaconda.org/conda-forge/linux-64/libogg-1.3.4-h7f98852_1.tar.bz2#6e8cc2173440d77708196c5b93771680 -https://conda.anaconda.org/conda-forge/linux-64/libopenblas-0.3.17-pthreads_h8fe5266_1.tar.bz2#7f96c04618e952e0f9d94d5e07545a71 -https://conda.anaconda.org/conda-forge/linux-64/libsanitizer-9.4.0-h79bfe98_8.tar.bz2#b1147a7a52cec2d07a67214008e94239 -https://conda.anaconda.org/conda-forge/linux-64/libsodium-1.0.18-h36c2ea0_1.tar.bz2#c3788462a6fbddafdb413a9f9053e58d -https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.32.1-h7f98852_1000.tar.bz2#772d69f030955d9646d3d0eaf21d859d -https://conda.anaconda.org/conda-forge/linux-64/libuv-1.42.0-h7f98852_0.tar.bz2#5b3e8d9da3e6a68a0e945c37eef6b472 -https://conda.anaconda.org/conda-forge/linux-64/libwebp-base-1.2.1-h7f98852_0.tar.bz2#90607c4c0247f04ec98b48997de71c1a -https://conda.anaconda.org/conda-forge/linux-64/libxkbcommon-0.10.0-he1b5a44_0.tar.bz2#78ccac2098edcd3673af2ceb3e95f932 -https://conda.anaconda.org/conda-forge/linux-64/libzopfli-1.0.3-h9c3ff4c_0.tar.bz2#c66fe2d123249af7651ebde8984c51c2 -https://conda.anaconda.org/conda-forge/linux-64/llvm-openmp-8.0.1-hc9558a2_0.tar.bz2#67590caab043d6d7ffc371f9cced7848 -https://conda.anaconda.org/conda-forge/linux-64/lz4-c-1.9.2-he1b5a44_3.tar.bz2#b2e54aad8640e7a877d2280d3ebfe85b -https://conda.anaconda.org/conda-forge/linux-64/metis-5.1.0-h58526e2_1006.tar.bz2#d099b812378b1e133c12e3b75167d83a -https://conda.anaconda.org/conda-forge/linux-64/mpich-3.4.2-h846660c_100.tar.bz2#0868d02349fc7e128d4bdc515b58dd7e -https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.2-h58526e2_4.tar.bz2#509f2a21c4a09214cd737a480dfd80c9 -https://conda.anaconda.org/conda-forge/linux-64/nettle-3.6-he412f7d_0.tar.bz2#f050099af540c1c960c813b06bca89ad -https://conda.anaconda.org/conda-forge/linux-64/nspr-4.30-h9c3ff4c_0.tar.bz2#e6dc1f8f6e0bcebe8e3d8a5bca258dbe -https://conda.anaconda.org/conda-forge/linux-64/openssl-1.1.1k-h7f98852_1.tar.bz2#2e92f95fd202f92a2114d5d86ce4dd83 -https://conda.anaconda.org/conda-forge/linux-64/pcre-8.45-h9c3ff4c_0.tar.bz2#c05d1820a6d34ff07aaaab7a9b7eddaa -https://conda.anaconda.org/conda-forge/linux-64/pkg-config-0.29.2-h36c2ea0_1008.tar.bz2#fbef41ff6a4c8140c30057466a1cdd47 -https://conda.anaconda.org/conda-forge/linux-64/pthread-stubs-0.4-h36c2ea0_1001.tar.bz2#22dad4df6e8630e8dff2428f6f6a7036 -https://conda.anaconda.org/conda-forge/linux-64/pugixml-1.10-he1b5a44_1.tar.bz2#ee18f3c361ae75fa1236da484c064576 -https://conda.anaconda.org/conda-forge/linux-64/rhash-1.4.1-h7f98852_0.tar.bz2#950d61884fdd45bfa8bbe479bb38cc18 -https://conda.anaconda.org/conda-forge/linux-64/snappy-1.1.8-he1b5a44_3.tar.bz2#83f1dc295c711bdbaf97e1f3bedf2f52 -https://conda.anaconda.org/conda-forge/linux-64/tbb-2020.2-h4bd325d_4.tar.bz2#850df84d9b8261b73102a8fce99f820f -https://conda.anaconda.org/conda-forge/linux-64/x264-1!161.3030-h7f98852_1.tar.bz2#4c9106542ee02c991b64b575ca4ea029 -https://conda.anaconda.org/conda-forge/linux-64/xorg-kbproto-1.0.7-h7f98852_1002.tar.bz2#4b230e8381279d76131116660f5a241a -https://conda.anaconda.org/conda-forge/linux-64/xorg-libice-1.0.10-h7f98852_0.tar.bz2#d6b0b50b49eccfe0be0373be628be0f3 -https://conda.anaconda.org/conda-forge/linux-64/xorg-libxau-1.0.9-h7f98852_0.tar.bz2#bf6f803a544f26ebbdc3bfff272eb179 -https://conda.anaconda.org/conda-forge/linux-64/xorg-libxdmcp-1.1.3-h7f98852_0.tar.bz2#be93aabceefa2fac576e971aef407908 -https://conda.anaconda.org/conda-forge/linux-64/xorg-xextproto-7.3.0-h7f98852_1002.tar.bz2#1e15f6ad85a7d743a2ac68dae6c82b98 -https://conda.anaconda.org/conda-forge/linux-64/xorg-xproto-7.0.31-h7f98852_1007.tar.bz2#b4a4381d54784606820704f7b5f05a15 -https://conda.anaconda.org/conda-forge/linux-64/xz-5.2.5-h516909a_1.tar.bz2#33f601066901f3e1a85af3522a8113f9 -https://conda.anaconda.org/conda-forge/linux-64/yaml-0.2.5-h516909a_0.tar.bz2#03a530e925414902547cf48da7756db8 -https://conda.anaconda.org/conda-forge/linux-64/zfp-0.5.5-h9c3ff4c_5.tar.bz2#a48a43fdc002f68cbc17b44681a02d42 -https://conda.anaconda.org/conda-forge/linux-64/zlib-1.2.11-h516909a_1010.tar.bz2#339cc5584e6d26bc73a875ba900028c3 -https://conda.anaconda.org/conda-forge/linux-64/boost-cpp-1.72.0-h8e57a91_0.tar.bz2#133a674da10caef4af883eaff85fd9a5 -https://conda.anaconda.org/conda-forge/linux-64/gcc_impl_linux-64-9.4.0-h03d3576_8.tar.bz2#69dd659dc50e30438eee8af75b40628f -https://conda.anaconda.org/conda-forge/linux-64/gettext-0.19.8.1-hf34092f_1004.tar.bz2#5582e1349bee4a25705adca745bf6845 -https://conda.anaconda.org/conda-forge/linux-64/gnutls-3.6.13-h85f3911_1.tar.bz2#7d1b6fff16c1431d96cb4934938799fd -https://conda.anaconda.org/conda-forge/linux-64/hdf4-4.2.15-h10796ff_3.tar.bz2#21a8d66dc17f065023b33145c42652fe -https://conda.anaconda.org/conda-forge/linux-64/libblas-3.9.0-11_linux64_openblas.tar.bz2#b8a498e2cac5746b808d5961cb584a13 -https://conda.anaconda.org/conda-forge/linux-64/libbrotlidec-1.0.9-h7f98852_5.tar.bz2#c34616b12f8350f63010e32bf181a772 -https://conda.anaconda.org/conda-forge/linux-64/libbrotlienc-1.0.9-h7f98852_5.tar.bz2#0e5f9325bb831b5fb9c454ea248d4a2d -https://conda.anaconda.org/conda-forge/linux-64/libedit-3.1.20191231-he28a2e2_2.tar.bz2#4d331e44109e3f0e19b4cb8f9b82f3e1 -https://conda.anaconda.org/conda-forge/linux-64/libllvm9-9.0.1-hf817b99_2.tar.bz2#624afc1fc8a84409fd607fb4082de00b -https://conda.anaconda.org/conda-forge/linux-64/libnghttp2-1.43.0-h812cca2_0.tar.bz2#1867d1e9658596b3fac8847a7702eef4 -https://conda.anaconda.org/conda-forge/linux-64/libpng-1.6.37-h21135ba_2.tar.bz2#b6acf807307d033d4b7e758b4f44b036 -https://conda.anaconda.org/conda-forge/linux-64/libssh2-1.9.0-ha56f1ee_6.tar.bz2#f0dfb86444df325e599dbc3f4c0a3f5b -https://conda.anaconda.org/conda-forge/linux-64/libvorbis-1.3.7-h9c3ff4c_0.tar.bz2#309dec04b70a3cc0f1e84a4013683bc0 -https://conda.anaconda.org/conda-forge/linux-64/libxcb-1.13-h7f98852_1003.tar.bz2#a9371e9e40aded194dcba1447606c9a1 -https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.9.10-hee79883_0.tar.bz2#0217b0926808b1adf93247bba489d733 -https://conda.anaconda.org/conda-forge/linux-64/mpfr-4.1.0-h9202a9a_0.tar.bz2#1fdba6a122363c956105a3a76e97cec0 -https://conda.anaconda.org/conda-forge/linux-64/openh264-2.1.1-h780b84a_0.tar.bz2#034a6f90f1bbc7ba11d04b84ec9d74c8 -https://conda.anaconda.org/conda-forge/linux-64/openmp-8.0.1-0.tar.bz2#b35241079152e5cc891c99368395b2c6 -https://conda.anaconda.org/conda-forge/linux-64/parmetis-4.0.3-h2a9763c_1005.tar.bz2#d32150ac4a75576e7d8043379e7f1059 -https://conda.anaconda.org/conda-forge/linux-64/readline-7.0-hf8c457e_1001.tar.bz2#ba9f8093574f89e5efc3e775ecc0d7d8 -https://conda.anaconda.org/conda-forge/linux-64/scotch-6.0.9-h3858553_1.tar.bz2#4fc20f28a6cf69eb3bde776b99df3a92 -https://conda.anaconda.org/conda-forge/linux-64/swig-4.0.2-hd3c618e_2.tar.bz2#9f7f2e8da6b6696430de9843884e8aa2 -https://conda.anaconda.org/conda-forge/linux-64/tbb-devel-2020.2-h4bd325d_4.tar.bz2#678ce1182271b5b039c78190c4a7fde9 -https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.11-h21135ba_0.tar.bz2#17e20f2d8435ffa2831fb5e328219e04 -https://conda.anaconda.org/conda-forge/linux-64/xorg-libsm-1.2.3-hd9c2040_1000.tar.bz2#9e856f78d5c80d5a78f61e72d1d473a3 -https://conda.anaconda.org/conda-forge/linux-64/zeromq-4.3.4-h9c3ff4c_0.tar.bz2#9105c7da67ebfb39ff08e2a8ea72bb71 -https://conda.anaconda.org/conda-forge/linux-64/zstd-1.4.8-hdf46e1d_0.tar.bz2#9e4943915c2bc43144da348d0c1b1e6b -https://conda.anaconda.org/conda-forge/linux-64/brotli-bin-1.0.9-h7f98852_5.tar.bz2#8062a4d3f435d91e569bd3d627c9b959 -https://conda.anaconda.org/conda-forge/linux-64/freetype-2.10.4-h0708190_1.tar.bz2#4a06f2ac2e5bfae7b6b245171c3f07aa -https://conda.anaconda.org/conda-forge/linux-64/gcc_linux-64-9.4.0-h391b98a_0.tar.bz2#52251093e6f936f1e8d33a5144446df6 -https://conda.anaconda.org/conda-forge/linux-64/gl2ps-1.4.2-h0708190_0.tar.bz2#438718bf8921ac70956d919d0e2cc487 -https://conda.anaconda.org/conda-forge/linux-64/gxx_impl_linux-64-9.4.0-h03d3576_8.tar.bz2#599f4227e43456c278f895d0bcfa1729 -https://conda.anaconda.org/conda-forge/linux-64/krb5-1.19.2-hcc1bbae_0.tar.bz2#81256fa86f9b65cf8ca726eeb3a7f283 -https://conda.anaconda.org/conda-forge/linux-64/libcblas-3.9.0-11_linux64_openblas.tar.bz2#59bf439337c9ec59297f701e4ee97e09 -https://conda.anaconda.org/conda-forge/linux-64/libclang-9.0.1-default_ha53f305_1.tar.bz2#cfa8e81d9d8c2861f56fb6461d6478b6 -https://conda.anaconda.org/conda-forge/linux-64/libglib-2.66.3-hbe7bbb4_0.tar.bz2#d5a09a9e981849b751cb75656b7302a0 -https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.9.0-11_linux64_openblas.tar.bz2#00d3680586af1f0689398b080e273cbb -https://conda.anaconda.org/conda-forge/linux-64/libtheora-1.1.1-h7f98852_1005.tar.bz2#1a7c35f56343b7e9e8db20b296c7566c -https://conda.anaconda.org/conda-forge/linux-64/libtiff-4.2.0-hdc55705_0.tar.bz2#f1406324f1d02fa26447a0a0f2dd0107 -https://conda.anaconda.org/conda-forge/linux-64/mpc-1.1.0-h04dde30_1009.tar.bz2#04a83b86c244fd8fe557a24e50b0028e -https://conda.anaconda.org/conda-forge/linux-64/ptscotch-6.0.9-h253636d_1.tar.bz2#fe2925307b60782284b8b54ed23612ae -https://repo.anaconda.com/pkgs/main/linux-64/sqlite-3.33.0-h62c20be_0.conda#c4d7dd5cb9eca27fdf96764c1f706cb5 -https://conda.anaconda.org/conda-forge/linux-64/xorg-libx11-1.7.2-h7f98852_0.tar.bz2#12a61e640b8894504326aadafccbb790 -https://conda.anaconda.org/conda-forge/linux-64/brotli-1.0.9-h7f98852_5.tar.bz2#ff132b5e255b58c9cf29db23cd642e0f -https://conda.anaconda.org/conda-forge/linux-64/ffmpeg-4.3.2-hca11adc_0.tar.bz2#b0781ef7f364374006913c8a3353e53c -https://conda.anaconda.org/conda-forge/linux-64/fontconfig-2.13.1-hba837de_1005.tar.bz2#fd3611672eb91bc9d24fd6fb970037eb -https://conda.anaconda.org/conda-forge/linux-64/gxx_linux-64-9.4.0-h0316aca_0.tar.bz2#9b71ed8fcd0671a8507706574d99035d -https://conda.anaconda.org/conda-forge/linux-64/hypre-2.18.2-hc98498a_1.tar.bz2#cd28e15f1af0eb05d01e1c675dc894c0 -https://conda.anaconda.org/conda-forge/linux-64/lcms2-2.12-hddcbb42_0.tar.bz2#797117394a4aa588de6d741b06fad80f -https://conda.anaconda.org/conda-forge/linux-64/libcurl-7.78.0-h2574ce0_0.tar.bz2#9c06cc5692dcd0b91699413fcc18405b -https://conda.anaconda.org/conda-forge/linux-64/nss-3.59-h2c00c37_0.tar.bz2#3b3b61a1c906531351be7a4bccda218f -https://conda.anaconda.org/conda-forge/linux-64/openjpeg-2.4.0-hb52868f_1.tar.bz2#b7ad78ad2e9ee155f59e6428406ee824 -https://repo.anaconda.com/pkgs/main/linux-64/python-3.7.4-h265db76_1.conda#05f5f232f6c0193b775f10fd9e5fe4b1 -https://conda.anaconda.org/conda-forge/linux-64/scalapack-2.0.2-hf659fdc_1009.tar.bz2#66565a49028a590c018ee135efa848da -https://conda.anaconda.org/conda-forge/linux-64/suitesparse-5.6.0-h717dc36_0.tar.bz2#d1592ce2e333ff3831e86b36c1e3cc32 -https://conda.anaconda.org/conda-forge/linux-64/superlu-5.2.2-h16cfea0_0.tar.bz2#0d224a62f153c29c55f9bfa8e8e521d2 -https://conda.anaconda.org/conda-forge/linux-64/superlu_dist-6.2.0-h25dcc4a_4.tar.bz2#90dad5805512d246c3caaa1f2194add9 -https://conda.anaconda.org/conda-forge/linux-64/xorg-libxext-1.3.4-h7f98852_1.tar.bz2#536cc5db4d0a3ba0630541aec064b5e4 -https://conda.anaconda.org/conda-forge/linux-64/xorg-libxt-1.2.1-h7f98852_2.tar.bz2#60d6eec5273f1c9af096c10c268912e3 -https://conda.anaconda.org/conda-forge/noarch/appdirs-1.4.4-pyh9f0ad1d_0.tar.bz2#5f095bc6454094e96f146491fd03633b -https://conda.anaconda.org/conda-forge/noarch/async_generator-1.10-py_0.tar.bz2#d56c596e61b1c4952acf0a9920856c12 -https://conda.anaconda.org/conda-forge/noarch/attrs-21.2.0-pyhd8ed1ab_0.tar.bz2#d2e1c7f388ac403df7079b411c37cc50 -https://conda.anaconda.org/conda-forge/noarch/backcall-0.2.0-pyh9f0ad1d_0.tar.bz2#6006a6d08a3fa99268a2681c7fb55213 -https://conda.anaconda.org/conda-forge/noarch/backports-1.0-py_2.tar.bz2#0da16b293affa6ac31812376f8eb79dd -https://conda.anaconda.org/conda-forge/linux-64/brunsli-0.1-h9c3ff4c_0.tar.bz2#c1ac6229d0bfd14f8354ff9ad2a26cad -https://conda.anaconda.org/conda-forge/noarch/cached_property-1.5.2-pyha770c72_1.tar.bz2#576d629e47797577ab0f1b351297ef4a -https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-2.0.0-pyhd8ed1ab_0.tar.bz2#4a57e24d5b759893615c05926b7b5fb9 -https://conda.anaconda.org/conda-forge/noarch/cloudpickle-1.6.0-py_0.tar.bz2#76d764d8881719e305f6fa368dc2b65e -https://conda.anaconda.org/conda-forge/linux-64/cmake-3.19.6-h3020d66_0.tar.bz2#2132517a0debf8040823ccf50fcfa244 -https://conda.anaconda.org/conda-forge/linux-64/curl-7.78.0-hea6ffbf_0.tar.bz2#89c45ff3044b2ddcd7689972e675c189 -https://conda.anaconda.org/conda-forge/noarch/decorator-5.0.9-pyhd8ed1ab_0.tar.bz2#0ae9cca42e37b5ce6267c2a2b1383546 -https://conda.anaconda.org/conda-forge/noarch/defusedxml-0.7.1-pyhd8ed1ab_0.tar.bz2#961b3a227b437d82ad7054484cfa71b2 -https://conda.anaconda.org/conda-forge/noarch/entrypoints-0.3-pyhd8ed1ab_1003.tar.bz2#bbf9a201f6ce99a506f4955374d9a9f4 -https://conda.anaconda.org/conda-forge/noarch/fsspec-2021.7.0-pyhd8ed1ab_0.tar.bz2#84fdd43802084b7c414db36b33538ea3 -https://conda.anaconda.org/conda-forge/linux-64/glew-2.1.0-h9c3ff4c_2.tar.bz2#fb05eb5c47590b247658243d27fc32f1 -https://conda.anaconda.org/conda-forge/linux-64/glib-2.66.3-h58526e2_0.tar.bz2#62c2e5c84f6cdc7ded2307ef9c30dc8c -https://conda.anaconda.org/conda-forge/linux-64/hdf5-1.10.6-mpi_mpich_h996c276_1014.tar.bz2#6af2e2e4dfb0ef36c35042cd69a1599d -https://conda.anaconda.org/conda-forge/noarch/idna-3.1-pyhd3deb0d_0.tar.bz2#9c9aea4b8391264477df484f798562d0 -https://conda.anaconda.org/conda-forge/noarch/ipython_genutils-0.2.0-py_1.tar.bz2#5071c982548b3a20caf70462f04f5287 -https://conda.anaconda.org/conda-forge/noarch/json5-0.9.5-pyh9f0ad1d_0.tar.bz2#10759827a94e6b14996e81fb002c0bda -https://conda.anaconda.org/conda-forge/noarch/jupyterlab_widgets-1.0.0-pyhd8ed1ab_1.tar.bz2#f8da92114c8fbe1d951b0efaf54dd14b -https://conda.anaconda.org/conda-forge/noarch/locket-0.2.0-py_2.tar.bz2#709e8671651c7ec3d1ad07800339ff1d -https://conda.anaconda.org/conda-forge/noarch/mpmath-1.2.1-pyhd8ed1ab_0.tar.bz2#9b06ebbd24f7c60ba5a29117c528514e -https://conda.anaconda.org/conda-forge/linux-64/mumps-mpi-5.2.1-hd6b9cac_10.tar.bz2#5de084e35937cf3b2b8f04cd0643a5b9 -https://conda.anaconda.org/conda-forge/noarch/nest-asyncio-1.5.1-pyhd8ed1ab_0.tar.bz2#47a51a5b8f9cc41004c8d7bd88b62447 -https://conda.anaconda.org/conda-forge/noarch/olefile-0.46-pyh9f0ad1d_1.tar.bz2#0b2e68acc8c78c8cc392b90983481f58 -https://conda.anaconda.org/conda-forge/noarch/pandocfilters-1.4.2-py_1.tar.bz2#ba6f4a308f1ea22abe1d72e72544af76 -https://conda.anaconda.org/conda-forge/noarch/parso-0.8.2-pyhd8ed1ab_0.tar.bz2#fb40b157bd62b457a1cc82527b63f0b0 -https://conda.anaconda.org/conda-forge/noarch/pickleshare-0.7.5-py_1003.tar.bz2#415f0ebb6198cc2801c73438a9fb5761 -https://conda.anaconda.org/conda-forge/linux-64/proj-7.1.1-h966b41f_3.tar.bz2#efb5863ec167964c9fe01b2a12f2c417 -https://conda.anaconda.org/conda-forge/noarch/prometheus_client-0.11.0-pyhd8ed1ab_0.tar.bz2#01f530bf82d9f589c2087b8c347d5e29 -https://conda.anaconda.org/conda-forge/noarch/ptyprocess-0.7.0-pyhd3deb0d_0.tar.bz2#359eeb6536da0e687af562ed265ec263 -https://conda.anaconda.org/conda-forge/noarch/pycparser-2.20-pyh9f0ad1d_2.tar.bz2#aa798d50ffd182a0f6f31478c7f434f6 -https://conda.anaconda.org/conda-forge/noarch/pyparsing-2.4.7-pyh9f0ad1d_0.tar.bz2#626c4f20d5bf06dcec9cf2eaa31725c7 -https://conda.anaconda.org/conda-forge/linux-64/python_abi-3.7-2_cp37m.tar.bz2#afff88bf9a7048da740c70aeb8cdbb82 -https://conda.anaconda.org/conda-forge/noarch/pytz-2021.1-pyhd8ed1ab_0.tar.bz2#3af2e9424d5eb0063824a3f9b850d411 -https://conda.anaconda.org/conda-forge/noarch/scooby-0.5.7-pyhd8ed1ab_0.tar.bz2#28afd49bf7257847fe2d2c816c5649c7 -https://conda.anaconda.org/conda-forge/noarch/send2trash-1.8.0-pyhd8ed1ab_0.tar.bz2#edab14119efe85c3bf131ad747e9005c -https://conda.anaconda.org/conda-forge/noarch/six-1.16.0-pyh6c4a22f_0.tar.bz2#e5f25f8dbc060e9a8d912e432202afc2 -https://conda.anaconda.org/conda-forge/noarch/testpath-0.5.0-pyhd8ed1ab_0.tar.bz2#53b57d6a468bebc7cef1253b177a5e9e -https://conda.anaconda.org/conda-forge/noarch/toolz-0.11.1-py_0.tar.bz2#d1e66b58cb00b3817ad9f05eec098c00 -https://conda.anaconda.org/conda-forge/noarch/typing_extensions-3.10.0.0-pyha770c72_0.tar.bz2#67c0cba6533b641f28946d7c16f361c8 -https://conda.anaconda.org/conda-forge/noarch/webencodings-0.5.1-py_1.tar.bz2#3563be4c5611a44210d9ba0c16113136 -https://conda.anaconda.org/conda-forge/noarch/wheel-0.37.0-pyhd8ed1ab_1.tar.bz2#3aa2c3e25dd361b453d010388b9cdff1 -https://conda.anaconda.org/conda-forge/noarch/zipp-3.5.0-pyhd8ed1ab_0.tar.bz2#f9dd05a5ed6b81c91f097e3739107a74 -https://conda.anaconda.org/conda-forge/noarch/babel-2.9.1-pyh44b312d_0.tar.bz2#74136ed39bfea0832d338df1e58d013e -https://conda.anaconda.org/conda-forge/noarch/cached-property-1.5.2-hd8ed1ab_1.tar.bz2#9b347a7ec10940d3f7941ff6c460b551 -https://conda.anaconda.org/conda-forge/linux-64/certifi-2021.5.30-py37h89c1867_0.tar.bz2#105f18ae8597a5f4d4e3188bcb06c796 -https://conda.anaconda.org/conda-forge/linux-64/cffi-1.14.4-py37h11fe52a_0.tar.bz2#2640988a30e6b84da411402a8cdeb9f6 -https://conda.anaconda.org/conda-forge/linux-64/chardet-4.0.0-py37h89c1867_1.tar.bz2#f4fbd4721b80f0d6b53b3a3374914068 -https://conda.anaconda.org/conda-forge/noarch/cycler-0.10.0-py_2.tar.bz2#f6d7c7e6d8f42cbbec7e07a8d879f91c -https://conda.anaconda.org/conda-forge/linux-64/cython-0.29.24-py37hcd2ae1e_0.tar.bz2#254a23562f74201cd69ff2df5368c960 -https://conda.anaconda.org/conda-forge/linux-64/cytoolz-0.11.0-py37h5e8e339_3.tar.bz2#2e89a6f3baf5eeb13763f61ea3d0601f -https://conda.anaconda.org/conda-forge/linux-64/dbus-1.13.6-hfdff14a_1.tar.bz2#4caaca6356992ee545080c7d7193b5a3 -https://conda.anaconda.org/conda-forge/linux-64/debugpy-1.4.1-py37hcd2ae1e_0.tar.bz2#2fe9a412db79e302782f7ed9e18c02dd -https://conda.anaconda.org/conda-forge/linux-64/gmpy2-2.1.0b5-py37h025e8b9_0.tar.bz2#fa4d28439beb0a3d44ca6cfe3b7150a9 -https://conda.anaconda.org/conda-forge/linux-64/gstreamer-1.14.5-h36ae1b5_2.tar.bz2#00084ab2657be5bf0ba0757ccde797ef -https://conda.anaconda.org/conda-forge/linux-64/importlib-metadata-4.6.4-py37h89c1867_0.tar.bz2#a5976c997c3f75aa8a10c7c08d8f8425 -https://conda.anaconda.org/conda-forge/linux-64/jedi-0.18.0-py37h89c1867_2.tar.bz2#5e95b453f199caec4dd1bf6002ae0ce2 -https://conda.anaconda.org/conda-forge/linux-64/kiwisolver-1.3.1-py37h2527ec5_1.tar.bz2#61149814e0ea71cb5b44881c65d25f7b -https://conda.anaconda.org/conda-forge/linux-64/libnetcdf-4.7.4-mpi_mpich_hdef422e_7.tar.bz2#7e1544ceea2c644e23140f2bb0b4c48e -https://conda.anaconda.org/conda-forge/linux-64/loguru-0.5.3-py37h89c1867_2.tar.bz2#8646e20db6f1dfbd5a61649d23da4949 -https://conda.anaconda.org/conda-forge/linux-64/markupsafe-2.0.1-py37h5e8e339_0.tar.bz2#90ad307f6997784664de956e09ec689e -https://conda.anaconda.org/conda-forge/linux-64/mistune-0.8.4-py37h5e8e339_1004.tar.bz2#2a5b3879a9268d1cad576f36a6b41349 -https://conda.anaconda.org/conda-forge/linux-64/mpi4py-3.1.1-py37h1e5cb63_0.tar.bz2#461f8ced885f85824887122c6fe7052e -https://conda.anaconda.org/conda-forge/linux-64/numpy-1.21.2-py37h31617e3_0.tar.bz2#c7e452d6e97ebbf447fa3d6ea8d59f02 -https://conda.anaconda.org/conda-forge/linux-64/orjson-3.6.3-py37h5e8e339_0.tar.bz2#bea5402dd9ef877e4a38dd848b02e9ed -https://conda.anaconda.org/conda-forge/noarch/packaging-21.0-pyhd8ed1ab_0.tar.bz2#45cfb8e482b5cce8f07c87e0e19a592c -https://conda.anaconda.org/conda-forge/noarch/partd-1.2.0-pyhd8ed1ab_0.tar.bz2#0c32f563d7f22e3a34c95cad8cc95651 -https://conda.anaconda.org/conda-forge/linux-64/petsc-3.13.6-h0f1f9f0_1.tar.bz2#cc7cb5e439de2de0f1d7ad4c1f656c0e -https://conda.anaconda.org/conda-forge/noarch/pexpect-4.8.0-pyh9f0ad1d_2.tar.bz2#5909e7b978141dd80d28dbf9de627827 -https://conda.anaconda.org/conda-forge/linux-64/pillow-8.2.0-py37h4600e1f_1.tar.bz2#8998270d7ebbb22261ab440176d3a5cf -https://conda.anaconda.org/conda-forge/linux-64/pkgconfig-1.5.5-py37h89c1867_0.tar.bz2#942134f34613e8c6167f230c9d94576c -https://conda.anaconda.org/conda-forge/linux-64/pybind11-2.6.1-py37hc928c03_0.tar.bz2#815e41a828e3ecf97ba3c16186478107 -https://conda.anaconda.org/conda-forge/linux-64/pyrsistent-0.17.3-py37h5e8e339_2.tar.bz2#829e0a0279d711a7b5aa67fe18c73672 -https://conda.anaconda.org/conda-forge/linux-64/pysocks-1.7.1-py37h89c1867_3.tar.bz2#bd069d59ee91a2e26552cd7bb4c64032 -https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.8.2-pyhd8ed1ab_0.tar.bz2#dd999d1cc9f79e67dbb855c8924c7984 -https://conda.anaconda.org/conda-forge/linux-64/pyyaml-5.4.1-py37h5e8e339_1.tar.bz2#16757160a88eedbed94774e41189a729 -https://conda.anaconda.org/conda-forge/linux-64/pyzmq-22.2.1-py37h336d617_0.tar.bz2#5e896e57dbd648ee3fad9726d8a90bb2 -https://conda.anaconda.org/conda-forge/linux-64/setuptools-57.4.0-py37h89c1867_0.tar.bz2#a7b2bc1c23e73d43d5dae86046eeae61 -https://conda.anaconda.org/conda-forge/linux-64/sniffio-1.2.0-py37h89c1867_1.tar.bz2#a48a71b3c0a40b5227056a7cb653d99d -https://conda.anaconda.org/conda-forge/linux-64/tornado-6.1-py37h5e8e339_1.tar.bz2#92449128c4639feae48d731ef2186099 -https://conda.anaconda.org/conda-forge/noarch/traitlets-5.0.5-py_0.tar.bz2#99618ee9ab1323e40f231acdab92fe60 -https://conda.anaconda.org/conda-forge/linux-64/websocket-client-0.57.0-py37h89c1867_4.tar.bz2#b7d10c52e3aaca152f4e16f90e40cd55 -https://conda.anaconda.org/conda-forge/linux-64/anyio-3.3.0-py37h89c1867_0.tar.bz2#899c3238a03ede12ecbe217e9bc13c3d -https://conda.anaconda.org/conda-forge/linux-64/argon2-cffi-20.1.0-py37h5e8e339_2.tar.bz2#5403470dcc6211e0ad72077616e2519d -https://conda.anaconda.org/conda-forge/noarch/backports.functools_lru_cache-1.6.4-pyhd8ed1ab_0.tar.bz2#c5b3edc62d6309088f4970b3eaaa65a6 -https://conda.anaconda.org/conda-forge/noarch/bleach-4.0.0-pyhd8ed1ab_0.tar.bz2#6b153c1c9e712f40e1f128476944996a -https://conda.anaconda.org/conda-forge/linux-64/brotlipy-0.7.0-py37h5e8e339_1001.tar.bz2#871eed4ba322e7b3f200956a096b34e7 -https://conda.anaconda.org/conda-forge/linux-64/cftime-1.5.0-py37h6f94858_0.tar.bz2#e252867ed3798d946b16576a575ccaa6 -https://conda.anaconda.org/conda-forge/linux-64/cryptography-3.4.7-py37h5d9358c_0.tar.bz2#d811fb6a96ae0cf8c0a17457a8e67ff4 -https://conda.anaconda.org/conda-forge/noarch/dask-core-2021.8.1-pyhd8ed1ab_0.tar.bz2#e42f775ec0e7b8ef9adc9384e0918345 -https://conda.anaconda.org/conda-forge/linux-64/fenics-dijitso-2019.1.0-py37h89c1867_21.tar.bz2#d99d23333eb0ee9ec3a02b55ca5319a2 -https://conda.anaconda.org/conda-forge/linux-64/fenics-ufl-2019.1.0-py37h89c1867_21.tar.bz2#33826733d6a20e831eefd168c335e58c -https://conda.anaconda.org/conda-forge/linux-64/gst-plugins-base-1.14.5-h0935bb2_2.tar.bz2#eb125ee86480e00a4a1ed45a577c3311 -https://conda.anaconda.org/conda-forge/linux-64/h5py-3.3.0-nompi_py37ha3df211_100.tar.bz2#36c9e9d4aae5375965a953c749cd80b8 -https://conda.anaconda.org/conda-forge/linux-64/imagecodecs-2021.1.11-py37h70f1e17_0.tar.bz2#d0fb924aff5fafb9a5f4f634507db0cc -https://conda.anaconda.org/conda-forge/noarch/imageio-2.9.0-py_0.tar.bz2#62ad9e579278e777d4abaa8c9312b6a7 -https://conda.anaconda.org/conda-forge/noarch/importlib_metadata-4.6.4-hd8ed1ab_0.tar.bz2#27ed39c0be1e9f66bf1336d013db842f -https://conda.anaconda.org/conda-forge/noarch/jinja2-3.0.1-pyhd8ed1ab_0.tar.bz2#c647e77921fd3e245cdcc5b2d451a0f8 -https://conda.anaconda.org/conda-forge/noarch/jsonschema-3.2.0-pyhd8ed1ab_3.tar.bz2#66125e28711d8ffc04a207a2b170316d -https://conda.anaconda.org/conda-forge/linux-64/jupyter_core-4.7.1-py37h89c1867_0.tar.bz2#42202575ecb1cc9491d57a4ad25f14bb -https://conda.anaconda.org/conda-forge/linux-64/matplotlib-base-3.4.3-py37h1058ff1_0.tar.bz2#195872ca8597bfc155364851072344c4 -https://conda.anaconda.org/conda-forge/noarch/matplotlib-inline-0.1.2-pyhd8ed1ab_2.tar.bz2#0967e1db58b16e416464ca399f87df79 -https://conda.anaconda.org/conda-forge/noarch/networkx-2.5-py_0.tar.bz2#d836ad8453c22192357707026ca21653 -https://conda.anaconda.org/conda-forge/linux-64/petsc4py-3.13.0-py37h2d00a08_5.tar.bz2#7060cb0aec8c9a0da2a3d95684eb996a -https://conda.anaconda.org/conda-forge/noarch/pip-21.2.4-pyhd8ed1ab_0.tar.bz2#4104ada314dd5639ea36cc12bce0a2cd -https://conda.anaconda.org/conda-forge/noarch/pyevtk-1.4.1-pyh8a188c0_0.tar.bz2#78cd9abeb15a8129dd7b8aa79b3c3a31 -https://conda.anaconda.org/conda-forge/noarch/pygments-2.10.0-pyhd8ed1ab_0.tar.bz2#32bcce837f1316f1c3208118b6c5e5fc -https://conda.anaconda.org/conda-forge/linux-64/pywavelets-1.1.1-py37h902c9e0_3.tar.bz2#104648a5a091a493046a62704eef5c49 -https://conda.anaconda.org/conda-forge/linux-64/scipy-1.7.1-py37hf2a6cf1_0.tar.bz2#b727e3ad6b8821c7d75442d2f61c3113 -https://conda.anaconda.org/conda-forge/linux-64/slepc-3.13.4-h44d3fa2_2.tar.bz2#ed9c0ec8ddd94894b8fb7851e3fd7950 -https://conda.anaconda.org/conda-forge/linux-64/sympy-1.8-py37h89c1867_0.tar.bz2#8bc910daa625a591c8a21310f254bf38 -https://conda.anaconda.org/conda-forge/linux-64/terminado-0.11.1-py37h89c1867_0.tar.bz2#1f424770bcaa27cdcab117582ac3287a -https://conda.anaconda.org/conda-forge/noarch/transforms3d-0.3.1-py_0.tar.bz2#6da5577349701747d4241472f18a9e76 -https://conda.anaconda.org/conda-forge/linux-64/vtk-9.0.1-no_osmesa_py37h8af0cc8_102.tar.bz2#415ccde38d81f157a31c2f98c6a03e28 -https://conda.anaconda.org/conda-forge/noarch/argcomplete-1.12.3-pyhd8ed1ab_2.tar.bz2#b8152341fc3fc9880c6e1b9d188974e5 -https://conda.anaconda.org/conda-forge/linux-64/fenics-fiat-2019.1.0-py37h89c1867_21.tar.bz2#c34217546de9a841ca961c356b6a403e -https://conda.anaconda.org/conda-forge/noarch/jupyter_client-6.1.12-pyhd8ed1ab_0.tar.bz2#f58b38ddb9f94fa3cafea4ba2b17f93b -https://conda.anaconda.org/conda-forge/noarch/jupyterlab_pygments-0.1.2-pyh9f0ad1d_0.tar.bz2#2cbd910890bb328e8959246a1e16fac7 -https://conda.anaconda.org/conda-forge/noarch/nbformat-5.1.3-pyhd8ed1ab_0.tar.bz2#bafa5df6d4f8db69a4d197b4657127e7 -https://conda.anaconda.org/conda-forge/linux-64/netcdf4-1.5.6-nompi_py37hf7b6e46_102.tar.bz2#997d73753e8a379c2100deef4a590402 -https://conda.anaconda.org/conda-forge/noarch/pyopenssl-20.0.1-pyhd8ed1ab_0.tar.bz2#92371c25994d0f5d28a01c1fb75ebf86 -https://conda.anaconda.org/conda-forge/linux-64/qt-5.12.5-hd8c4c69_1.tar.bz2#0e105d4afe0c3c81c4fbd9937ec4f359 -https://conda.anaconda.org/conda-forge/linux-64/scikit-umfpack-0.3.2-py37h991202b_1004.tar.bz2#3d77c3a99ab9111392990c3c1667d12d -https://conda.anaconda.org/conda-forge/linux-64/slepc4py-3.13.0-py37h59d694f_2.tar.bz2#4c08f18be761f2b97c99a31bdc865a4b -https://conda.anaconda.org/conda-forge/noarch/tifffile-2021.3.17-pyhd8ed1ab_0.tar.bz2#9cfba5e3844f16a1e270fb65f3207b17 -https://conda.anaconda.org/conda-forge/noarch/wcwidth-0.2.5-pyh9f0ad1d_2.tar.bz2#5266fcd697043c59621fda522b3d78ee -https://conda.anaconda.org/conda-forge/linux-64/fenics-ffc-2019.1.0-py37h89c1867_21.tar.bz2#5668584bba19e9abfef0adabc772acae -https://conda.anaconda.org/conda-forge/noarch/meshio-4.4.6-pyhd8ed1ab_0.tar.bz2#2dbacee1b852eb3b40cbd69de84c49a0 -https://conda.anaconda.org/conda-forge/noarch/nbclient-0.5.4-pyhd8ed1ab_0.tar.bz2#66ea0ea89e4f657a8b85fa5bdfce60ac -https://conda.anaconda.org/conda-forge/noarch/prompt-toolkit-3.0.19-pyha770c72_0.tar.bz2#d6db5e598611b7e81a3d38498174e6e8 -https://conda.anaconda.org/conda-forge/linux-64/pyqt-5.12.3-py37h8685d9f_3.tar.bz2#586ccc655950a4e9e9958a460854a239 -https://conda.anaconda.org/conda-forge/noarch/urllib3-1.26.6-pyhd8ed1ab_0.tar.bz2#dea5b6d93cfbfbc2a253168ad05b3f89 -https://conda.anaconda.org/conda-forge/linux-64/fenics-libdolfin-2019.1.0-hde6d0a8_16.tar.bz2#c5eea03aff9303b14ed16e2c43a25cce -https://conda.anaconda.org/conda-forge/linux-64/ipython-7.26.0-py37h6531663_0.tar.bz2#0672bce6ed551b99a305246e77fc00a4 -https://conda.anaconda.org/conda-forge/linux-64/matplotlib-3.4.3-py37h89c1867_0.tar.bz2#c187b5e294bc645d400637518a7aa3ff -https://conda.anaconda.org/conda-forge/linux-64/nbconvert-6.1.0-py37h89c1867_0.tar.bz2#a355bea7573fe3668a047b5df69b7623 -https://conda.anaconda.org/conda-forge/noarch/pyvista-0.31.3-pyhd8ed1ab_0.tar.bz2#9447b68bea5c204d50fcbc7cb1fe6939 -https://conda.anaconda.org/conda-forge/noarch/requests-2.26.0-pyhd8ed1ab_0.tar.bz2#0ed2ccbde6db9dd5789068eb7194463f -https://conda.anaconda.org/conda-forge/linux-64/fenics-dolfin-2019.1.0-py37h61670bc_16.tar.bz2#9df0b24892fe54c2395670afb0fc6a00 -https://conda.anaconda.org/conda-forge/linux-64/ipykernel-6.2.0-py37h6531663_0.tar.bz2#877b925a69c6cc1e18e2284835097b37 -https://conda.anaconda.org/conda-forge/noarch/pooch-1.5.1-pyhd8ed1ab_0.tar.bz2#75ed39bc4a6554e53e8e82702c7762be -https://conda.anaconda.org/conda-forge/noarch/requests-unixsocket-0.2.0-py_0.tar.bz2#1e94a233d2f2c81b2bf11bd43a515fbe -https://conda.anaconda.org/conda-forge/noarch/jupyter_server-1.10.2-pyhd8ed1ab_0.tar.bz2#135cf0c8641b737c56462c4ead895402 -https://conda.anaconda.org/conda-forge/noarch/notebook-6.4.3-pyha770c72_0.tar.bz2#8839b1ff228b3f8ec735963b8eb9dec5 -https://conda.anaconda.org/conda-forge/linux-64/scikit-image-0.18.3-py37he8f5f7f_0.tar.bz2#51014c4f0882d3e3a16a05a32e52e109 -https://conda.anaconda.org/conda-forge/noarch/jupyterlab_server-2.7.2-pyhd8ed1ab_0.tar.bz2#ae33d7b5f820027928a44f870b695052 -https://conda.anaconda.org/conda-forge/noarch/nbclassic-0.3.1-pyhd8ed1ab_1.tar.bz2#aa4f94da9fafb5b774493b26b631ad3f -https://conda.anaconda.org/conda-forge/linux-64/widgetsnbextension-3.5.1-py37h89c1867_4.tar.bz2#274af17d64191a15d3899d5fdc4abc02 -https://conda.anaconda.org/conda-forge/noarch/ipywidgets-7.6.3-pyhd3deb0d_0.tar.bz2#536a9ed6d9e740f2b83d1a3c388e4388 -https://conda.anaconda.org/conda-forge/noarch/jupyterlab-3.1.8-pyhd8ed1ab_0.tar.bz2#e45e11d357e4bc204495ed77bf10e32f -https://conda.anaconda.org/conda-forge/noarch/ipycanvas-0.9.0-pyhd8ed1ab_0.tar.bz2#5554821dffdef93ec05ee2e9dae23380 -https://conda.anaconda.org/conda-forge/noarch/ipyevents-2.0.1-pyhd8ed1ab_0.tar.bz2#dbf0d139d191847dbf1e6aebec3d23f6 -https://conda.anaconda.org/conda-forge/noarch/ipympl-0.7.0-pyhd8ed1ab_0.tar.bz2#2ab6d9f0d8943fb66694748bbfae959b -https://conda.anaconda.org/conda-forge/noarch/ipyvtklink-0.2.1-pyhd8ed1ab_1.tar.bz2#0176ebd85fb77c95ef56d1674fba8a72 diff --git a/install/env/puma-env-mac.lock b/install/env/puma-env-mac.lock deleted file mode 100644 index df6cba7..0000000 --- a/install/env/puma-env-mac.lock +++ /dev/null @@ -1,224 +0,0 @@ -# Generated by conda-lock. -# platform: osx-64 -# env_hash: 8bd5a5bb1dc6410791c69a09ffc221812f285767c0594ccd237b2a947b73f6fc -@EXPLICIT -https://conda.anaconda.org/conda-forge/osx-64/bzip2-1.0.8-h0d85af4_4.tar.bz2#37edc4e6304ca87316e160f5ca0bd1b5 -https://conda.anaconda.org/conda-forge/osx-64/c-ares-1.17.2-h0d85af4_0.tar.bz2#133e6624e8c549a83f5350847d3e0a43 -https://conda.anaconda.org/conda-forge/osx-64/ca-certificates-2021.5.30-h033912b_0.tar.bz2#2377a0c58b5ffe92d70b7bdcd833e8ff -https://conda.anaconda.org/conda-forge/osx-64/jpeg-9d-hbcb3906_0.tar.bz2#ff6fba028f282f94ceb10597d58a56e8 -https://conda.anaconda.org/conda-forge/osx-64/libcxx-12.0.1-habf9029_0.tar.bz2#49c188a7f9c7c9ddabafc80cc5625bb7 -https://conda.anaconda.org/conda-forge/osx-64/libev-4.33-haf1e3a3_1.tar.bz2#79dc2be110b2a3d1e97ec21f691c50ad -https://conda.anaconda.org/conda-forge/osx-64/libiconv-1.16-haf1e3a3_0.tar.bz2#c5fab167412a52e491c8e11453ae016f -https://conda.anaconda.org/conda-forge/osx-64/libsodium-1.0.18-hbcb3906_1.tar.bz2#24632c09ed931af617fe6d5292919cab -https://conda.anaconda.org/conda-forge/osx-64/libuv-1.42.0-h0d85af4_0.tar.bz2#0893dc8db34a4fc7aa999f6be2c48f5c -https://conda.anaconda.org/conda-forge/osx-64/metis-5.1.0-h2e338ed_1006.tar.bz2#ed90f7784864e7c0580624ec3ed5534e -https://conda.anaconda.org/conda-forge/osx-64/mpi-1.0-mpich.tar.bz2#7316a634ed27146b42d28433ec3bc227 -https://conda.anaconda.org/conda-forge/osx-64/mumps-include-5.2.1-6.tar.bz2#f434d6da8acee72e9170065e1591b399 -https://conda.anaconda.org/conda-forge/osx-64/ncurses-6.2-h2e338ed_4.tar.bz2#9cef1910395d1543527583e73dba30f1 -https://conda.anaconda.org/conda-forge/osx-64/pandoc-2.14.1-h0d85af4_0.tar.bz2#e92dcbeab114699191c169e9afdf2c2e -https://conda.anaconda.org/conda-forge/osx-64/rhash-1.4.1-h35c211d_0.tar.bz2#0b9fe5873503310fa32d2c0a3afd57bc -https://conda.anaconda.org/conda-forge/osx-64/xz-5.2.5-haf1e3a3_1.tar.bz2#41116deb499e9bc58048c297d6403ce6 -https://conda.anaconda.org/conda-forge/osx-64/yaml-0.2.5-haf1e3a3_0.tar.bz2#84c2fc186995c25a43e86ed708065572 -https://conda.anaconda.org/conda-forge/osx-64/zlib-1.2.11-h7795811_1010.tar.bz2#7d39e47e16ed0107f37c7224d5b5be8b -https://conda.anaconda.org/conda-forge/osx-64/eigen-3.3.9-h926bf3e_1.tar.bz2#433fb0bf9c15fd24a449055a0a996762 -https://conda.anaconda.org/conda-forge/osx-64/expat-2.4.1-he49afe7_0.tar.bz2#61d8ae52fc518342e6e0891f2d2c4104 -https://conda.anaconda.org/conda-forge/osx-64/gmp-6.2.1-h2e338ed_0.tar.bz2#dedc96914428dae572a39e69ee2a392f -https://conda.anaconda.org/conda-forge/osx-64/hdf4-4.2.15-hefd3b78_3.tar.bz2#07bbe01a1cabdb9ec0d35524e09f4db4 -https://conda.anaconda.org/conda-forge/osx-64/icu-64.2-h6de7cb9_1.tar.bz2#98593e7221241d8e19fee197ac105b4d -https://conda.anaconda.org/conda-forge/osx-64/jsoncpp-1.8.4-ha1b3eb9_1002.tar.bz2#d51074b98c3ef49d9cd06d7f49006e34 -https://conda.anaconda.org/conda-forge/osx-64/libedit-3.1.20191231-h0678c8f_2.tar.bz2#6016a8a1d0e63cac3de2c352cd40208b -https://conda.anaconda.org/conda-forge/osx-64/libffi-3.2.1-hb1e8313_1007.tar.bz2#be8b6ba3b6710a89ab891bbed151659c -https://conda.anaconda.org/conda-forge/osx-64/libllvm9-9.0.1-h223d4b2_3.tar.bz2#1548efa3f9d92865a3a6bfad4176d8b9 -https://conda.anaconda.org/conda-forge/osx-64/libpng-1.6.37-h7cec526_2.tar.bz2#9e52521faba2b53269672628d34e1513 -https://conda.anaconda.org/conda-forge/osx-64/llvm-openmp-8.0.1-h770b8ee_0.tar.bz2#22981e6688ff84040427ecfbdb45825a -https://conda.anaconda.org/conda-forge/osx-64/lz4-c-1.8.3-h6de7cb9_1001.tar.bz2#bacc4bc848109b87398b5ae18e6c4e00 -https://conda.anaconda.org/conda-forge/osx-64/nspr-4.30-hcd9eead_0.tar.bz2#47c2bc33545b08de4d808fca615178c6 -https://conda.anaconda.org/conda-forge/osx-64/openssl-1.1.1k-h0d85af4_1.tar.bz2#74d8c1e0196f2a556638d54be56debc8 -https://conda.anaconda.org/conda-forge/osx-64/pcre-8.45-he49afe7_0.tar.bz2#0526850419e04ac003bc0b65a78dc4cc -https://conda.anaconda.org/conda-forge/osx-64/pkg-config-0.29.2-h31203cd_1008.tar.bz2#c72ece6dc1aba238da9104ee41a18111 -https://conda.anaconda.org/conda-forge/osx-64/readline-7.0-hcfe32e1_1001.tar.bz2#4dfbb0e22ab207236cdd49e2352cecd9 -https://conda.anaconda.org/conda-forge/osx-64/scotch-6.0.8-h703c93e_1.tar.bz2#f35a14b172ed59f8242d7b6afc221c28 -https://conda.anaconda.org/conda-forge/osx-64/tbb-2020.2-h940c156_4.tar.bz2#5b12427550a7a818ce9275ae5dcf6258 -https://conda.anaconda.org/conda-forge/osx-64/tk-8.6.11-hd798d34_0.tar.bz2#579405c0cc2780700a2fbe9778285bda -https://conda.anaconda.org/conda-forge/osx-64/zeromq-4.3.4-h1c7c35f_0.tar.bz2#2af55e3523e9210b2b2dff5855fb5382 -https://conda.anaconda.org/conda-forge/osx-64/boost-cpp-1.70.0-h75728bb_2.tar.bz2#8866632c2abb193dacf0dd9ddfd3f76b -https://conda.anaconda.org/conda-forge/osx-64/freetype-2.10.4-h4cff582_1.tar.bz2#5a136a432c6062362cd7990c514bd8d6 -https://conda.anaconda.org/conda-forge/osx-64/krb5-1.19.2-hcfbf3a7_0.tar.bz2#a690006b8fea5c7d9eccf30aa07bb5d9 -https://conda.anaconda.org/conda-forge/osx-64/libclang-9.0.1-default_he082bbe_1.tar.bz2#7ad9e50bdb5a8e30bd2309104bd3b7f5 -https://conda.anaconda.org/conda-forge/osx-64/libgfortran4-7.5.0-h1a10cd1_23.tar.bz2#c26272f23d01f8cde50ed0c776c0edb1 -https://conda.anaconda.org/conda-forge/osx-64/libnghttp2-1.43.0-h07e645a_0.tar.bz2#b4a9c405d47f3b120ed6cf86cc8a13aa -https://conda.anaconda.org/conda-forge/osx-64/libssh2-1.9.0-h52ee1ee_6.tar.bz2#42cebefd1fd127d1180e3df004a413b7 -https://conda.anaconda.org/conda-forge/osx-64/libxml2-2.9.10-h53d96d6_0.tar.bz2#18dab8184a9255bf6fcd55c69f94f3b1 -https://conda.anaconda.org/conda-forge/osx-64/mpfr-4.1.0-h0f52abe_0.tar.bz2#15648520501e6b444afa03e70255ea4b -https://conda.anaconda.org/conda-forge/osx-64/openmp-8.0.1-0.tar.bz2#3dbc076bd4314ddaa831fe6bbe19ee2a -https://repo.anaconda.com/pkgs/main/osx-64/sqlite-3.33.0-hffcf06c_0.conda#c1c74e72f33b4d1f3f9800e721e83019 -https://conda.anaconda.org/conda-forge/osx-64/swig-4.0.2-hce5123c_2.tar.bz2#2c2c9cdb0feab0a3f40ddecbd4a5ad44 -https://conda.anaconda.org/conda-forge/osx-64/zstd-1.4.4-hed8d7c8_2.tar.bz2#ad39133ba192dfe936b4dc03c2849d9d -https://conda.anaconda.org/conda-forge/osx-64/libcurl-7.78.0-hf45b732_0.tar.bz2#dbd0239d2c0aee6405a5466ad7cdf7ee -https://conda.anaconda.org/conda-forge/osx-64/libgfortran-4.0.0-7_5_0_h1a10cd1_23.tar.bz2#617b1e5089026c0a2fe551ecccd58a79 -https://repo.anaconda.com/pkgs/main/osx-64/libpq-12.2-h1b4eb34_1.conda#186bfaa1d73863ca597b3024ae0ee3e5 -https://conda.anaconda.org/conda-forge/osx-64/libtiff-4.1.0-ha78913b_3.tar.bz2#224de8f4c2e6e60fe0aafb3ed905e083 -https://conda.anaconda.org/conda-forge/osx-64/mpc-1.1.0-ha57cd0f_1009.tar.bz2#e97438cea7c25b9906edf9525f580674 -https://conda.anaconda.org/conda-forge/osx-64/nss-3.47-hc0980d9_0.tar.bz2#c4a8c66c0125d86fbde82cf965212917 -https://repo.anaconda.com/pkgs/main/osx-64/python-3.7.4-h359304d_1.conda#7c00442e64b073663fe708744feca5ec -https://conda.anaconda.org/conda-forge/noarch/appdirs-1.4.4-pyh9f0ad1d_0.tar.bz2#5f095bc6454094e96f146491fd03633b -https://conda.anaconda.org/conda-forge/noarch/async_generator-1.10-py_0.tar.bz2#d56c596e61b1c4952acf0a9920856c12 -https://conda.anaconda.org/conda-forge/noarch/attrs-21.2.0-pyhd8ed1ab_0.tar.bz2#d2e1c7f388ac403df7079b411c37cc50 -https://conda.anaconda.org/conda-forge/noarch/backcall-0.2.0-pyh9f0ad1d_0.tar.bz2#6006a6d08a3fa99268a2681c7fb55213 -https://conda.anaconda.org/conda-forge/noarch/backports-1.0-py_2.tar.bz2#0da16b293affa6ac31812376f8eb79dd -https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-2.0.0-pyhd8ed1ab_0.tar.bz2#4a57e24d5b759893615c05926b7b5fb9 -https://conda.anaconda.org/conda-forge/noarch/cloudpickle-1.6.0-py_0.tar.bz2#76d764d8881719e305f6fa368dc2b65e -https://conda.anaconda.org/conda-forge/osx-64/cmake-3.19.4-hdeeeba1_0.tar.bz2#40e8eef0a039d251ec1540a75c2e40d4 -https://conda.anaconda.org/conda-forge/osx-64/curl-7.78.0-hb861fe1_0.tar.bz2#439763cec96dd320cc36e3d4cf948093 -https://conda.anaconda.org/conda-forge/noarch/decorator-5.0.9-pyhd8ed1ab_0.tar.bz2#0ae9cca42e37b5ce6267c2a2b1383546 -https://conda.anaconda.org/conda-forge/noarch/defusedxml-0.7.1-pyhd8ed1ab_0.tar.bz2#961b3a227b437d82ad7054484cfa71b2 -https://conda.anaconda.org/conda-forge/noarch/entrypoints-0.3-pyhd8ed1ab_1003.tar.bz2#bbf9a201f6ce99a506f4955374d9a9f4 -https://conda.anaconda.org/conda-forge/osx-64/fftw-3.3.8-nompi_h9629793_1109.tar.bz2#741e66fe021b3278395902f278ca9611 -https://conda.anaconda.org/conda-forge/noarch/fsspec-2021.7.0-pyhd8ed1ab_0.tar.bz2#84fdd43802084b7c414db36b33538ea3 -https://conda.anaconda.org/conda-forge/noarch/idna-3.1-pyhd3deb0d_0.tar.bz2#9c9aea4b8391264477df484f798562d0 -https://conda.anaconda.org/conda-forge/noarch/ipython_genutils-0.2.0-py_1.tar.bz2#5071c982548b3a20caf70462f04f5287 -https://conda.anaconda.org/conda-forge/noarch/json5-0.9.5-pyh9f0ad1d_0.tar.bz2#10759827a94e6b14996e81fb002c0bda -https://conda.anaconda.org/conda-forge/noarch/jupyterlab_widgets-1.0.0-pyhd8ed1ab_1.tar.bz2#f8da92114c8fbe1d951b0efaf54dd14b -https://conda.anaconda.org/conda-forge/osx-64/lcms2-2.11-h11f7e16_1.tar.bz2#e51153c3a4a2455f2466ef4e5496c34d -https://conda.anaconda.org/conda-forge/osx-64/libopenblas-0.3.7-h3d69b6c_4.tar.bz2#1c66a224ff1bbd2248bee5027bb46e54 -https://conda.anaconda.org/conda-forge/noarch/locket-0.2.0-py_2.tar.bz2#709e8671651c7ec3d1ad07800339ff1d -https://conda.anaconda.org/conda-forge/osx-64/mpich-3.3.2-hd33e60e_5.tar.bz2#f0194a19091f0ca11b61a8e295fdd532 -https://conda.anaconda.org/conda-forge/noarch/mpmath-1.2.1-pyhd8ed1ab_0.tar.bz2#9b06ebbd24f7c60ba5a29117c528514e -https://conda.anaconda.org/conda-forge/noarch/nest-asyncio-1.5.1-pyhd8ed1ab_0.tar.bz2#47a51a5b8f9cc41004c8d7bd88b62447 -https://conda.anaconda.org/conda-forge/noarch/olefile-0.46-pyh9f0ad1d_1.tar.bz2#0b2e68acc8c78c8cc392b90983481f58 -https://conda.anaconda.org/conda-forge/noarch/pandocfilters-1.4.2-py_1.tar.bz2#ba6f4a308f1ea22abe1d72e72544af76 -https://conda.anaconda.org/conda-forge/noarch/parso-0.8.2-pyhd8ed1ab_0.tar.bz2#fb40b157bd62b457a1cc82527b63f0b0 -https://conda.anaconda.org/conda-forge/noarch/pickleshare-0.7.5-py_1003.tar.bz2#415f0ebb6198cc2801c73438a9fb5761 -https://conda.anaconda.org/conda-forge/noarch/prometheus_client-0.11.0-pyhd8ed1ab_0.tar.bz2#01f530bf82d9f589c2087b8c347d5e29 -https://conda.anaconda.org/conda-forge/noarch/ptyprocess-0.7.0-pyhd3deb0d_0.tar.bz2#359eeb6536da0e687af562ed265ec263 -https://conda.anaconda.org/conda-forge/noarch/pycparser-2.20-pyh9f0ad1d_2.tar.bz2#aa798d50ffd182a0f6f31478c7f434f6 -https://conda.anaconda.org/conda-forge/noarch/pyparsing-2.4.7-pyh9f0ad1d_0.tar.bz2#626c4f20d5bf06dcec9cf2eaa31725c7 -https://conda.anaconda.org/conda-forge/osx-64/python_abi-3.7-2_cp37m.tar.bz2#4b564389f52917cfe8fbc537284d42e6 -https://conda.anaconda.org/conda-forge/noarch/pytz-2021.1-pyhd8ed1ab_0.tar.bz2#3af2e9424d5eb0063824a3f9b850d411 -https://conda.anaconda.org/conda-forge/osx-64/qt-5.12.5-h514805e_3.tar.bz2#8c06142f187c16650ccf47fb4793369b -https://conda.anaconda.org/conda-forge/noarch/scooby-0.5.7-pyhd8ed1ab_0.tar.bz2#28afd49bf7257847fe2d2c816c5649c7 -https://conda.anaconda.org/conda-forge/noarch/send2trash-1.8.0-pyhd8ed1ab_0.tar.bz2#edab14119efe85c3bf131ad747e9005c -https://conda.anaconda.org/conda-forge/noarch/six-1.16.0-pyh6c4a22f_0.tar.bz2#e5f25f8dbc060e9a8d912e432202afc2 -https://conda.anaconda.org/conda-forge/noarch/testpath-0.5.0-pyhd8ed1ab_0.tar.bz2#53b57d6a468bebc7cef1253b177a5e9e -https://conda.anaconda.org/conda-forge/noarch/toolz-0.11.1-py_0.tar.bz2#d1e66b58cb00b3817ad9f05eec098c00 -https://conda.anaconda.org/conda-forge/noarch/typing_extensions-3.10.0.0-pyha770c72_0.tar.bz2#67c0cba6533b641f28946d7c16f361c8 -https://conda.anaconda.org/conda-forge/noarch/webencodings-0.5.1-py_1.tar.bz2#3563be4c5611a44210d9ba0c16113136 -https://conda.anaconda.org/conda-forge/noarch/wheel-0.37.0-pyhd8ed1ab_1.tar.bz2#3aa2c3e25dd361b453d010388b9cdff1 -https://conda.anaconda.org/conda-forge/noarch/zipp-3.5.0-pyhd8ed1ab_0.tar.bz2#f9dd05a5ed6b81c91f097e3739107a74 -https://conda.anaconda.org/conda-forge/osx-64/appnope-0.1.2-py37hf985489_1.tar.bz2#1bee6125d3ade317803d5358ea3f0e83 -https://conda.anaconda.org/conda-forge/noarch/babel-2.9.1-pyh44b312d_0.tar.bz2#74136ed39bfea0832d338df1e58d013e -https://conda.anaconda.org/conda-forge/osx-64/certifi-2021.5.30-py37hf985489_0.tar.bz2#0be45059d18a95220573963524676b1a -https://conda.anaconda.org/conda-forge/osx-64/cffi-1.14.4-py37hbddb872_0.tar.bz2#ef1cebc3cf59371c5845fee047097715 -https://conda.anaconda.org/conda-forge/osx-64/chardet-4.0.0-py37hf985489_1.tar.bz2#212f48113f4aa416eb58404fbece967b -https://conda.anaconda.org/conda-forge/noarch/cycler-0.10.0-py_2.tar.bz2#f6d7c7e6d8f42cbbec7e07a8d879f91c -https://conda.anaconda.org/conda-forge/osx-64/cython-0.29.24-py37hd8d24ac_0.tar.bz2#b47153f223d774ff026743339329dc80 -https://conda.anaconda.org/conda-forge/osx-64/cytoolz-0.11.0-py37h271585c_3.tar.bz2#4c5542b4ece2bbe20eefae2b431c4105 -https://conda.anaconda.org/conda-forge/osx-64/debugpy-1.4.1-py37hd8d24ac_0.tar.bz2#3b06b715642da8dab6835673d77aa285 -https://conda.anaconda.org/conda-forge/osx-64/future-0.18.2-py37hf985489_3.tar.bz2#5137794442657f0dbafb035a31627fc6 -https://conda.anaconda.org/conda-forge/osx-64/gmpy2-2.1.0b5-py37h60f582e_0.tar.bz2#36f5e544a885a293a06ca57bf4de3e7b -https://conda.anaconda.org/conda-forge/osx-64/hdf5-1.10.5-mpi_mpich_hd7fb7e8_1011.tar.bz2#9f8ae12fa3fbd61ef443222bf1aeefec -https://conda.anaconda.org/conda-forge/osx-64/importlib-metadata-4.6.4-py37hf985489_0.tar.bz2#ee3b038eac7e4430bebdc63cc840bc55 -https://conda.anaconda.org/conda-forge/osx-64/jedi-0.18.0-py37hf985489_2.tar.bz2#8cf41e3992c9d1ae8549dfaf03d4bc14 -https://conda.anaconda.org/conda-forge/osx-64/kiwisolver-1.3.1-py37h737db71_1.tar.bz2#9f21eaa3eff1f10def66b7d91d6fee7a -https://conda.anaconda.org/conda-forge/osx-64/libblas-3.8.0-14_openblas.tar.bz2#4fb639363cc2ac8b4df0fa79e0f67e47 -https://conda.anaconda.org/conda-forge/osx-64/markupsafe-2.0.1-py37h271585c_0.tar.bz2#e3488847e5c3bba390401e73a820a0d6 -https://conda.anaconda.org/conda-forge/osx-64/mistune-0.8.4-py37h271585c_1004.tar.bz2#5d4658291ea2b8afb0382857cd60c409 -https://conda.anaconda.org/conda-forge/osx-64/mpi4py-3.0.3-py37he3c3b00_4.tar.bz2#b95f571e5d54a8d3f14df41abd83f35d -https://conda.anaconda.org/conda-forge/osx-64/orjson-3.6.3-py37h13e996e_0.tar.bz2#ce74d7ae79aca86d2e9314390f41ca6c -https://conda.anaconda.org/conda-forge/noarch/packaging-21.0-pyhd8ed1ab_0.tar.bz2#45cfb8e482b5cce8f07c87e0e19a592c -https://conda.anaconda.org/conda-forge/osx-64/parmetis-4.0.3-hbc1d92b_1005.tar.bz2#68074e32aa39fa42f66779b6f863f199 -https://conda.anaconda.org/conda-forge/noarch/partd-1.2.0-pyhd8ed1ab_0.tar.bz2#0c32f563d7f22e3a34c95cad8cc95651 -https://conda.anaconda.org/conda-forge/noarch/pexpect-4.8.0-pyh9f0ad1d_2.tar.bz2#5909e7b978141dd80d28dbf9de627827 -https://conda.anaconda.org/conda-forge/osx-64/pillow-8.1.0-py37h40a97b9_1.tar.bz2#0ce56e9b15a71d30758ffc8b6d279b9b -https://conda.anaconda.org/conda-forge/osx-64/pkgconfig-1.5.5-py37hf985489_0.tar.bz2#1775243b3ff5bda452195c0c475574f5 -https://conda.anaconda.org/conda-forge/osx-64/ptscotch-6.0.8-h8c5ff5d_1.tar.bz2#df7cf53feac344bb0b9f55b064cbdcb2 -https://conda.anaconda.org/conda-forge/osx-64/pybind11-2.4.3-py37ha1cc60f_3.tar.bz2#1581554942dd2a882a44837707b89211 -https://conda.anaconda.org/conda-forge/osx-64/pyrsistent-0.17.3-py37h271585c_2.tar.bz2#517d0f4408cdbfff73b684acd8f383ec -https://conda.anaconda.org/conda-forge/osx-64/pysocks-1.7.1-py37hf985489_3.tar.bz2#02bf224638f91b6b695fec5de6bbd860 -https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.8.2-pyhd8ed1ab_0.tar.bz2#dd999d1cc9f79e67dbb855c8924c7984 -https://conda.anaconda.org/conda-forge/osx-64/pyyaml-5.4.1-py37h271585c_1.tar.bz2#1c6010ae5d10ce79382abed496553ae2 -https://conda.anaconda.org/conda-forge/osx-64/pyzmq-22.2.1-py37h8f778e5_0.tar.bz2#cc5d6f53a892eb26cb5af7e13a8dddf1 -https://conda.anaconda.org/conda-forge/osx-64/setuptools-57.4.0-py37hf985489_0.tar.bz2#0b62b639ed4465fb0a3970194751d49b -https://conda.anaconda.org/conda-forge/osx-64/sniffio-1.2.0-py37hf985489_1.tar.bz2#d2624002903acd9b87e73b436b18c7fe -https://conda.anaconda.org/conda-forge/osx-64/tornado-6.1-py37h271585c_1.tar.bz2#f4f12c1487879c702e2dcf02de36aaac -https://conda.anaconda.org/conda-forge/noarch/traitlets-5.0.5-py_0.tar.bz2#99618ee9ab1323e40f231acdab92fe60 -https://conda.anaconda.org/conda-forge/osx-64/websocket-client-0.57.0-py37hf985489_4.tar.bz2#b8d9e2ad187b18d0abd25441db9f4ac9 -https://conda.anaconda.org/conda-forge/osx-64/anyio-3.3.0-py37hf985489_0.tar.bz2#f2291d9fe7a5896811ea340fdf2096be -https://conda.anaconda.org/conda-forge/osx-64/argon2-cffi-20.1.0-py37h271585c_2.tar.bz2#94c660be4d18f5038af33d65f6e4b13b -https://conda.anaconda.org/conda-forge/noarch/backports.functools_lru_cache-1.6.4-pyhd8ed1ab_0.tar.bz2#c5b3edc62d6309088f4970b3eaaa65a6 -https://conda.anaconda.org/conda-forge/noarch/bleach-4.0.0-pyhd8ed1ab_0.tar.bz2#6b153c1c9e712f40e1f128476944996a -https://conda.anaconda.org/conda-forge/osx-64/brotlipy-0.7.0-py37h271585c_1001.tar.bz2#5c1d243f053931c9be18a1ca0aec419e -https://conda.anaconda.org/conda-forge/osx-64/cryptography-3.4.7-py37hce4a858_0.tar.bz2#3d8dba99e6bba580b947da6daf8b1d94 -https://conda.anaconda.org/conda-forge/noarch/dask-core-2021.8.1-pyhd8ed1ab_0.tar.bz2#e42f775ec0e7b8ef9adc9384e0918345 -https://conda.anaconda.org/conda-forge/noarch/importlib_metadata-4.6.4-hd8ed1ab_0.tar.bz2#27ed39c0be1e9f66bf1336d013db842f -https://conda.anaconda.org/conda-forge/noarch/jinja2-3.0.1-pyhd8ed1ab_0.tar.bz2#c647e77921fd3e245cdcc5b2d451a0f8 -https://conda.anaconda.org/conda-forge/noarch/jsonschema-3.2.0-pyhd8ed1ab_3.tar.bz2#66125e28711d8ffc04a207a2b170316d -https://conda.anaconda.org/conda-forge/osx-64/jupyter_core-4.7.1-py37hf985489_0.tar.bz2#a49ae78b4a221744cca02dfed08a990f -https://conda.anaconda.org/conda-forge/osx-64/libcblas-3.8.0-14_openblas.tar.bz2#13b63079044bf57e429f4ee014b77d5d -https://conda.anaconda.org/conda-forge/osx-64/liblapack-3.8.0-14_openblas.tar.bz2#14fd39f1808bbdd24a337681b99c99d0 -https://conda.anaconda.org/conda-forge/osx-64/libnetcdf-4.7.4-mpi_mpich_h4141d09_1.tar.bz2#b38a80e088f611fd555bf3296c0618a9 -https://conda.anaconda.org/conda-forge/noarch/matplotlib-inline-0.1.2-pyhd8ed1ab_2.tar.bz2#0967e1db58b16e416464ca399f87df79 -https://conda.anaconda.org/conda-forge/noarch/networkx-2.5-py_0.tar.bz2#d836ad8453c22192357707026ca21653 -https://conda.anaconda.org/conda-forge/noarch/pip-21.2.4-pyhd8ed1ab_0.tar.bz2#4104ada314dd5639ea36cc12bce0a2cd -https://conda.anaconda.org/conda-forge/noarch/pygments-2.10.0-pyhd8ed1ab_0.tar.bz2#32bcce837f1316f1c3208118b6c5e5fc -https://conda.anaconda.org/conda-forge/osx-64/sympy-1.8-py37hf985489_0.tar.bz2#69fb38205d0a097e36a2cc83d1bedb01 -https://conda.anaconda.org/conda-forge/osx-64/terminado-0.11.1-py37hf985489_0.tar.bz2#7ab59653666b807d4809ec7101fc6e54 -https://conda.anaconda.org/conda-forge/noarch/argcomplete-1.12.3-pyhd8ed1ab_2.tar.bz2#b8152341fc3fc9880c6e1b9d188974e5 -https://conda.anaconda.org/conda-forge/osx-64/hypre-2.18.2-hc9ba2bc_1.tar.bz2#07782be7867c4c12a5e7c3b245c1db1a -https://conda.anaconda.org/conda-forge/noarch/jupyter_client-6.1.12-pyhd8ed1ab_0.tar.bz2#f58b38ddb9f94fa3cafea4ba2b17f93b -https://conda.anaconda.org/conda-forge/noarch/jupyterlab_pygments-0.1.2-pyh9f0ad1d_0.tar.bz2#2cbd910890bb328e8959246a1e16fac7 -https://conda.anaconda.org/conda-forge/noarch/nbformat-5.1.3-pyhd8ed1ab_0.tar.bz2#bafa5df6d4f8db69a4d197b4657127e7 -https://conda.anaconda.org/conda-forge/osx-64/numpy-1.21.2-py37haefe36b_0.tar.bz2#31b2466e3763bf32651f26571e0f966f -https://conda.anaconda.org/conda-forge/noarch/pyopenssl-20.0.1-pyhd8ed1ab_0.tar.bz2#92371c25994d0f5d28a01c1fb75ebf86 -https://conda.anaconda.org/conda-forge/osx-64/scalapack-2.0.2-hb7119d5_1009.tar.bz2#f6d74e8a23001c75f28b475ee30e25e8 -https://conda.anaconda.org/conda-forge/osx-64/suitesparse-5.6.0-h0e59142_0.tar.bz2#49aad4f07783bec5cf116dfd32d3f99a -https://conda.anaconda.org/conda-forge/osx-64/superlu-5.2.2-h8e61ea7_0.tar.bz2#4764b770a094da4bcc1254b9029e2054 -https://conda.anaconda.org/conda-forge/osx-64/vtk-8.2.0-py37h91d6c75_213.tar.bz2#81a164703aca11234f4b93480ab5bb17 -https://conda.anaconda.org/conda-forge/noarch/wcwidth-0.2.5-pyh9f0ad1d_2.tar.bz2#5266fcd697043c59621fda522b3d78ee -https://conda.anaconda.org/conda-forge/osx-64/cftime-1.5.0-py37h238668a_0.tar.bz2#a45f6d03b65a9102279b3941aecb71ef -https://conda.anaconda.org/conda-forge/osx-64/fenics-dijitso-2019.1.0-py37hf985489_21.tar.bz2#8929bb86d2a0528cabbe59857c112d8c -https://conda.anaconda.org/conda-forge/osx-64/fenics-fiat-2019.1.0-py37hf985489_21.tar.bz2#8af0c0dacd6abaf671e62c784ce3acac -https://conda.anaconda.org/conda-forge/osx-64/fenics-ufl-2019.1.0-py37hf985489_21.tar.bz2#77a4cdc03498ec461fa3c7eebed6041a -https://conda.anaconda.org/conda-forge/osx-64/h5py-2.10.0-nompi_py37h106b333_102.tar.bz2#8fa08913638c541d3db8f3b2edbf1cbb -https://conda.anaconda.org/conda-forge/osx-64/imagecodecs-lite-2019.12.3-py37h37391d0_3.tar.bz2#5b1aa016ab9de817d4408dd343f9cc8d -https://conda.anaconda.org/conda-forge/noarch/imageio-2.9.0-py_0.tar.bz2#62ad9e579278e777d4abaa8c9312b6a7 -https://conda.anaconda.org/conda-forge/osx-64/matplotlib-base-3.4.3-py37h3147e9e_0.tar.bz2#6fd7855b0d52c813c2049b6ae74f95d4 -https://conda.anaconda.org/conda-forge/osx-64/mumps-mpi-5.2.1-hcf7f05f_6.tar.bz2#7614c28b5806b7799920e7162f11c823 -https://conda.anaconda.org/conda-forge/noarch/nbclient-0.5.4-pyhd8ed1ab_0.tar.bz2#66ea0ea89e4f657a8b85fa5bdfce60ac -https://conda.anaconda.org/conda-forge/noarch/prompt-toolkit-3.0.19-pyha770c72_0.tar.bz2#d6db5e598611b7e81a3d38498174e6e8 -https://conda.anaconda.org/conda-forge/noarch/pyevtk-1.4.1-pyh8a188c0_0.tar.bz2#78cd9abeb15a8129dd7b8aa79b3c3a31 -https://conda.anaconda.org/conda-forge/osx-64/pywavelets-1.1.1-py37h37391d0_3.tar.bz2#1432c6ff1237725121ad82373480648c -https://conda.anaconda.org/conda-forge/osx-64/scipy-1.5.3-py37h04d6967_0.tar.bz2#66095208164c74a5a13cbeb686afa3fe -https://conda.anaconda.org/conda-forge/noarch/transforms3d-0.3.1-py_0.tar.bz2#6da5577349701747d4241472f18a9e76 -https://conda.anaconda.org/conda-forge/noarch/urllib3-1.26.6-pyhd8ed1ab_0.tar.bz2#dea5b6d93cfbfbc2a253168ad05b3f89 -https://conda.anaconda.org/conda-forge/osx-64/fenics-ffc-2019.1.0-py37hf985489_21.tar.bz2#d77c16b63d26385c459a453e604739b0 -https://conda.anaconda.org/conda-forge/osx-64/ipython-7.26.0-py37h4c52d7d_0.tar.bz2#c10324aa05cf34a8e55f9749c2f8556b -https://conda.anaconda.org/conda-forge/osx-64/matplotlib-3.4.3-py37hf985489_0.tar.bz2#ad7a524a7320854206b3e4781f5e60e3 -https://conda.anaconda.org/conda-forge/osx-64/nbconvert-6.1.0-py37hf985489_0.tar.bz2#3ea1d27528aff2bcd3c5d3096e55a45e -https://conda.anaconda.org/conda-forge/osx-64/netcdf4-1.5.3-mpi_mpich_py37hb599327_3.tar.bz2#1f1eef026949bd1e1ccca833df3717ed -https://conda.anaconda.org/conda-forge/osx-64/petsc-3.12.2-h6ceeb6d_2.tar.bz2#29aba2d2f517451137a004df37384f15 -https://conda.anaconda.org/conda-forge/noarch/requests-2.26.0-pyhd8ed1ab_0.tar.bz2#0ed2ccbde6db9dd5789068eb7194463f -https://conda.anaconda.org/conda-forge/osx-64/scikit-umfpack-0.3.2-py37h27a8955_1004.tar.bz2#b267fdc34625662acb9d9ea581973516 -https://conda.anaconda.org/conda-forge/noarch/tifffile-2020.6.3-py_0.tar.bz2#1fb771bb25b2eecbc73abf5143fa35bd -https://conda.anaconda.org/conda-forge/osx-64/ipykernel-6.2.0-py37h4c52d7d_0.tar.bz2#c7122346119b8544b38aac28d02990db -https://conda.anaconda.org/conda-forge/noarch/meshio-4.4.6-pyhd8ed1ab_0.tar.bz2#2dbacee1b852eb3b40cbd69de84c49a0 -https://conda.anaconda.org/conda-forge/osx-64/petsc4py-3.12.0-py37h833b260_4.tar.bz2#e31446b017e82d40cdfcc580ae456452 -https://conda.anaconda.org/conda-forge/noarch/pooch-1.5.1-pyhd8ed1ab_0.tar.bz2#75ed39bc4a6554e53e8e82702c7762be -https://conda.anaconda.org/conda-forge/noarch/requests-unixsocket-0.2.0-py_0.tar.bz2#1e94a233d2f2c81b2bf11bd43a515fbe -https://conda.anaconda.org/conda-forge/osx-64/slepc-3.12.1-hefb7033_2.tar.bz2#41ef32b9c9ddb0828725c53f45dcc771 -https://conda.anaconda.org/conda-forge/osx-64/fenics-libdolfin-2019.1.0-h765d0ea_8.tar.bz2#54385990e2264d03341e5d46048d7c76 -https://conda.anaconda.org/conda-forge/noarch/jupyter_server-1.10.2-pyhd8ed1ab_0.tar.bz2#135cf0c8641b737c56462c4ead895402 -https://conda.anaconda.org/conda-forge/noarch/notebook-6.4.3-pyha770c72_0.tar.bz2#8839b1ff228b3f8ec735963b8eb9dec5 -https://conda.anaconda.org/conda-forge/noarch/pyvista-0.31.3-pyhd8ed1ab_0.tar.bz2#9447b68bea5c204d50fcbc7cb1fe6939 -https://conda.anaconda.org/conda-forge/osx-64/scikit-image-0.18.3-py37h5b83a90_0.tar.bz2#8726124b30f6ce1bcdd846157e9d8655 -https://conda.anaconda.org/conda-forge/osx-64/slepc4py-3.12.0-py37h00bfe04_1.tar.bz2#4b7a087861861383ccf4de85a41453bc -https://conda.anaconda.org/conda-forge/osx-64/fenics-dolfin-2019.1.0-py37hb0736e2_8.tar.bz2#1d5283b5355148b08d2306c8d448268d -https://conda.anaconda.org/conda-forge/noarch/jupyterlab_server-2.7.2-pyhd8ed1ab_0.tar.bz2#ae33d7b5f820027928a44f870b695052 -https://conda.anaconda.org/conda-forge/noarch/nbclassic-0.3.1-pyhd8ed1ab_1.tar.bz2#aa4f94da9fafb5b774493b26b631ad3f -https://conda.anaconda.org/conda-forge/osx-64/widgetsnbextension-3.5.1-py37hf985489_4.tar.bz2#6d710b69d390deed8dbf74c8b60e3f09 -https://conda.anaconda.org/conda-forge/noarch/ipywidgets-7.6.3-pyhd3deb0d_0.tar.bz2#536a9ed6d9e740f2b83d1a3c388e4388 -https://conda.anaconda.org/conda-forge/noarch/jupyterlab-3.1.8-pyhd8ed1ab_0.tar.bz2#e45e11d357e4bc204495ed77bf10e32f -https://conda.anaconda.org/conda-forge/noarch/ipycanvas-0.9.0-pyhd8ed1ab_0.tar.bz2#5554821dffdef93ec05ee2e9dae23380 -https://conda.anaconda.org/conda-forge/noarch/ipyevents-2.0.1-pyhd8ed1ab_0.tar.bz2#dbf0d139d191847dbf1e6aebec3d23f6 -https://conda.anaconda.org/conda-forge/noarch/ipympl-0.7.0-pyhd8ed1ab_0.tar.bz2#2ab6d9f0d8943fb66694748bbfae959b -https://conda.anaconda.org/conda-forge/noarch/ipyvtklink-0.2.1-pyhd8ed1ab_1.tar.bz2#0176ebd85fb77c95ef56d1674fba8a72 diff --git a/install/env/puma_env.yml b/install/env/puma_env.yml deleted file mode 100644 index 32b819e..0000000 --- a/install/env/puma_env.yml +++ /dev/null @@ -1,25 +0,0 @@ -name: puma -channels: - - conda-forge - - defaults -dependencies: - - python - - pip - - numpy - - scipy - - cython - - scikit-image - - scikit-umfpack - - matplotlib - - pyevtk - - fenics-dolfin >=2019.1.0 - - pyvista - - ipyvtklink - - ipympl - - jupyterlab - - openmp - - fftw - - eigen - - swig - - cmake >=3.11.0 - - qt >=5.9.0 diff --git a/install/env/update_env.sh b/install/env/update_env.sh deleted file mode 100755 index e9f01fa..0000000 --- a/install/env/update_env.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/bash -cd "${0%/*}" || exit 1 # run from this directory -set -e # exit when any command fails -eval "$(conda shell.bash hook)" - -echo "Installing conda-lock" -echo -ne '\n' | conda install -c conda-forge conda-lock # install conda-lock in base - -if [ "$(uname)" == "Darwin" ]; then - conda-lock -f puma_env.yml -p osx-64 --filename-template "puma-env-mac.lock" -elif [ "$(expr substr $(uname -s) 1 5)" == "Linux" ]; then - conda-lock -f puma_env.yml -p linux-64 --filename-template "puma-env-linux.lock" -else - echo "Unrecongnized Operating System, PuMA cannot be installed." - exit 1 -fi diff --git a/install/environment.yml b/install/environment.yml new file mode 100644 index 0000000..834d4d1 --- /dev/null +++ b/install/environment.yml @@ -0,0 +1,33 @@ +name: puma +channels: + - conda-forge +dependencies: + - python =3.7.4 + + # pumapy + - numpy =1.21.2 + - scikit-image =0.18.3 + - scipy =1.7.1 + - matplotlib =3.4.3 + - pyevtk =1.4.1 + - pyvista =0.31.3 + + # puma cpp + - fftw =3.3.9 + - eigen =3.3.9 + - openmp =8.0.1 + - cmake =3.19.6 # needed >=3.11.0 + + # puma gui + - qt =5.12.5 # needed >=5.9.0 + + # texgen + - swig =4.0.2 + + # nice to have + - pip =21.2.4 + - cython =0.29.24 + - scikit-umfpack =0.3.2 + - jupyterlab =3.1.8 + - ipyvtklink =0.2.1 + - ipympl =0.7.0 diff --git a/install/gui_installer.sh b/install/gui_installer.sh index 1efbce4..9f28ff3 100755 --- a/install/gui_installer.sh +++ b/install/gui_installer.sh @@ -6,16 +6,8 @@ eval "$(conda shell.bash hook)" # creating puma conda env if it doesn't exist if [ ! -d "$(conda info --base)/envs/puma" ]; then echo "Creating puma conda environment." - - if [ "$(uname)" == "Darwin" ]; then - conda create --name puma --file env/puma-env-mac.lock - elif [ "$(expr substr $(uname -s) 1 5)" == "Linux" ]; then - conda create --name puma --file env/puma-env-linux.lock - else - echo "Unrecongnized Operating System, PuMA cannot be installed." - exit 1 - fi -fi; + conda env create +fi # this env activation only lasts inside bash script conda activate puma diff --git a/install/puma_installer.sh b/install/puma_installer.sh index 8a62af4..9065053 100755 --- a/install/puma_installer.sh +++ b/install/puma_installer.sh @@ -6,16 +6,8 @@ eval "$(conda shell.bash hook)" # creating puma conda env if it doesn't exist if [ ! -d "$(conda info --base)/envs/puma" ]; then echo "Creating puma conda environment." - - if [ "$(uname)" == "Darwin" ]; then - conda create --name puma --file env/puma-env-mac.lock - elif [ "$(expr substr $(uname -s) 1 5)" == "Linux" ]; then - conda create --name puma --file env/puma-env-linux.lock - else - echo "Unrecongnized Operating System, PuMA cannot be installed." - exit 1 - fi -fi; + conda env create +fi # this env activation only lasts inside bash script conda activate puma diff --git a/install/pumapy_installer.sh b/install/pumapy_installer.sh index 288e955..66985b7 100755 --- a/install/pumapy_installer.sh +++ b/install/pumapy_installer.sh @@ -6,16 +6,8 @@ eval "$(conda shell.bash hook)" # creating puma conda env if it doesn't exist if [ ! -d "$(conda info --base)/envs/puma" ]; then echo "Creating puma conda environment." - - if [ "$(uname)" == "Darwin" ]; then - conda create --name puma --file env/puma-env-mac.lock - elif [ "$(expr substr $(uname -s) 1 5)" == "Linux" ]; then - conda create --name puma --file env/puma-env-linux.lock - else - echo "Unrecongnized Operating System, PuMA cannot be installed." - exit 1 - fi -fi; + conda env create +fi # this env activation only lasts inside bash script conda activate puma diff --git a/install/texgen_installer.sh b/install/texgen_installer.sh index c30ec8d..8a7bb53 100755 --- a/install/texgen_installer.sh +++ b/install/texgen_installer.sh @@ -6,16 +6,8 @@ eval "$(conda shell.bash hook)" # creating puma conda env if it doesn't exist if [ ! -d "$(conda info --base)/envs/puma" ]; then echo "Creating puma conda environment." - - if [ "$(uname)" == "Darwin" ]; then - conda create --name puma --file env/puma-env-mac.lock - elif [ "$(expr substr $(uname -s) 1 5)" == "Linux" ]; then - conda create --name puma --file env/puma-env-linux.lock - else - echo "Unrecongnized Operating System, PuMA cannot be installed." - exit 1 - fi -fi; + conda env create +fi # this env activation only lasts inside bash script conda activate puma diff --git a/python/pumapy/__init__.py b/python/pumapy/__init__.py index 1fd686a..3ef50fe 100644 --- a/python/pumapy/__init__.py +++ b/python/pumapy/__init__.py @@ -20,10 +20,15 @@ from pumapy.utilities.isosurface import generate_isosurface from pumapy.utilities.property_maps import IsotropicConductivityMap, AnisotropicConductivityMap, ElasticityMap from pumapy.utilities.boundary_conditions import ConductivityBC, ElasticityBC +from pumapy.utilities.example_files import path_to_example_file, list_example_files # input/output from pumapy.io.input import import_3Dtiff, import_bin, import_weave_vtu, import_vti -from pumapy.io.output import export_vti, export_3Dtiff, export_bin, export_sparta_implicit_surfaces, export_stl, export_weave_vtu +from pumapy.io.output import export_vti, export_3Dtiff, export_bin, export_sparta_implicit_surfaces, export_stl +try: + from pumapy.io.export_texgen_weave import export_weave_vtu +except: + print_warning("WARNING: 'import TexGen.Core' failed: cannot use TexGen functions and pumapy.export_weave_vtu.") # material properties from pumapy.materialproperties.surfacearea import compute_surface_area @@ -34,10 +39,7 @@ from pumapy.materialproperties.tortuosity import compute_continuum_tortuosity from pumapy.materialproperties.elasticity import compute_elasticity, compute_stress_analysis from pumapy.materialproperties.radiation import compute_radiation, compute_extinction_coefficients -try: - from pumapy.materialproperties.permeability import compute_permeability -except: - print("WARNING: 'import dolfin' failed: cannot use compute_permeability.") +from pumapy.materialproperties.permeability import compute_permeability # filtering from pumapy.filters.filters import (filter_median, filter_gaussian, filter_edt, filter_mean, @@ -61,12 +63,3 @@ # segmentation from pumapy.segmentation.porespace import identify_porespace, fill_closed_pores - -# example data -from pumapy.data.path_to_example_file import path_to_example_file - -# add wrapped puma cpp functions -# try: -# import pumapy.utilities.libPuMA as cpp -# except ImportError: -# print("libPuMA not found, cannot use pumapy.cpp functions.") diff --git a/python/pumapy/data/50_artfibers.tif b/python/pumapy/data/50_artfibers.tif index 2852ca8..9aa3fce 100644 Binary files a/python/pumapy/data/50_artfibers.tif and b/python/pumapy/data/50_artfibers.tif differ diff --git a/python/pumapy/data/__init__.py b/python/pumapy/data/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/python/pumapy/data/path_to_example_file.py b/python/pumapy/data/path_to_example_file.py deleted file mode 100644 index 0ead225..0000000 --- a/python/pumapy/data/path_to_example_file.py +++ /dev/null @@ -1,17 +0,0 @@ -import os.path - - -def path_to_example_file(example_filename): - """ Path to example data that is installed with pumapy (used for testing and tutorial) - - :param example_filename: name of the example file (check python/pumapy/data for a list of example files) - :type example_filename: str - :return: path to the example file, which can be used to import it - :rtype: str - """ - file_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), example_filename) - - if not os.path.isfile(file_path): - raise Exception("Example file not found.") - - return file_path diff --git a/python/pumapy/filters/filters.py b/python/pumapy/filters/filters.py index 18d272d..595b29f 100644 --- a/python/pumapy/filters/filters.py +++ b/python/pumapy/filters/filters.py @@ -16,6 +16,15 @@ def filter_median(ws, size): :type size: int :return: True if successful, False otherwise. :rtype: bool + + :Example: + >>> import pumapy as puma + >>> ws = puma.generate_tpms((100, 100, 100), (0.02, 0.05), 0.201, 0) # generate tpms material + >>> ws.binarize_range((128, 255)) # binarize it so that it is only 1s and 0s + >>> ws_median = ws.copy() + >>> puma.filter_median(ws_median, size = 10) + >>> puma.compare_slices(ws, ws_median) # compare it + """ if not isinstance(ws, Workspace): raise Exception("Workspace must be passed.") @@ -39,6 +48,14 @@ def filter_gaussian(ws, sigma=1, apply_on_orientation=False): :type apply_on_orientation: bool, optional :return: True if successful, False otherwise. :rtype: bool + + :Example: + >>> import pumapy as puma + >>> ws = puma.generate_tpms((100, 100, 100), (0.02, 0.05), 0.201, 0) # generate tpms material + >>> ws.binarize_range((128, 255)) # binarize it so that it is only 1s and 0s + >>> ws_gaussian = ws.copy() + >>> puma.filter_gaussian(ws_gaussian, sigma=2, apply_on_orientation=False) + >>> puma.compare_slices(ws, ws_gaussian) # compare it """ if not isinstance(ws, Workspace): raise Exception("Workspace must be passed.") @@ -72,6 +89,14 @@ def filter_edt(ws, cutoff): :type cutoff: tuple(int, int) :return: True if successful, False otherwise. :rtype: bool + + :Example: + >>> import pumapy as puma + >>> ws = puma.generate_tpms((100, 100, 100), (0.02, 0.05), 0.201, 0) # generate tpms material + >>> ws.binarize_range((128, 255)) # binarize it so that it is only 1s and 0s + >>> ws_edt = ws.copy() + >>> puma.filter_edt(ws_edt, cutoff=(1,1)) + >>> puma.compare_slices(ws, ws_edt) #compare it """ if not isinstance(ws, Workspace): raise Exception("Workspace must be passed") @@ -92,6 +117,15 @@ def filter_mean(ws, size=5): :type size: int, optional :return: True if successful, False otherwise. :rtype: bool + + :Example: + >>> import pumapy as puma + >>> ws = puma.generate_tpms((100, 100, 100), (0.02, 0.05), 0.201, 0) # generate tpms material + >>> ws.binarize_range((128, 255)) # binarize it so that it is only 1s and 0s + >>> ws_mean = ws.copy() + >>> puma.filter_mean(ws_mean, size=10) + >>> puma.compare_slices(ws, ws_mean) #compare it + """ if not isinstance(ws, Workspace): raise Exception("Workspace must be passed") @@ -148,6 +182,14 @@ def filter_dilate(ws, cutoff, size=5): :type size: int, optional :return: True if successful, False otherwise. :rtype: bool + + :Example: + >>> import pumapy as puma + >>> ws = puma.generate_tpms((100, 100, 100), (0.02, 0.05), 0.201, 0) # generate tpms material + >>> ws.binarize_range((128, 255)) # binarize it so that it is only 1s and 0s + >>> ws_dilate = ws.copy() + >>> puma.filter_dilate(ws_dilate, cutoff=(1, 1), size=5) # dilating the copy + >>> puma.compare_slices(ws, ws_dilate) # compare it """ if not isinstance(ws, Workspace): raise Exception("Workspace must be passed") @@ -173,6 +215,15 @@ def filter_opening(ws, cutoff, size=5): :type size: int, optional :return: True if successful, False otherwise. :rtype: bool + + :Example: + >>> import pumapy as puma + >>> ws = puma.generate_tpms((100, 100, 100), (0.02, 0.05), 0.201, 0) # generate tpms material + >>> ws_opening = ws.copy() + >>> puma.filter_opening(ws_opening, cutoff=(128,255), size=3) + >>> ws_binary = ws.copy() + >>> ws_binary.binarize_range((128, 255)) + >>> puma.compare_slices(ws_binary, ws_opening) # compare it """ if not isinstance(ws, Workspace): raise Exception("Workspace must be passed") @@ -198,6 +249,15 @@ def filter_closing(ws, cutoff, size=5): :type size: int, optional :return: True if successful, False otherwise. :rtype: bool + + :Example: + >>> import pumapy as puma + >>> ws = puma.generate_tpms((100, 100, 100), (0.02, 0.05), 0.201, 0) # generate tpms material + >>> ws_closing = ws.copy() + >>> puma.filter_closing(ws.closing, cutoff=(128, 255), size=3) + >>> ws_binary = ws.copy() + >>> ws_binary.binarize_range((128, 255)) + >>> puma.compare_slices(ws_binary, ws_closing) # compare it """ if not isinstance(ws, Workspace): raise Exception("Workspace must be passed") diff --git a/python/pumapy/generation/random_fibers.py b/python/pumapy/generation/random_fibers.py index d7e9a99..494287e 100644 --- a/python/pumapy/generation/random_fibers.py +++ b/python/pumapy/generation/random_fibers.py @@ -11,59 +11,6 @@ import sys -def _generate_fibers(shape, radius, nfibers, phi=0, theta=90, length=None): - """ Generates random fibers given nfibers""" - - # error checks - shape = np.array(shape) - if np.size(shape) == 1: - shape = np.full((3, ), int(shape)) - elif np.size(shape) == 2: - raise Exception("Shape can only be 3D") - - H = np.sqrt(np.sum(np.square(shape))).astype(int) - if length is None: - length = 2 * H - R = min(int(length / 2), 2 * H) - - if (phi > 90) or (phi < 0): - raise Exception('phi_max must be betwen 0 and 90') - if (theta > 90) or (theta < 0): - raise Exception('theta_max must be betwen 0 and 90') - - im = np.zeros(shape, dtype=bool) - n = 0 - L = min(H, R) - - while n < nfibers: - x = np.random.rand(3) * (shape + 2 * L) - - phi_rand = (np.pi / 2 - np.pi * np.random.rand()) * phi / 90 - theta_rand = (np.pi / 2 - np.pi * np.random.rand()) * theta / 90 - x0 = R * np.array([np.cos(phi_rand) * np.cos(theta_rand), - np.cos(phi_rand) * np.sin(theta_rand), - np.sin(phi_rand)]) - [x0, x1] = [x + x0, x - x0] - - x0 = np.around(x0).astype(int) - x1 = np.around(x1).astype(int) - L = np.amax(np.absolute([[x1[0] - x0[0]], [x1[1] - x0[1]], [x1[2] - x0[2]]])) + 1 - crds = [np.rint(np.linspace(x0[0], x1[0], L)).astype(int), - np.rint(np.linspace(x0[1], x1[1], L)).astype(int), - np.rint(np.linspace(x0[2], x1[2], L)).astype(int)] - - lower = ~np.any(np.vstack(crds).T < [L, L, L], axis=1) - upper = ~np.any(np.vstack(crds).T >= shape + L, axis=1) - valid = upper * lower - if np.any(valid): - im[crds[0][valid] - L, crds[1][valid] - L, crds[2][valid] - L] = 1 - n += 1 - - im = np.array(im, dtype=bool) - dt = edt(~im) < radius - return ~dt - - def generate_random_fibers(shape, radius, nfibers=None, porosity=None, phi=0, theta=90, length=None, max_iter=3): """ Generates random fibers from number of fibers or porosity @@ -97,10 +44,17 @@ def generate_random_fibers(shape, radius, nfibers=None, porosity=None, phi=0, th :type max_iter: int, optional :return: random fibers domain :rtype: Workspace + + :Example: + >>> import pumapy as puma + >>> ws_fibers = puma.generate_random_fibers(shape=(200, 200, 200), radius=8, porosity=0.8, phi=90, theta=90, length=200) + >>> puma.render_contour(ws_fibers, cutoff=(1, 1)) + >>> ws_fibers = puma.generate_random_fibers(shape=(200, 200, 200), radius=8, nfibers=100, phi=90, theta=90, length=200) + >>> puma.render_contour(ws_fibers, cutoff=(1, 1)) """ # error checks - if nfibers is None and porosity is None: + if nfibers is None and porosity is None: raise Exception("'nfibers' and 'porosity' can't be both None") if max_iter < 3: raise Exception("Iterations must be >= 3") @@ -137,9 +91,62 @@ def generate_random_fibers(shape, radius, nfibers=None, porosity=None, phi=0, th vol_added = -np.log(porosity) * vol_total vol_fiber = vol_added / n_fibers_added - sys.stdout.write("\rGenerating fibers ... {:.1f}% ".format((i+1) / len(fractions) * 100)) + sys.stdout.write("\rGenerating fibers ... {:.1f}% ".format((i + 1) / len(fractions) * 100)) img = np.where(img, np.uint16(0), np.uint16(1)) img = Workspace.from_array(img.astype(np.uint16)) print("\nGenerated random fibers domain with porosity: {}".format(compute_volume_fraction(img, (0, 0)))) return img + + +def _generate_fibers(shape, radius, nfibers, phi=0, theta=90, length=None): + """ Generates random fibers given nfibers""" + + # error checks + shape = np.array(shape) + if np.size(shape) == 1: + shape = np.full((3, ), int(shape)) + elif np.size(shape) == 2: + raise Exception("Shape can only be 3D") + + H = np.sqrt(np.sum(np.square(shape))).astype(int) + if length is None: + length = 2 * H + R = min(int(length / 2), 2 * H) + + if (phi > 90) or (phi < 0): + raise Exception('phi_max must be betwen 0 and 90') + if (theta > 90) or (theta < 0): + raise Exception('theta_max must be betwen 0 and 90') + + im = np.zeros(shape, dtype=bool) + n = 0 + L = min(H, R) + + while n < nfibers: + x = np.random.rand(3) * (shape + 2 * L) + + phi_rand = (np.pi / 2 - np.pi * np.random.rand()) * phi / 90 + theta_rand = (np.pi / 2 - np.pi * np.random.rand()) * theta / 90 + x0 = R * np.array([np.cos(phi_rand) * np.cos(theta_rand), + np.cos(phi_rand) * np.sin(theta_rand), + np.sin(phi_rand)]) + [x0, x1] = [x + x0, x - x0] + + x0 = np.around(x0).astype(int) + x1 = np.around(x1).astype(int) + L = np.amax(np.absolute([[x1[0] - x0[0]], [x1[1] - x0[1]], [x1[2] - x0[2]]])) + 1 + crds = [np.rint(np.linspace(x0[0], x1[0], L)).astype(int), + np.rint(np.linspace(x0[1], x1[1], L)).astype(int), + np.rint(np.linspace(x0[2], x1[2], L)).astype(int)] + + lower = ~np.any(np.vstack(crds).T < [L, L, L], axis=1) + upper = ~np.any(np.vstack(crds).T >= shape + L, axis=1) + valid = upper * lower + if np.any(valid): + im[crds[0][valid] - L, crds[1][valid] - L, crds[2][valid] - L] = 1 + n += 1 + + im = np.array(im, dtype=bool) + dt = edt(~im) < radius + return ~dt diff --git a/python/pumapy/generation/random_spheres.py b/python/pumapy/generation/random_spheres.py index 1106852..7733065 100644 --- a/python/pumapy/generation/random_spheres.py +++ b/python/pumapy/generation/random_spheres.py @@ -18,6 +18,11 @@ def generate_random_spheres(size, diameter, porosity, allow_intersect=True): :type allow_intersect: bool :return: domain with random spheres with input diameter :rtype: Workspace + + :Example: + >>> import pumapy as puma + >>> ws_generated = puma.generate_random_spheres(size=(200,200,200), diameter=20, porosity=0.7) # Generating a workspace of randomly placed, intersecting spheres + >>> puma.render_contour(ws_generated, cutoff=(128, 255)) """ generator = GeneratorSpheres(size, diameter, porosity, allow_intersect) diff --git a/python/pumapy/generation/tpms.py b/python/pumapy/generation/tpms.py index 09cabe8..eeb412c 100644 --- a/python/pumapy/generation/tpms.py +++ b/python/pumapy/generation/tpms.py @@ -17,6 +17,18 @@ def generate_tpms(size, w, q, equation=0): :type equation: int :return: TPMS domain :rtype: Workspace + + :Example: + >>> import pumapy as puma + >>> size = (200, 200, 200) # size of the domain, in voxels. + >>> w = 0.08 # value of w in the equations above + >>> q = 0.2 # value of q in the equations above + >>> ws_eq0 = puma.generate_tpms(size, w, q, equation=0) + >>> ws_eq1 = puma.generate_tpms(size, w, q, equation=1) + >>> ws_eq2 = puma.generate_tpms(size, w, q, equation=2) + >>> puma.render_contour(ws_eq0, cutoff=(128, 255)) #visualize the workspace + >>> puma.render_contour(ws_eq1, cutoff=(128, 255)) + >>> puma.render_contour(ws_eq2, cutoff=(128, 255)) """ if isinstance(w, tuple): diff --git a/python/pumapy/io/export_texgen_weave.py b/python/pumapy/io/export_texgen_weave.py new file mode 100644 index 0000000..5205d16 --- /dev/null +++ b/python/pumapy/io/export_texgen_weave.py @@ -0,0 +1,67 @@ +from TexGen.Core import * + + +def export_weave_vtu(filename, weave, domain, max_dim_nvox, round_vox_up=True, export_orientation=True): + """ Exporting weave to vtu, to be read by pumapy + + :param filename: filepath and name + :type filename: string + :param weave: weave object, as defined in TexGen + :type weave: CTextile or child class of CTextile + :param domain: domain size object, as defined in TexGen + :type domain: CDomainPlanes + :param max_dim_nvox: number of voxels to add in the largest domain dimension + :type max_dim_nvox: int + :param round_vox_up: for the shorter dimensions, round number of voxels up (for +/-1 vox) + :type round_vox_up: bool + :param export_orientation: specify whether to export orientation + :type export_orientation: bool + :return: filename of weave exported (input filename + dimensions) + :rtype: string + """ + + if not isinstance(domain, CDomainPlanes): + raise Exception("Domain needs to be of CDomainPlanes type.") + if not isinstance(filename, str): + raise Exception("Filename has to be a string.") + if not path.exists(path.split(filename)[0]): + raise Exception("Directory " + path.split(filename)[0] + " not found.") + + min_bounds = XYZ() + max_bounds = XYZ() + domain.GetBoxLimits(min_bounds, max_bounds) + + weave.AssignDomain(CDomainPlanes(min_bounds, max_bounds)) + + lengths = np.array([max_bounds.x - min_bounds.x, max_bounds.y - min_bounds.y, max_bounds.z - min_bounds.z]) + max_len = np.max(lengths) + + mask = np.zeros(3, dtype=bool) + mask[lengths == max_len] = True + + voxel_length = max_len / float(max_dim_nvox) + + nvox = np.zeros(3, dtype=int) + nvox[mask] = max_dim_nvox + nvox[~mask] = (lengths[~mask] / voxel_length).astype(int) # truncates + + rem = np.zeros(3, dtype=float) + rem[~mask] = lengths[~mask] - voxel_length * nvox[~mask] + + if round_vox_up: + rem[~mask] = voxel_length - rem[~mask] + max_bounds = XYZ(max_bounds.x + rem[0], + max_bounds.y + rem[1], + max_bounds.z + rem[2]) + nvox[~mask] += 1 + else: + max_bounds = XYZ(max_bounds.x - rem[0], max_bounds.y - rem[1], max_bounds.z - rem[2]) + weave.AssignDomain(CDomainPlanes(min_bounds, max_bounds)) + + mesh = CRectangularVoxelMesh() + print("Exporting " + filename + ".vtu ... ", end='') + filename += "_" + str(nvox[0]) + "_" + str(nvox[1]) + "_" + str(nvox[2]) + mesh.SaveVoxelMesh(weave, filename, int(nvox[0]), int(nvox[1]), int(nvox[2]), False, export_orientation, + MATERIAL_CONTINUUM, 0, VTU_EXPORT) + print("Done") + return filename diff --git a/python/pumapy/io/input.py b/python/pumapy/io/input.py index 7171f84..1a31f3b 100644 --- a/python/pumapy/io/input.py +++ b/python/pumapy/io/input.py @@ -20,6 +20,11 @@ def import_3Dtiff(filename, voxel_length=1e-6, import_ws=True): :type import_ws: bool, optional :return: domain :rtype: Workspace or ndarray + + :Example: + >>> import pumapy as puma + >>> ws_tiff = puma.import_3Dtiff(puma.path_to_example_file("50_artfibers.tif"), 1.3e-6, import_ws=True) + >>> ws_tiff.get_shape() """ print("Importing " + filename + " ... ", end='') @@ -48,6 +53,10 @@ def import_bin(filename): :type filename: string :return: True if successful, False otherwise. :rtype: bool + + :Example: + >>> import pumapy as puma + >>> ws_binary = puma.import_bin(puma.path_to_example_file("fibers_with_orientation.pumapy")) """ print("Importing " + filename + " ... ", end='') @@ -73,6 +82,10 @@ def import_vti(filename, voxel_length=None, import_ws=True): :return: if import_ws is True, then it returns a Workspace. if import_ws is False, it returns a dictionary of ndarrays as {"name1": data1, "name2": data2 ...} :rtype: Workspace or dict(string: ndarray) + + :Example: + >>> import pumapy as puma + >>> ws_vtk = puma.import_vti(puma.path_to_example_file("fibers_with_orientation.vti")) """ print("Importing " + filename + " ... ", end='') diff --git a/python/pumapy/io/output.py b/python/pumapy/io/output.py index 35a0853..2fa8f80 100644 --- a/python/pumapy/io/output.py +++ b/python/pumapy/io/output.py @@ -5,7 +5,6 @@ from pumapy.utilities.workspace import Workspace from pumapy.utilities.logger import print_warning from pumapy.utilities.isosurface import generate_isosurface -from TexGen.Core import * from os import path @@ -20,6 +19,11 @@ def export_vti(filename, dict_data, voxel_length=None): :type voxel_length: float, optional :return: True if successful, False otherwise. :rtype: bool + + :Example: + >>> import pumapy as puma + >>> ws_vtk = puma.import_vti(puma.path_to_example_file("fibers_with_orientation.vti")) + >>> puma.export_vti("fibers_with_orientation.vti", ws_vtk) """ # error path checks @@ -89,6 +93,11 @@ def export_3Dtiff(filename, ws_or_nparray, to8bit=False): :type to8bit: bool, optional :return: True if successful, False otherwise. :rtype: bool + + :Example: + >>> import pumapy as puma + >>> ws_tiff = puma.import_3Dtiff(puma.path_to_example_file("50_artfibers.tif"), 1.3e-6, import_ws=True) + >>> puma.export_3Dtiff("50_artfibers.tif", ws_tiff) """ # error checks @@ -133,6 +142,11 @@ def export_bin(filename, ws): :type: Workspace :return: True if successful, False otherwise. :rtype: bool + + :Example: + >>> import pumapy as puma + >>> ws_binary = puma.import_bin(puma.path_to_example_file("fibers_with_orientation.pumapy")) + >>> puma.export_bin("fibers_with_orientation.vti", ws_binary) """ # error checks @@ -207,6 +221,11 @@ def export_stl(filename, ws, cutoff, flag_closed_edges=True, flag_gaussian=False :type flag_gaussian: bool, optional :return: True if successful, False otherwise. :rtype: bool + + :Example: + >>> import pumapy as puma + >>> ws_imported = puma.import_3Dtiff(puma.path_to_example_file("200_fiberform.tif"), 1.3e-6) + >>> puma.export_stl('200_fiberform', ws_imported, cutoff=(100, 255), flag_closed_edges=True) """ # error checks @@ -226,69 +245,3 @@ def export_stl(filename, ws, cutoff, flag_closed_edges=True, flag_gaussian=False mesh.save(filename, binary) print("Done") return True - - -def export_weave_vtu(filename, weave, domain, max_dim_nvox, round_vox_up=True, export_orientation=True): - """ Exporting weave to vtu, to be read by pumapy - - :param filename: filepath and name - :type filename: string - :param weave: weave object, as defined in TexGen - :type weave: CTextile or child class of CTextile - :param domain: domain size object, as defined in TexGen - :type domain: CDomainPlanes - :param max_dim_nvox: number of voxels to add in the largest domain dimension - :type max_dim_nvox: int - :param round_vox_up: for the shorter dimensions, round number of voxels up (for +/-1 vox) - :type round_vox_up: bool - :param export_orientation: specify whether to export orientation - :type export_orientation: bool - :return: filename of weave exported (input filename + dimensions) - :rtype: string - """ - - if not isinstance(domain, CDomainPlanes): - raise Exception("Domain needs to be of CDomainPlanes type.") - if not isinstance(filename, str): - raise Exception("Filename has to be a string.") - if not path.exists(path.split(filename)[0]): - raise Exception("Directory " + path.split(filename)[0] + " not found.") - - min_bounds = XYZ() - max_bounds = XYZ() - domain.GetBoxLimits(min_bounds, max_bounds) - - weave.AssignDomain(CDomainPlanes(min_bounds, max_bounds)) - - lengths = np.array([max_bounds.x - min_bounds.x, max_bounds.y - min_bounds.y, max_bounds.z - min_bounds.z]) - max_len = np.max(lengths) - - mask = np.zeros(3, dtype=bool) - mask[lengths == max_len] = True - - voxel_length = max_len / float(max_dim_nvox) - - nvox = np.zeros(3, dtype=int) - nvox[mask] = max_dim_nvox - nvox[~mask] = (lengths[~mask] / voxel_length).astype(int) # truncates - - rem = np.zeros(3, dtype=float) - rem[~mask] = lengths[~mask] - voxel_length * nvox[~mask] - - if round_vox_up: - rem[~mask] = voxel_length - rem[~mask] - max_bounds = XYZ(max_bounds.x + rem[0], - max_bounds.y + rem[1], - max_bounds.z + rem[2]) - nvox[~mask] += 1 - else: - max_bounds = XYZ(max_bounds.x - rem[0], max_bounds.y - rem[1], max_bounds.z - rem[2]) - weave.AssignDomain(CDomainPlanes(min_bounds, max_bounds)) - - mesh = CRectangularVoxelMesh() - print("Exporting " + filename + ".vtu ... ", end='') - filename += "_" + str(nvox[0]) + "_" + str(nvox[1]) + "_" + str(nvox[2]) - mesh.SaveVoxelMesh(weave, filename, int(nvox[0]), int(nvox[1]), int(nvox[2]), False, export_orientation, - MATERIAL_CONTINUUM, 0, VTU_EXPORT) - print("Done") - return filename diff --git a/python/pumapy/materialproperties/conductivity.py b/python/pumapy/materialproperties/conductivity.py index 6dd9f99..5489276 100644 --- a/python/pumapy/materialproperties/conductivity.py +++ b/python/pumapy/materialproperties/conductivity.py @@ -29,6 +29,17 @@ def compute_thermal_conductivity(workspace, cond_map, direction, side_bc='s', pr :type print_matrices: tuple(5 bools), optional :return: thermal conductivity, temperature field, flux :rtype: tuple(tuple(float, float, float), ndarray, ndarray) + + :Example: + >>> import pumapy as puma + >>> ws_fiberform = puma.import_3Dtiff(puma.path_to_example_file("200_fiberform.tif"), 1.3e-6) + >>> ws_fiberform.matrix = ws_fiberform.matrix[50:150, 50:150, 50:150] + >>> cond_map = puma.IsotropicConductivityMap() + >>> cond_map.add_material((0, 89), 0.0257) + >>> cond_map.add_material((90, 255), 12) + >>> k_eff_x, T_x, q_x = puma.compute_thermal_conductivity(ws_fiberform, cond_map, 'x', 's', tolerance=1e-2, solver_type='cg') + >>> print("Effective thermal conductivity tensor:") + >>> print(k_eff_x) """ if isinstance(cond_map, IsotropicConductivityMap): solver = IsotropicConductivity(workspace, cond_map, direction, side_bc, prescribed_bc, tolerance, maxiter, @@ -73,6 +84,17 @@ def compute_electrical_conductivity(workspace, cond_map, direction, side_bc='p', :type print_matrices: tuple(5 bools), optional :return: electrical conductivity, potential field, flux :rtype: tuple(tuple(float, float, float), ndarray, ndarray) + + :Example: + >>> import pumapy as puma + >>> ws_fiberform = puma.import_3Dtiff(puma.path_to_example_file("200_fiberform.tif"), 1.3e-6) + >>> ws_fiberform.matrix = ws_fiberform.matrix[50:150, 50:150, 50:150] + >>> cond_map = puma.IsotropicConductivityMap() + >>> cond_map.add_material((0, 89), 0.0257) + >>> cond_map.add_material((90, 255), 12) + >>> k_eff_x, P_x, q_x = puma.compute_electrical_conductivity(ws_fiberform, cond_map, 'x', 's', tolerance=1e-2, solver_type='cg') + >>> print("Effective electrical conductivity tensor:") + >>> print(k_eff_x) """ return compute_thermal_conductivity(workspace, cond_map, direction, side_bc, prescribed_bc, tolerance, maxiter, solver_type, display_iter, print_matrices) diff --git a/python/pumapy/materialproperties/elasticity.py b/python/pumapy/materialproperties/elasticity.py index 5b036b8..a7f7b7a 100644 --- a/python/pumapy/materialproperties/elasticity.py +++ b/python/pumapy/materialproperties/elasticity.py @@ -1,6 +1,5 @@ from pumapy.physicsmodels.mpsa_elasticity import Elasticity from pumapy.utilities.property_maps import ElasticityMap -import numpy as np def compute_elasticity(workspace, elast_map, direction, side_bc='p', prescribed_bc=None, tolerance=1e-4, @@ -29,6 +28,20 @@ def compute_elasticity(workspace, elast_map, direction, side_bc='p', prescribed_ :type print_matrices: tuple(5 ints), optional :return: elasticity, displacement field, direct stresses, shear stresses :rtype: tuple(tuple(6 floats), ndarray, ndarray, ndarray) + + :Example: + >>> import pumapy as puma + >>> export_name = 'halfmat' + >>> X = 20 + >>> Y = 20 + >>> Z = 20 + >>> ws = puma.Workspace.from_shape_value((X, Y, Z), 1) + >>> ws[int(X / 2):] = 2 + >>> elast_map = puma.ElasticityMap() + >>> elast_map.add_isotropic_material((1, 1), 200, 0.3) + >>> elast_map.add_isotropic_material((2, 2), 400, 0.1) + >>> C, u, s, t = puma.compute_elasticity(ws, elast_map, direction='x', side_bc='f', solver_type="direct") + >>> print(C) """ if isinstance(elast_map, ElasticityMap): solver = Elasticity(workspace, elast_map, direction, side_bc, prescribed_bc, tolerance, maxiter, diff --git a/python/pumapy/materialproperties/permeability.py b/python/pumapy/materialproperties/permeability.py index 8187e5d..0440d9d 100644 --- a/python/pumapy/materialproperties/permeability.py +++ b/python/pumapy/materialproperties/permeability.py @@ -1,49 +1,28 @@ -from pumapy.physicsmodels.fenics_stokes import Permeability +from pumapy.physicsmodels.fe_permeability import Permeability -def compute_permeability(workspace, direction, solid_cutoff, side_bc='fs', first_order=True, inf_sup=0.2, - pressure_driven=True, rel_tol=1e-8, abs_tol=1e-6, maxiter=10000, solver_type='bicgstab', - prec_type=None, display_iter=16, export_path=None): - """ Compute the permeability +def compute_permeability(workspace, solid_cutoff, tol=1e-8, maxiter=10000, solver_type='minres', display_iter=True): + """ Compute the permeability using first order Q1-Q1 Finite Element solver and periodic BC on the sides :param workspace: domain :type workspace: Workspace - :param direction: direction for solve ('x','y', or 'z') - :type direction: string :param solid_cutoff: specify the solid phase :type solid_cutoff: tuple(int, int) - :param side_bc: side boundary conditions can be free slip ('fs'), no slip ('ns') or periodic ('p') - :type side_bc: string, optional - :param first_order: specify whether to use Stab. 1st order method or Taylor-Hood method - :type first_order: bool, optional - :param inf_sup: inf-sup parameter used in case first_order=True to stabilize the Q1-Q1 method - :type inf_sup: float, optional - :param pressure_driven: whether the permeability is to be computed using a pressure driven-flow or body force - :type pressure_driven: bool, optional - :param rel_tol: relative tolerance for iterative solver - :type rel_tol: float, optional - :param abs_tol: absolute tolerance for iterative solver - :type abs_tol: float, optional + :param tol: tolerance for iterative solver + :type tol: float, optional :param maxiter: maximum Iterations for solver :type maxiter: int, optional - :param solver_type: solver type, options: 'bicgstab', 'minres', 'gmres', 'direct' + :param solver_type: solver type, options: 'minres' (default), 'direct', 'cg', 'bicgstab' :type solver_type: string, optional - :param prec_type: preconditioner type, options: 'amg', 'sor', 'ilu', 'icc' or None - :type prec_type: string, optional - :param display_iter: FEniCS progress print: 16 for what's happening (broadly), - 13 for what's happening (in detail), 20 for information of general interest, 0 for printing off - :type display_iter: int, optional - :param export_path: export path for intermediary steps (mesh_facets, p, v). If None (default), no export - :type export_path: string, optional - :return: permeability, pressure field, velocity field - :rtype: tuple(ndarray, ndarray, ndarray) + :type display_iter: bool, optional + :return: permeability, velocity field + :rtype: tuple(ndarray, ndarray) """ - solver = Permeability(workspace, direction, solid_cutoff, side_bc, first_order, inf_sup, pressure_driven, - rel_tol, abs_tol, maxiter, solver_type, prec_type, display_iter, export_path) + solver = Permeability(workspace, solid_cutoff, tol, maxiter, solver_type, display_iter) solver.error_check() solver.log_input() solver.compute() solver.log_output() - return solver.keff, solver.pressure, solver.velocity + return solver.keff, solver.u_x, solver.u_y, solver.u_z diff --git a/python/pumapy/physicsmodels/conductivity_parent.py b/python/pumapy/physicsmodels/conductivity_parent.py index f75bd5c..cc9a868 100644 --- a/python/pumapy/physicsmodels/conductivity_parent.py +++ b/python/pumapy/physicsmodels/conductivity_parent.py @@ -1,32 +1,24 @@ from pumapy.utilities.workspace import Workspace from pumapy.utilities.boundary_conditions import ConductivityBC -import sys -import inspect +from pumapy.utilities.linear_solvers import PropertySolver import numpy as np -class Conductivity: - def __init__(self, workspace, cond_map, direction, side_bc, prescribed_bc, - tolerance, maxiter, solver_type, display_iter): - self.ws = workspace +class Conductivity(PropertySolver): + + def __init__(self, workspace, cond_map, direction, side_bc, prescribed_bc, tolerance, maxiter, solver_type, display_iter): + allowed_solvers = ['direct', 'gmres', 'cg', 'bicgstab'] + super().__init__(workspace, solver_type, allowed_solvers, tolerance, maxiter, display_iter) + self.cond_map = cond_map self.direction = direction self.side_bc = side_bc self.prescribed_bc = prescribed_bc - self.tolerance = tolerance - self.maxiter = maxiter - self.solver_type = solver_type - self.display_iter = display_iter self.keff = [-1., -1., -1.] self.solve_time = -1 self.T = np.zeros([1, 1, 1]) self.q = np.zeros([1, 1, 1, 3]) - self.len_x = self.ws.matrix.shape[0] - self.len_y = self.ws.matrix.shape[1] - self.len_z = self.ws.matrix.shape[2] - self.len_xy = self.len_x * self.len_y - self.len_xyz = self.len_xy * self.len_z def log_input(self): self.ws.log.log_section("Computing Conductivity") @@ -36,6 +28,7 @@ def log_input(self): low, high, cond = self.cond_map.get_material(i) self.ws.log.log_line( " - Material " + str(i) + "[" + str(low) + "," + str(high) + "," + str(cond) + "]") + self.ws.log.log_line("Solver Type: " + str(self.solver_type)) self.ws.log.log_line("Solver Tolerance: " + str(self.tolerance)) self.ws.log.log_line("Max Iterations: " + str(self.maxiter)) self.ws.log.write_log() @@ -87,13 +80,3 @@ def error_check(self): self.prescribed_bc.dirichlet = self.prescribed_bc.dirichlet.transpose((2, 1, 0)) if np.any((self.prescribed_bc[[0, -1]] == np.Inf)): raise Exception("prescribed_bc must be defined on the direction sides") - - -class SolverDisplay(object): - def __init__(self): - self.niter = 0 - - def __call__(self, rk=None): - self.niter += 1 - frame = inspect.currentframe().f_back - sys.stdout.write("\rIteration {} Residual = {} ".format(self.niter, frame.f_locals['resid'])) diff --git a/python/pumapy/physicsmodels/fe_permeability.py b/python/pumapy/physicsmodels/fe_permeability.py new file mode 100644 index 0000000..006e6e5 --- /dev/null +++ b/python/pumapy/physicsmodels/fe_permeability.py @@ -0,0 +1,306 @@ +from pumapy.utilities.timer import Timer +from pumapy.utilities.workspace import Workspace +from pumapy.utilities.linear_solvers import PropertySolver +from scipy.sparse import csc_matrix +import numpy as np + + +class Permeability(PropertySolver): + + def __init__(self, workspace, solid_cutoff, tolerance, maxiter, solver_type, display_iter): + allowed_solvers = ['minres', 'direct', 'cg', 'bicgstab'] + super().__init__(workspace, solver_type, allowed_solvers, tolerance, maxiter, display_iter) + + self.ws = workspace.copy() + self.solid_cutoff = solid_cutoff + self.ws.binarize_range(self.solid_cutoff) + + self.solver_type = solver_type + self.len_x, self.len_y, self.len_z = self.ws.matrix.shape + self.voxlength = self.ws.voxel_length + + self.nel = self.len_x * self.len_y + self.nels = self.len_x * self.len_y * self.len_z + self.nnP2 = (self.len_x + 1) * (self.len_y + 1) + self.velF = np.where(self.ws.matrix.ravel(order='F') == 0)[0] # only fluid elements + self.nelF = self.velF.shape[0] + + self.ke = np.zeros((24, 24), dtype=float) + self.ge = np.zeros((24, 8), dtype=float) + self.pe = np.zeros((8, 8), dtype=float) + self.fe = np.zeros((8, 1), dtype=float) + self.x_full = np.zeros((4 * self.nels, 3), dtype=float) + self.mConectP = np.zeros((self.nels, 8), dtype=np.uint64) + self.mgdlF = np.zeros((32, self.nelF), dtype=np.uint64) + self.resolveF = None + + self.keff = np.zeros((3, 3)) + self.solve_time = -1 + self.u_x = np.zeros((self.len_x, self.len_y, self.len_z, 3)) + self.u_y = np.zeros((self.len_x, self.len_y, self.len_z, 3)) + self.u_z = np.zeros((self.len_x, self.len_y, self.len_z, 3)) + + def compute(self): + t = Timer() + self.initialize() + self.assemble_bvector() + self.assemble_Amatrix() + print("Time to assemble matrices: ", t.elapsed()); t.reset() + self.solve() + print("Time to solve: ", t.elapsed()) + self.compute_effective_coefficient() + self.solve_time = t.elapsed() + + def initialize(self): + print("Initializing indexing matrices ... ", flush=True, end='') + + # Matrix with element connectivity with Periodic boundary conditions (PBC) + mConectP1 = np.zeros((self.nel, 4, self.len_z + 1), dtype=np.uint64) + aux = 1 + for slice in range(self.len_z): + mIdNosP = np.reshape(np.arange(aux, aux + self.nel, dtype=np.uint64), (self.len_x, self.len_y), order='F') + mIdNosP = np.append(mIdNosP, mIdNosP[0][np.newaxis], axis=0) # Numbering bottom nodes + mIdNosP = np.append(mIdNosP, mIdNosP[:, 0][:, np.newaxis], axis=1) # Numbering right nodes + mConectP1[:, 0, slice] = np.ravel(mIdNosP[1:, :-1], order='F') + mConectP1[:, 1, slice] = np.ravel(mIdNosP[1:, 1:], order='F') + mConectP1[:, 2, slice] = np.ravel(mIdNosP[:-1, 1:], order='F') + mConectP1[:, 3, slice] = np.ravel(mIdNosP[:-1, :-1], order='F') + aux += self.nel + mConectP1[:, :, -1] = mConectP1[:, :, 0] + + for slice in range(self.len_z): + self.mConectP[self.nel * slice:self.nel * (slice + 1), :4] = mConectP1[:, :, slice] + self.mConectP[self.nel * slice:self.nel * (slice + 1), 4:] = mConectP1[:, :, slice + 1] + + self.calculate_element_matrices() + + # degrees of freedom matrix + self.mgdlF[0] = self.mConectP[self.velF, 0] * 3 - 2 + self.mgdlF[1] = self.mConectP[self.velF, 0] * 3 - 1 + self.mgdlF[2] = self.mConectP[self.velF, 0] * 3 + self.mgdlF[3] = self.mConectP[self.velF, 1] * 3 - 2 + self.mgdlF[4] = self.mConectP[self.velF, 1] * 3 - 1 + self.mgdlF[5] = self.mConectP[self.velF, 1] * 3 + self.mgdlF[6] = self.mConectP[self.velF, 2] * 3 - 2 + self.mgdlF[7] = self.mConectP[self.velF, 2] * 3 - 1 + self.mgdlF[8] = self.mConectP[self.velF, 2] * 3 + self.mgdlF[9] = self.mConectP[self.velF, 3] * 3 - 2 + self.mgdlF[10] = self.mConectP[self.velF, 3] * 3 - 1 + self.mgdlF[11] = self.mConectP[self.velF, 3] * 3 + self.mgdlF[12] = self.mConectP[self.velF, 4] * 3 - 2 + self.mgdlF[13] = self.mConectP[self.velF, 4] * 3 - 1 + self.mgdlF[14] = self.mConectP[self.velF, 4] * 3 + self.mgdlF[15] = self.mConectP[self.velF, 5] * 3 - 2 + self.mgdlF[16] = self.mConectP[self.velF, 5] * 3 - 1 + self.mgdlF[17] = self.mConectP[self.velF, 5] * 3 + self.mgdlF[18] = self.mConectP[self.velF, 6] * 3 - 2 + self.mgdlF[19] = self.mConectP[self.velF, 6] * 3 - 1 + self.mgdlF[20] = self.mConectP[self.velF, 6] * 3 + self.mgdlF[21] = self.mConectP[self.velF, 7] * 3 - 2 + self.mgdlF[22] = self.mConectP[self.velF, 7] * 3 - 1 + self.mgdlF[23] = self.mConectP[self.velF, 7] * 3 + self.mgdlF[24] = 3 * self.nels + self.mConectP[self.velF, 0] + self.mgdlF[25] = 3 * self.nels + self.mConectP[self.velF, 1] + self.mgdlF[26] = 3 * self.nels + self.mConectP[self.velF, 2] + self.mgdlF[27] = 3 * self.nels + self.mConectP[self.velF, 3] + self.mgdlF[28] = 3 * self.nels + self.mConectP[self.velF, 4] + self.mgdlF[29] = 3 * self.nels + self.mConectP[self.velF, 5] + self.mgdlF[30] = 3 * self.nels + self.mConectP[self.velF, 6] + self.mgdlF[31] = 3 * self.nels + self.mConectP[self.velF, 7] + print("Done") + + def assemble_bvector(self): + print("Assembling b vector ... ", flush=True, end='') + iF = np.hstack((np.reshape(self.mgdlF[:24:3], self.nelF * 8, order='F'), + np.reshape(self.mgdlF[1:24:3], self.nelF * 8, order='F'), + np.reshape(self.mgdlF[2:24:3], self.nelF * 8, order='F'))) - 1 + jF = np.hstack((np.zeros(self.nelF * 8, dtype=np.uint8), + np.ones(self.nelF * 8, dtype=np.uint8), + np.full(self.nelF * 8, 2, dtype=np.uint8))) + sF = np.squeeze(np.tile(self.fe, (self.nelF * 3, 1))) + self.bvec_full = csc_matrix((sF, (iF, jF)), shape=(4 * self.nels, 3)) + print("Done") + + def assemble_Amatrix(self): + print("Initializing large data structures ... ", flush=True, end='') + iK = np.repeat(np.reshape(self.mgdlF[:24], self.nelF * 24, order='F'), 24) + jK = np.reshape(np.repeat(self.mgdlF[:24], 24, axis=1), self.nelF * 576, order='F') + iG = np.repeat(np.reshape(self.mgdlF[:24], self.nelF * 24, order='F'), 8) + jG = np.reshape(np.repeat(self.mgdlF[24:], 24, axis=1), self.nelF * 192, order='F') + iP = np.repeat(np.reshape(self.mgdlF[24:], self.nelF * 8, order='F'), 8) + jP = np.reshape(np.repeat(self.mgdlF[24:], 8, axis=1), self.nelF * 64, order='F') + del self.mgdlF + iA = np.hstack((iK, iG, jG, iP)) - 1 + jA = np.hstack((jK, jG, iG, jP)) - 1 + coeff = np.hstack((np.tile(self.ke, self.nelF), np.tile(self.ge, self.nelF), + np.tile(self.ge, self.nelF), -np.tile(self.pe, self.nelF))) + + print("Done\nAssembling A matrix ... ", flush=True, end='') + self.Amat = csc_matrix((coeff, (iA, jA))) + print("Done") + + print("Reducing system of equations ... ", flush=True, end='') + resolveF_u = np.arange(1, self.nels * 3 + 1, dtype=np.uint64) + nosnulos = np.unique(self.mConectP[np.where(self.ws.matrix.ravel(order='F') > 0)[0], :8]) + gdlnulos = np.hstack((nosnulos * 3 - 2, nosnulos * 3 - 1, nosnulos * 3)) + resolveF_u = np.delete(resolveF_u, gdlnulos - 1) + resolveF_p = self.nels * 3 + np.unique(self.mConectP[np.where(self.ws.matrix.ravel(order='F') == 0)[0], :8]) + self.resolveF = np.hstack((resolveF_u, resolveF_p)) - 1 + del self.mConectP + + self.Amat = self.Amat[self.resolveF][:, self.resolveF] + self.bvec_full = self.bvec_full[self.resolveF] + print("Done") + + def solve(self): + # solves the system in the 3 directions directly + if self.solver_type == 'direct': + self.bvec = self.bvec_full + super().solve() + self.x_full[self.resolveF] = self.x.toarray() + else: # solves one direction at a time + self.del_matrices = False + for i in range(3): + self.bvec = self.bvec_full[:, i] + super().solve() + self.x_full[self.resolveF, i] = self.x + del self.Amat, self.bvec, self.initial_guess + + def compute_effective_coefficient(self): + aux = 1 + vIdNosP = np.zeros(self.len_z * self.nnP2, dtype=np.uint64) + for slice in range(self.len_z): + mIdNosP = np.reshape(np.arange(aux, aux + self.nel, dtype=np.uint64), (self.len_x, self.len_y), order='F') + mIdNosP = np.append(mIdNosP, mIdNosP[0][np.newaxis], axis=0) # Numbering bottom nodes + mIdNosP = np.append(mIdNosP, mIdNosP[:, 0][:, np.newaxis], axis=1) # Numbering right nodes + + vIdNosP[self.nnP2 * slice:self.nnP2 * (slice + 1)] = mIdNosP.ravel(order='F') + aux += self.nel + del mIdNosP + + vIdNosP = np.append(vIdNosP, (vIdNosP[:self.nnP2])) + vIdNosP = np.unique(vIdNosP) + + self.keff[0, 0] = np.sum(self.x_full[vIdNosP * 3 - 2, 1]) + self.keff[0, 1] = - np.sum(self.x_full[vIdNosP * 3 - 3, 1]) + self.keff[0, 2] = - np.sum(self.x_full[vIdNosP * 3 - 1, 1]) + self.keff[1, 0] = - np.sum(self.x_full[vIdNosP * 3 - 2, 0]) + self.keff[1, 1] = np.sum(self.x_full[vIdNosP * 3 - 3, 0]) + self.keff[1, 2] = np.sum(self.x_full[vIdNosP * 3 - 1, 0]) + self.keff[2, 0] = - np.sum(self.x_full[vIdNosP * 3 - 2, 2]) + self.keff[2, 1] = np.sum(self.x_full[vIdNosP * 3 - 3, 2]) + self.keff[2, 2] = np.sum(self.x_full[vIdNosP * 3 - 1, 2]) + self.keff /= self.nels + print(f'\nEffective permeability tensor: \n{self.keff}') + + # Extracting velocity fields + self.u_x[:, :, :, 0] = np.reshape(self.x_full[vIdNosP * 3 - 2, 1], (self.len_x, self.len_y, self.len_z), order='F') + self.u_x[:, :, :, 1] = - np.reshape(self.x_full[vIdNosP * 3 - 3, 1], (self.len_x, self.len_y, self.len_z), order='F') + self.u_x[:, :, :, 2] = - np.reshape(self.x_full[vIdNosP * 3 - 1, 1], (self.len_x, self.len_y, self.len_z), order='F') + self.u_y[:, :, :, 0] = - np.reshape(self.x_full[vIdNosP * 3 - 2, 0], (self.len_x, self.len_y, self.len_z), order='F') + self.u_y[:, :, :, 1] = np.reshape(self.x_full[vIdNosP * 3 - 3, 0], (self.len_x, self.len_y, self.len_z), order='F') + self.u_y[:, :, :, 2] = np.reshape(self.x_full[vIdNosP * 3 - 1, 0], (self.len_x, self.len_y, self.len_z), order='F') + self.u_z[:, :, :, 0] = - np.reshape(self.x_full[vIdNosP * 3 - 2, 2], (self.len_x, self.len_y, self.len_z), order='F') + self.u_z[:, :, :, 1] = np.reshape(self.x_full[vIdNosP * 3 - 3, 2], (self.len_x, self.len_y, self.len_z), order='F') + self.u_z[:, :, :, 2] = np.reshape(self.x_full[vIdNosP * 3 - 1, 2], (self.len_x, self.len_y, self.len_z), order='F') + + def calculate_element_matrices(self): + coordsElem = np.array([[0, 0, 0], [self.voxlength, 0, 0], [self.voxlength, self.voxlength, 0], + [0, self.voxlength, 0], [0, 0, self.voxlength], [self.voxlength, 0, self.voxlength], + [self.voxlength, self.voxlength, self.voxlength], [0, self.voxlength, self.voxlength]]) + rr = np.array([-1. / np.sqrt(3), 1. / np.sqrt(3)]) + ss = rr.copy() + tt = rr.copy() + ww = np.array([1, 1]) + C = np.diag([2., 2., 2., 1., 1., 1.]) + stab = (self.voxlength ** 2 + self.voxlength ** 2 + self.voxlength ** 2) / 18. + mat111000 = np.array([[1.], [1.], [1.], [0.], [0.], [0.]]) + + for i in range(2): + r = rr[i] + for j in range(2): + s = ss[j] + for k in range(2): + t = tt[k] + + N1 = (1 - r) * (1 - s) * (1 - t) + N2 = (1 + r) * (1 - s) * (1 - t) + N3 = (1 + r) * (1 + s) * (1 - t) + N4 = (1 - r) * (1 + s) * (1 - t) + N5 = (1 - r) * (1 - s) * (1 + t) + N6 = (1 + r) * (1 - s) * (1 + t) + N7 = (1 + r) * (1 + s) * (1 + t) + N8 = (1 - r) * (1 + s) * (1 + t) + N = 0.125 * np.array([[N1, 0, 0, N2, 0, 0, N3, 0, 0, N4, 0, 0, N5, 0, 0, N6, 0, 0, N7, 0, 0, N8, 0, 0], + [0, N1, 0, 0, N2, 0, 0, N3, 0, 0, N4, 0, 0, N5, 0, 0, N6, 0, 0, N7, 0, 0, N8, 0], + [0, 0, N1, 0, 0, N2, 0, 0, N3, 0, 0, N4, 0, 0, N5, 0, 0, N6, 0, 0, N7, 0, 0, N8]]) + + dN1dr = -0.125 * (1 - s) * (1 - t) + dN1ds = -0.125 * (1 - r) * (1 - t) + dN1dt = -0.125 * (1 - r) * (1 - s) + dN2dr = +0.125 * (1 - s) * (1 - t) + dN2ds = -0.125 * (1 + r) * (1 - t) + dN2dt = -0.125 * (1 + r) * (1 - s) + dN3dr = +0.125 * (1 + s) * (1 - t) + dN3ds = +0.125 * (1 + r) * (1 - t) + dN3dt = -0.125 * (1 + r) * (1 + s) + dN4dr = -0.125 * (1 + s) * (1 - t) + dN4ds = +0.125 * (1 - r) * (1 - t) + dN4dt = -0.125 * (1 - r) * (1 + s) + dN5dr = -0.125 * (1 - s) * (1 + t) + dN5ds = -0.125 * (1 - r) * (1 + t) + dN5dt = +0.125 * (1 - r) * (1 - s) + dN6dr = +0.125 * (1 - s) * (1 + t) + dN6ds = -0.125 * (1 + r) * (1 + t) + dN6dt = +0.125 * (1 + r) * (1 - s) + dN7dr = +0.125 * (1 + s) * (1 + t) + dN7ds = +0.125 * (1 + r) * (1 + t) + dN7dt = +0.125 * (1 + r) * (1 + s) + dN8dr = -0.125 * (1 + s) * (1 + t) + dN8ds = +0.125 * (1 - r) * (1 + t) + dN8dt = +0.125 * (1 - r) * (1 + s) + DN = np.array([[dN1dr, dN2dr, dN3dr, dN4dr, dN5dr, dN6dr, dN7dr, dN8dr], + [dN1ds, dN2ds, dN3ds, dN4ds, dN5ds, dN6ds, dN7ds, dN8ds], + [dN1dt, dN2dt, dN3dt, dN4dt, dN5dt, dN6dt, dN7dt, dN8dt]]) + + J = DN @ coordsElem + detJ = np.linalg.det(J) + weight = detJ * ww[i] * ww[j] * ww[k] + invJ = np.linalg.inv(J) + DNxy = invJ @ DN + B = np.array([[DNxy[0, 0], 0, 0, DNxy[0, 1], 0, 0, DNxy[0, 2], 0, 0, DNxy[0, 3], 0, 0, DNxy[0, 4], 0, 0, DNxy[0, 5], 0, 0, DNxy[0, 6], 0, 0, DNxy[0, 7], 0, 0], + [0, DNxy[1, 0], 0, 0, DNxy[1, 1], 0, 0, DNxy[1, 2], 0, 0, DNxy[1, 3], 0, 0, DNxy[1, 4], 0, 0, DNxy[1, 5], 0, 0, DNxy[1, 6], 0, 0, DNxy[1, 7], 0], + [0, 0, DNxy[2, 0], 0, 0, DNxy[2, 1], 0, 0, DNxy[2, 2], 0, 0, DNxy[2, 3], 0, 0, DNxy[2, 4], 0, 0, DNxy[2, 5], 0, 0, DNxy[2, 6], 0, 0, DNxy[2, 7]], + [DNxy[1, 0], DNxy[0, 0], 0, DNxy[1, 1], DNxy[0, 1], 0, DNxy[1, 2], DNxy[0, 2], 0, DNxy[1, 3], DNxy[0, 3], 0, + DNxy[1, 4], DNxy[0, 4], 0, DNxy[1, 5], DNxy[0, 5], 0, DNxy[1, 6], DNxy[0, 6], 0, DNxy[1, 7], DNxy[0, 7], 0], + [DNxy[2, 0], 0, DNxy[0, 0], DNxy[2, 1], 0, DNxy[0, 1], DNxy[2, 2], 0, DNxy[0, 2], DNxy[2, 3], 0, DNxy[0, 3], + DNxy[2, 4], 0, DNxy[0, 4], DNxy[2, 5], 0, DNxy[0, 5], DNxy[2, 6], 0, DNxy[0, 6], DNxy[2, 7], 0, DNxy[0, 7]], + [0, DNxy[2, 0], DNxy[1, 0], 0, DNxy[2, 1], DNxy[1, 1], 0, DNxy[2, 2], DNxy[1, 2], 0, DNxy[2, 3], DNxy[1, 3], + 0, DNxy[2, 4], DNxy[1, 4], 0, DNxy[2, 5], DNxy[1, 5], 0, DNxy[2, 6], DNxy[1, 6], 0, DNxy[2, 7], DNxy[1, 7]]]) + + self.ke += weight * B.T @ C @ B + self.ge += weight * B.T @ mat111000 @ N.ravel(order='F')[::9][np.newaxis] + self.pe += weight * stab * DNxy.T @ DNxy + self.fe += weight * N[0][::3][:, np.newaxis] + + self.ke = self.ke.ravel() + self.ge = self.ge.ravel() + self.pe = self.pe.ravel() + + def log_input(self): + self.ws.log.log_section("Computing Permeability") + self.ws.log.log_line("Domain Size: " + str(self.ws.get_shape())) + self.ws.log.log_line("Solver Type: " + str(self.solver_type)) + self.ws.log.log_line("Solver Tolerance: " + str(self.tolerance)) + self.ws.log.log_line("Max Iterations: " + str(self.maxiter)) + self.ws.log.write_log() + + def log_output(self): + self.ws.log.log_section("Finished Permeability Calculation") + self.ws.log.log_line("Permeability: " + str(self.keff)) + self.ws.log.log_line("Solver Time: " + str(self.solve_time)) + self.ws.log.write_log() + + def error_check(self): + if not isinstance(self.ws, Workspace): + raise Exception("Workspace must be a puma.Workspace.") diff --git a/python/pumapy/physicsmodels/fenics_stokes.py b/python/pumapy/physicsmodels/fenics_stokes.py deleted file mode 100644 index 6b2ab2c..0000000 --- a/python/pumapy/physicsmodels/fenics_stokes.py +++ /dev/null @@ -1,329 +0,0 @@ -import numpy as np -import dolfin as df -import sys -from pumapy.utilities.timer import Timer -from pumapy.utilities.generic_checks import check_ws_cutoff -from pumapy.utilities.logger import print_warning - - -class Permeability: - - def __init__(self, workspace, direction, cutoff, side_bc, first_order, inf_sup, pressure_driven, - relative_tolerance, absolute_tolerance, maxiter, solver_type, prec_type, display_iter, export_path): - - flags = ["-O3", "-ffast-math", "-march=native"] - # df.parameters["form_compiler"]["quadrature_degree"] = 4 - df.parameters["form_compiler"]["representation"] = "uflacs" - df.parameters["form_compiler"]["cpp_optimize"] = True - df.parameters["form_compiler"]["cpp_optimize_flags"] = " ".join(flags) - df.parameters["form_compiler"]["precision"] = 8 - - self.ws = workspace.copy() - self.direction = direction - self.cutoff = cutoff - self.side_bc = side_bc - self.first_order = first_order - self.pressure_driven = pressure_driven - self.solver_type = solver_type - self.prec_type = prec_type - self.export_path = export_path - self.len_x, self.len_y, self.len_z = self.ws.matrix.shape - self.inf_sup = inf_sup - - if self.first_order: - self.voxel_length = 1 - else: - self.voxel_length = self.ws.voxel_length - - if self.pressure_driven: - self.p_in = df.Constant(1.) - self.bf = df.Constant((0, 0, 0)) - else: - self.p_in = df.Constant(0.) - self.bf = df.Constant((1, 0, 0)) - - self.mesh = df.BoxMesh.create([df.Point(0, 0, 0), df.Point(self.ws.get_shape())], - self.ws.get_shape(), df.CellType.Type.hexahedron) - self.faces = df.MeshFunction("size_t", self.mesh, self.mesh.topology().dim() - 1) - self.P = df.FiniteElement("CG", self.mesh.ufl_cell(), 1) - self.V = df.VectorElement("CG", self.mesh.ufl_cell(), 1 if first_order else 2) - self.W = None - self.p = None - self.u = None - self.v = None - self.q = None - self.w = None - self.bcs = [] - self.dx = None - self.ds = None - self.a = None - self.L = None - self.timer = Timer() - if df.MPI.rank(df.MPI.comm_world) == 0: - self.timer.start() - - self.keff = None - self.pressure = None - self.velocity = None - - prm = df.parameters['krylov_solver'] - prm["monitor_convergence"] = display_iter > 0 - prm["relative_tolerance"] = relative_tolerance - prm["absolute_tolerance"] = absolute_tolerance - prm["maximum_iterations"] = maxiter - prm['nonzero_initial_guess'] = True - df.set_log_level(display_iter) - - def compute(self): - self.modify_domain() - self.mark_domain() - self.setup_bcs() - self.construct_variational_form() - self.solve() - self.compute_effective_coefficient() - - if df.MPI.rank(df.MPI.comm_world) == 0: - sys.stdout.write("Solved in {}s\n".format(str(self.timer.elapsed()))) - sys.stdout.flush() - - def modify_domain(self): - self.ws.binarize_range(self.cutoff) - - if self.direction == "y": - self.ws.matrix.transpose(1, 0, 2) - elif self.direction == "z": - self.ws.matrix.transpose(2, 1, 0) - - def setup_bcs(self): - if self.side_bc == "p": - if self.pressure_driven: - self.W = df.FunctionSpace(self.mesh, self.V * self.P, - constrained_domain=PeriodicBoundaryYZ(self.len_y, self.len_z)) - else: - self.W = df.FunctionSpace(self.mesh, self.V * self.P, - constrained_domain=PeriodicBoundaryXYZ(self.len_x, self.len_y, self.len_z)) - else: - self.W = df.FunctionSpace(self.mesh, self.V * self.P) - - # imposing bc on W FunctionSpace, where W.sub(0) is velocity and W.sub(1) is pressure - if self.side_bc == "fs": - self.bcs.append(df.DirichletBC(self.W.sub(0).sub(1), df.Constant(0.), self.faces, 3)) # free slip y faces - self.bcs.append(df.DirichletBC(self.W.sub(0).sub(2), df.Constant(0.), self.faces, 4)) # free slip z faces - elif self.side_bc == "ns": - self.bcs.append(df.DirichletBC(self.W.sub(0), df.Constant((0., 0., 0.)), self.faces, 3)) # no slip y faces - self.bcs.append(df.DirichletBC(self.W.sub(0), df.Constant((0., 0., 0.)), self.faces, 4)) # no slip z faces - - self.bcs.append(df.DirichletBC(self.W.sub(1), df.Constant(0.), self.faces, 5)) # zero pressure inside - self.bcs.append(df.DirichletBC(self.W.sub(0), df.Constant((0., 0., 0.)), self.faces, 5)) # zero velocity inside - self.bcs.append(df.DirichletBC(self.W.sub(0), df.Constant((0., 0., 0.)), self.faces, 6)) # no slip on surfaces - - def construct_variational_form(self): - self.u, self.p = df.TrialFunctions(self.W) - self.v, self.q = df.TestFunctions(self.W) - self.dx = df.Measure("dx", domain=self.mesh, subdomain_data=self.faces) # Volume integration - self.ds = df.Measure("ds", domain=self.mesh, subdomain_data=self.faces) # Surface integration - n = df.FacetNormal(self.mesh) - - self.a = (df.inner(df.grad(self.u), df.grad(self.v)) + self.q * df.div(self.u)) * self.dx - self.L = - self.p_in * df.inner(n, self.v) * self.ds(1) - - if self.first_order: - self.a += (- df.div(self.v) * self.p + self.inf_sup * df.inner(df.grad(self.q), df.grad(self.p))) * self.dx - self.L += df.inner(self.v + self.inf_sup * df.grad(self.q), self.bf) * self.dx - else: - self.a += df.div(self.v) * self.p * self.dx # +ve pressure to make system symmetric - self.L += df.inner(self.bf, self.v) * self.dx - - def solve(self): - w = df.Function(self.W) - - if self.first_order: - solver_parameters = dict() - if self.solver_type == 'direct': - solver_parameters['linear_solver'] = 'umfpack' # LU solver - else: - solver_parameters['linear_solver'] = self.solver_type - if self.prec_type is not None: - solver_parameters['preconditioner'] = self.prec_type - df.solve(self.a == self.L, w, self.bcs, solver_parameters=solver_parameters) - - else: # Taylor Hood elements - if self.solver_type == "direct": - df.solve(self.a == self.L, w, self.bcs) # LU solver - else: - A, b = df.assemble_system(self.a, self.L, self.bcs) - if self.prec_type is None: - solver = df.KrylovSolver(A, self.solver_type) - else: # construct ad-hoc preconditioner for TH method - solver = df.KrylovSolver(A, self.solver_type, self.prec_type) - b_prec = df.inner(df.grad(self.u), df.grad(self.v)) * self.dx + self.p * self.q * self.dx - P, _ = df.assemble_system(b_prec, self.L, self.bcs) # assemble P preconditioner matrix - solver.set_operators(A, P) - solver.solve(w.vector(), b) - - self.u, self.p = w.split(deepcopy=True) - - if not self.first_order: # because we want to be able to use minres for TH - self.p.vector()[:] *= -1 - - x = self.mesh.coordinates() - x[:, :] *= self.ws.voxel_length - self.u.vector()[:] *= self.ws.voxel_length ** 2 - if not self.pressure_driven: - self.p.vector()[:] *= self.ws.voxel_length ** 2 - - if self.export_path is not None: - with df.XDMFFile(self.export_path + '/mesh_facets.xdmf') as f: - f.write(self.faces) - df.File(self.export_path + "/velocity.pvd").write(self.u) - df.File(self.export_path + "/pressure.pvd").write(self.p) - - def compute_effective_coefficient(self): - - self.keff = [df.assemble(self.u[0] * self.dx) * self.len_x, - df.assemble(self.u[1] * self.dx) * self.len_x, - df.assemble(self.u[2] * self.dx) * self.len_x] - - if self.direction == 'y': - self.keff = [self.keff[1], self.keff[0], self.keff[2]] - elif self.direction == 'z': - self.keff = [self.keff[2], self.keff[1], self.keff[0]] - - # reconstruct pressure and velocity only when not running in parallel with MPI (cannot gather data to one proc) - if (self.len_x + 1) * (self.len_y + 1) * (self.len_z + 1) == self.p.compute_vertex_values().size: - self.pressure = self.p.compute_vertex_values().reshape(self.len_z + 1, self.len_y + 1, self.len_x + 1).transpose(2, 1, 0) - self.velocity = self.u.compute_vertex_values().reshape(3, self.len_z + 1, self.len_y + 1, self.len_x + 1).transpose(3, 2, 1, 0) - if self.direction == 'y': - self.pressure = self.pressure.transpose(1, 0, 2) - self.velocity = self.velocity.transpose(1, 0, 2, 3)[:, :, :, [1, 0, 2]] - elif self.direction == 'z': - self.pressure = self.pressure.transpose(2, 1, 0) - self.velocity = self.velocity.transpose(2, 1, 0, 3)[:, :, :, [2, 1, 0]] - - def error_check(self): - check_ws_cutoff(self.ws, self.cutoff) - - # solver type - if not (self.solver_type == "bicgstab" or self.solver_type == "minres" or - self.solver_type == "gmres" or self.solver_type == "direct"): - print_warning("Unrecognized solver specified, defaulting to bicgstab.") - self.solver_type = "bicgstab" - if self.solver_type == "minres" and self.first_order: - print_warning("Cannot solve body force with minres, defaulting to bicgstab.") - self.solver_type = "bicgstab" - - # preconditioner type - if not (self.prec_type == "amg" or self.prec_type == "sor" or - self.prec_type == "ilu" or self.prec_type == "icc" or self.prec_type is None): - print_warning("Unrecognized preconditioner specified, defaulting to amg.") - self.prec_type = "amg" - - # direction checks - if self.direction == "x" or self.direction == "X": - self.direction = "x" - elif self.direction == "y" or self.direction == "Y": - self.direction = "y" - elif self.direction == "z" or self.direction == "Z": - self.direction = "z" - else: - raise Exception("Invalid simulation direction.") - - # side_bc checks - if self.side_bc == "periodic" or self.side_bc == "Periodic" or self.side_bc == "p": - self.side_bc = "p" - elif self.side_bc == "free slip" or self.side_bc == "Free Slip" or self.side_bc == "fs": - self.side_bc = "fs" - elif self.side_bc == "no slip" or self.side_bc == "No Slip" or self.side_bc == "ns": - self.side_bc = "ns" - else: - raise Exception("Invalid side boundary conditions.") - - def log_input(self): - self.ws.log.log_section("Computing Permeability") - self.ws.log.log_line("Domain Size: " + str(self.ws.get_shape())) - self.ws.log.write_log() - - def log_output(self): - self.ws.log.log_section("Finished Permeability Calculation") - self.ws.log.log_line("Permeability: " + "[" + str(self.keff) + "]") - self.ws.log.write_log() - - def mark_domain(self): - # Mesh facets marked as: - # 0: void - # 1: inflow x0 - # 2: outflow x1 - # 3: y0 and y1 - # 4: z0 and z1 - # 5: inside solid - # 6: solid surface - for f in df.facets(self.mesh): - mp = f.midpoint() - if mp[0].is_integer(): - i, j, k = int(mp[0]), int(np.floor(mp[1])), int(np.floor(mp[2])) - if i == 0 or i == self.len_x: - self.faces[f] = 6 if self.ws[max(i - 1, 0), j, k] == 1 else (1 if i == 0 else 2) - else: - if self.ws[i - 1, j, k] == 1 and self.ws[i, j, k] == 1: - self.faces[f] = 5 - elif self.ws[i - 1, j, k] == 1: - self.faces[f] = 6 - elif self.ws[i, j, k] == 1: - self.faces[f] = 6 - elif mp[1].is_integer(): - i, j, k = int(np.floor(mp[0])), int(mp[1]), int(np.floor(mp[2])) - if j == 0 or j == self.len_y: - self.faces[f] = 6 if self.ws[i, max(j - 1, 0), k] == 1 else 3 - else: - if self.ws[i, j - 1, k] == 1 and self.ws[i, j, k] == 1: - self.faces[f] = 5 - elif self.ws[i, j - 1, k] == 1: - self.faces[f] = 6 - elif self.ws[i, j, k] == 1: - self.faces[f] = 6 - else: - i, j, k = int(np.floor(mp[0])), int(np.floor(mp[1])), int(mp[2]) - if k == 0 or k == self.len_z: - self.faces[f] = 6 if self.ws[i, j, max(k - 1, 0)] == 1 else 4 - else: - if self.ws[i, j, k - 1] == 1 and self.ws[i, j, k] == 1: - self.faces[f] = 5 - elif self.ws[i, j, k - 1] == 1: - self.faces[f] = 6 - elif self.ws[i, j, k] == 1: - self.faces[f] = 6 - - -class PeriodicBoundaryYZ(df.SubDomain): - - def __init__(self, len_y, len_z): - df.SubDomain.__init__(self) - self.len_y = len_y - self.len_z = len_z - - def inside(self, x, on_boundary): - return (int(x[1]) == 0 and not int(x[2]) == self.len_z) or (int(x[2]) == 0 and not int(x[1]) == self.len_y) - - def map(self, x, y): - y[0] = x[0] - y[1] = 0 if int(x[1]) == self.len_y else x[1] - y[2] = 0 if int(x[2]) == self.len_z else x[2] - - -class PeriodicBoundaryXYZ(df.SubDomain): - - def __init__(self, len_x, len_y, len_z): - df.SubDomain.__init__(self) - self.len_x = len_x - self.len_y = len_y - self.len_z = len_z - - def inside(self, x, on_boundary): - return (int(x[0]) == 0 and not int(x[1]) == self.len_y and not int(x[2]) == self.len_z) or \ - (int(x[1]) == 0 and not int(x[0]) == self.len_x and not int(x[2]) == self.len_z) or \ - (int(x[2]) == 0 and not int(x[0]) == self.len_x and not int(x[1]) == self.len_y) - - def map(self, x, y): - y[0] = 0 if int(x[0]) == self.len_x else x[0] - y[1] = 0 if int(x[1]) == self.len_y else x[1] - y[2] = 0 if int(x[2]) == self.len_z else x[2] diff --git a/python/pumapy/physicsmodels/isotropic_conductivity.py b/python/pumapy/physicsmodels/isotropic_conductivity.py index f362f08..7a5450b 100644 --- a/python/pumapy/physicsmodels/isotropic_conductivity.py +++ b/python/pumapy/physicsmodels/isotropic_conductivity.py @@ -1,18 +1,18 @@ from pumapy.utilities.logger import print_warning from pumapy.utilities.timer import Timer from pumapy.utilities.boundary_conditions import Isotropic_periodicBC, Isotropic_symmetricBC -from pumapy.physicsmodels.conductivity_parent import Conductivity, SolverDisplay +from pumapy.physicsmodels.conductivity_parent import Conductivity from pumapy.physicsmodels.isotropic_conductivity_utils import setup_matrices_cy, compute_flux -import numpy as np from scipy.sparse import csr_matrix, diags -from scipy.sparse.linalg import bicgstab, spsolve, cg, gmres # LinearOperator, spilu -import math +import numpy as np class IsotropicConductivity(Conductivity): - def __init__(self, workspace, cond_map, direction, side_bc, prescribed_bc, tolerance, maxiter, solver_type, display_iter): - super().__init__(workspace, cond_map, direction, side_bc, prescribed_bc, tolerance, maxiter, solver_type, display_iter) + def __init__(self, workspace, cond_map, direction, side_bc, prescribed_bc, tolerance, maxiter, solver_type, + display_iter): + super().__init__(workspace, cond_map, direction, side_bc, prescribed_bc, tolerance, maxiter, solver_type, + display_iter) self._bc_func = None self.cond = np.zeros([1, 1, 1]) @@ -23,12 +23,11 @@ def __init__(self, workspace, cond_map, direction, side_bc, prescribed_bc, toler elif self.direction == 'z': self._matrix = workspace.matrix.transpose(2, 1, 0) - self.len_x = self._matrix.shape[0] - self.len_y = self._matrix.shape[1] - self.len_z = self._matrix.shape[2] + self.len_x, self.len_y, self.len_z = self._matrix.shape self.len_xy = self.len_x * self.len_y self.len_xyz = self.len_xy * self.len_z + self.bc_check = 0 if self.side_bc == "p" or self.side_bc == "periodic": self._bc_func = Isotropic_periodicBC(self.len_x, self.len_y, self.len_z) elif self.side_bc == "s" or self.side_bc == "symmetric": @@ -38,26 +37,24 @@ def __init__(self, workspace, cond_map, direction, side_bc, prescribed_bc, toler self._bc_func = Isotropic_symmetricBC(self.len_x, self.len_y, self.len_z) self.n_iter = 0 - self._A = None - self._M = None - self._bf = np.zeros(1) - self._Tf = np.zeros(1) + self.Amat = None + self.M = None + self.bvec = np.zeros(1) + self.initial_guess = np.zeros(1) self._kf = np.zeros(1) def compute(self): - self.__create_cond_matrix() - self.__init_temperature() t = Timer() - self.__setup_matrices_cy() - print("Time to sep up A matrix: " , t.elapsed()) - t.reset() - self.__solve() + self.initialize() + self.assemble_bvector() + self.assemble_Amatrix() + print("Time to assemble matrices: ", t.elapsed()); t.reset() + super().solve() print("Time to solve: ", t.elapsed()) - t.reset() - self.__compute_conductivity() - print("Time to compute fluxes: ", t.elapsed()) + self.compute_effective_coefficient() + self.solve_time = t.elapsed() - def __create_cond_matrix(self): + def initialize(self): print("Creating conductivity matrix ... ", end='') self.cond = np.zeros(self._matrix.shape, dtype=float) for i in range(self.cond_map.get_size()): @@ -66,18 +63,16 @@ def __create_cond_matrix(self): mask_high = self._matrix <= high mask_low = mask_low * mask_high self.cond[mask_low] = k - print("Done") - def __init_temperature(self): print("Initializing temperature field ... ", end='') self.T = np.zeros([self.len_x, self.len_y, self.len_z]) for i in range(self.len_x): self.T[i, :, :] = i / (self.len_x - 1.) - self._Tf = self.T.flatten('F') + self.initial_guess = self.T.flatten('F') print("Done") - def __setup_matrices_cy(self): + def assemble_bvector(self): print("Setting up b matrix ... ", end='') bsq = np.zeros([self.len_x, self.len_y, self.len_z]) @@ -89,9 +84,9 @@ def __setup_matrices_cy(self): bsq[i, j, k] = self.prescribed_bc[i, j, k] self.prescribed_bc = self.prescribed_bc.dirichlet # because of cython, cannot pass object - bc_check = 1 + self.bc_check = 1 else: - bc_check = 0 + self.bc_check = 0 self.prescribed_bc = np.full(self._matrix.shape, np.Inf, dtype=float) bsq[-1, :, :] = 1 @@ -99,72 +94,31 @@ def __setup_matrices_cy(self): for i in range(self.cond_map.get_size()): low, high, k = self.cond_map.get_material(i) if k == 0: - bc_check = 1 + self.bc_check = 1 self.prescribed_bc[(self._matrix >= low) * (self._matrix <= high)] = 0 - self._bf = bsq.flatten('F') + self.bvec = bsq.flatten('F') print("Done") + def assemble_Amatrix(self): self._kf = self.cond.flatten('F') self._row, self._col, self._data = setup_matrices_cy(self._kf, self.len_x, self.len_y, self.len_z, - bc_check, self.prescribed_bc) + self.bc_check, self.prescribed_bc) n_elem = self.len_xyz - self._A = csr_matrix((self._data, (self._row, self._col)), shape=(n_elem, n_elem)) + self.Amat = csr_matrix((self._data, (self._row, self._col)), shape=(n_elem, n_elem)) print("Done") print("Setting up preconditioner ...", end ='') - # ilu = spilu(self._A.tocsc(), drop_tol=1e-5) - # Mx = lambda x: ilu.solve(x) - # self._M = LinearOperator((n_elem, n_elem), Mx) - diag = self._A.diagonal() + diag = self.Amat.diagonal() diag[diag==0] = 1 diag[:] = 1./diag[:] - self._M = diags(diag,0).tocsr() + self.M = diags(diag, 0).tocsr() print("Done") - - - def __solve(self): - print("Solving Ax=b system ... ", end='') - - info = 0 - - if self.solver_type == 'direct': - print("Direct solver", end='') - self._Tf = spsolve(self._A, self._bf) - elif self.solver_type == 'cg': - print("Conjugate Gradient:") - if self.display_iter: - self._Tf, info = cg(self._A, self._bf, x0=self._Tf, atol=self.tolerance, maxiter=self.maxiter, - callback=SolverDisplay(), M=self._M) - else: - self._Tf, info = cg(self._A, self._bf, x0=self._Tf, atol=self.tolerance, maxiter=self.maxiter, M=self._M) - - elif self.solver_type == 'gmres': - print("gmres:") - if self.display_iter: - self._Tf, info = gmres(self._A, self._bf, x0=self._Tf, atol=self.tolerance, - maxiter=self.maxiter, callback=SolverDisplay(), M=self._M) - else: - self._Tf, info = gmres(self._A, self._bf, x0=self._Tf, atol=self.tolerance, - maxiter=self.maxiter, M=self._M) - else: - if self.solver_type != 'bicgstab': - print_warning("Unrecognized solver, defaulting to bicgstab.") - print("Bicgstab:") - if self.display_iter: - self._Tf, info = bicgstab(self._A, self._bf, x0=self._Tf, atol=self.tolerance, - maxiter=self.maxiter, callback=SolverDisplay(), M=self._M) - else: - self._Tf, info = bicgstab(self._A, self._bf, x0=self._Tf, atol=self.tolerance, - maxiter=self.maxiter, M=self._M) - - if info != 0: - raise Exception("Solver error: " + str(info)) - self.T = self._Tf.reshape([self.len_x, self.len_y, self.len_z], order='F') - print(" ... Done") - - def __compute_conductivity(self): + def compute_effective_coefficient(self): + # reshaping solution + self.T = self.x.reshape([self.len_x, self.len_y, self.len_z], order='F') + del self.x if self.direction == 'y': self.T = self.T.transpose(1, 0, 2) @@ -187,7 +141,8 @@ def __compute_conductivity(self): self.keff[1] = flux_y * (self.len_y - 1) self.keff[2] = flux_z * (self.len_z - 1) + d = {'x': 'first', 'y': 'second', 'z': 'third'} + print(f'\nEffective conductivity tensor ({d[self.direction]} row): \n{self.keff}') + # making the flux have the correct spacial units self.q /= self.ws.voxel_length - - print("Computing effective conductivity... ", end='') diff --git a/python/pumapy/physicsmodels/mpfa_conductivity.py b/python/pumapy/physicsmodels/mpfa_conductivity.py index 29c9751..31fdfc1 100644 --- a/python/pumapy/physicsmodels/mpfa_conductivity.py +++ b/python/pumapy/physicsmodels/mpfa_conductivity.py @@ -1,15 +1,15 @@ from pumapy.physicsmodels.anisotropic_conductivity_utils import (pad_domain, add_nondiag, divP, fill_flux, flatten_Kmat_find_unstable_iv) from pumapy.physicsmodels.mpxa_matrices import fill_Ampfa, fill_Bmpfa, fill_Cmpfa, fill_Dmpfa, create_mpfa_indices -from pumapy.physicsmodels.conductivity_parent import Conductivity, SolverDisplay -from pumapy.utilities.logger import print_warning -import numpy as np +from pumapy.physicsmodels.conductivity_parent import Conductivity +from pumapy.utilities.timer import Timer from scipy.sparse import csr_matrix, diags -from scipy.sparse.linalg import bicgstab, spsolve, cg, gmres +import numpy as np import sys class AnisotropicConductivity(Conductivity): + def __init__(self, workspace, cond_map, direction, side_bc, prescribed_bc, tolerance, maxiter, solver_type, display_iter, print_matrices): super().__init__(workspace, cond_map, direction, side_bc, prescribed_bc, tolerance, maxiter, solver_type, display_iter) @@ -19,14 +19,17 @@ def __init__(self, workspace, cond_map, direction, side_bc, prescribed_bc, toler self.orient_pad = None def compute(self): - self.__initialize() - self.__assemble_bvector() - self.__assemble_Amatrix() - if not self.__solve(): - return - self.__compute_effective_coefficient() - - def __initialize(self): + t = Timer() + self.initialize() + self.assemble_bvector() + self.assemble_Amatrix() + print("Time to assemble matrices: ", t.elapsed()); t.reset() + super().solve() + print("Time to solve: ", t.elapsed()) + self.compute_effective_coefficient() + self.solve_time = t.elapsed() + + def initialize(self): print("Initializing and padding domains ... ", flush=True, end='') # Rotating domain to avoid cases and padding @@ -73,7 +76,14 @@ def __initialize(self): self.dir_vox[1:-1, 1:-1, 1:-1][self.prescribed_bc.dirichlet != np.Inf] = 1 print("Done") - def __assemble_bvector(self): + # Initialize initial guess for iterative solver + if self.solver_type != 'direct' and self.solver_type != 'spsolve': + self.initial_guess = np.zeros((self.len_x, self.len_y, self.len_z), dtype=float) + for i in range(self.len_x - 1): + self.initial_guess[i] = i / (self.len_x - 2.) + self.initial_guess = self.initial_guess.flatten('F') + + def assemble_bvector(self): print("Assembling b vector ... ", flush=True, end='') I, V = ([] for _ in range(2)) @@ -113,113 +123,8 @@ def __assemble_bvector(self): self._print_b(self.print_matrices[0]) print("Done") - def __compute_Kmat(self, i, i_cv): - # reset layer of Cmat - self.Kmat[i].fill(0) - - for key, value in self.mat_cond.items(): - mask = self.ws_pad[i_cv] == key - if len(value) == 6: # passing input conductivity - self.Kmat[i, mask] = value - else: # tensor rotation of input conductivity with orientation - phi = np.arctan2(self.orient_pad[i_cv, mask, 1], self.orient_pad[i_cv, mask, 0]) - theta = np.arcsin(self.orient_pad[i_cv, mask, 2]) - - size = np.sum(mask) - Rz_kinit = np.zeros((size, 3, 3), dtype=float) - Ry_krot = np.zeros((size, 3, 3), dtype=float) - - Rz_kinit[:, 0, 0] = np.cos(phi) - Rz_kinit[:, 1, 1] = Rz_kinit[:, 0, 0] - Rz_kinit[:, 1, 0] = np.sin(phi) - Rz_kinit[:, 0, 1] = -Rz_kinit[:, 1, 0] - Rz_kinit[:, 2, 2] = 1 - Ry_krot[:, 1, 1] = 1 - Ry_krot[:, 0, 0] = np.cos(theta) - Ry_krot[:, 2, 2] = Ry_krot[:, 0, 0] - Ry_krot[:, 0, 2] = np.sin(theta) - Ry_krot[:, 2, 0] = -Ry_krot[:, 0, 2] - - R = Rz_kinit @ Ry_krot - - Rz_kinit.fill(0) - Rz_kinit[:, [0, 1, 2], [0, 1, 2]] = [value[0], value[1], value[1]] - - Ry_krot = R @ Rz_kinit @ np.linalg.inv(R) - self.Kmat[i, mask] = Ry_krot[:, [0, 1, 2, 0, 0, 1], [0, 1, 2, 1, 2, 2]] - - def __compute_transmissibility(self, i, i_cv): - # reset layers - self.Emat[i].fill(0) - self.unstable[i].fill(False) - self.kf.fill(0) - - # if any of the surrounding CV have a zero diagonal cond, then set IV as unstable to skip computation - flatten_Kmat_find_unstable_iv(self.len_y, self.len_z, self.Kmat[i:i + 2], self.kf, self.unstable[i]) - - # creating C - self.mpfa12x12.fill(0) - self.mpfa12x12[:, :, self.Cind[0], self.Cind[1]] = fill_Cmpfa(self.kf) - - # Computing transmissibility matrix as: A @ (Cinv @ D) + B - if not np.all(self.unstable[i]): - - # creating D - self.Emat[i, :, :, self.Dind[0], self.Dind[1]] = fill_Dmpfa(self.kf) - self.Emat[i, self.unstable[i]] = 0 - - # computing: Cinv - self.mpfa12x12[~self.unstable[i]] = np.linalg.inv(self.mpfa12x12[~self.unstable[i]]) - - # computing: Cinv @ D - self.Emat[i, ~self.unstable[i]] = self.mpfa12x12[~self.unstable[i]] @ self.Emat[i, ~self.unstable[i]] - - # creating A - self.mpfa12x12.fill(0) - self.mpfa12x12[:, :, self.Aind[0], self.Aind[1]] = fill_Ampfa(self.kf) - - # computing: A @ (Cinv @ D) - self.Emat[i, ~self.unstable[i]] = self.mpfa12x12[~self.unstable[i]] @ self.Emat[i, ~self.unstable[i]] - - # creating and adding B: A @ (Cinv @ D) + B - self.Emat[i, ~self.unstable[i]] += fill_Bmpfa(self.kf, self.zeros)[~self.unstable[i]] - - if self.print_matrices[1]: - self._print_E(i, i_cv, self.print_matrices[1]) - - def __initialize_MPFA(self): - # Initialize matrix slice of conductivities - self.Kmat = np.zeros((3, self.len_y, self.len_z, 6), dtype=float) # per CV: kxx, kyy, kzz, kxy, kxz, kyz - self.__compute_Kmat(0, 0) # Computing first layer of Kmat - self.__compute_Kmat(1, 1) # Computing second layer of Kmat - - # Initialize MPFA variables - self.kf = np.zeros((48, self.len_y - 1, self.len_z - 1), dtype=float) # per IV - self.Emat = np.zeros((2, self.len_y - 1, self.len_z - 1, 12, 8), dtype=float) - self.unstable = np.zeros((2, self.len_y - 1, self.len_z - 1), dtype=bool) - self.mpfa12x12 = np.zeros((self.len_y - 1, self.len_z - 1, 12, 12), dtype=float) # A, C - self.zeros = np.zeros(self.kf[0].shape) - self.Aind, self.Cind, self.Dind = create_mpfa_indices() - self.__compute_transmissibility(0, 0) # Computing first layer of E - - def __creating_indices(self, i): - # Finding all indices for slice - i_indices = np.ones_like(self.ws_pad[i], dtype=np.uint32) - i_indices[[0, -1], :] = 0 - i_indices[:, [0, -1]] = 0 - i_indices = np.where(i_indices > 0) - i_indices = self.len_x * (self.len_y * i_indices[1] + i_indices[0]) + np.full(i_indices[0].size, i) - - # Removing dirichlet voxels - i_dirvox = np.where(self.dir_vox[i]) - i_dirvox = self.len_x * (self.len_y * i_dirvox[1] + i_dirvox[0]) + np.full(i_dirvox[0].size, i) - i_indices = i_indices[~np.in1d(i_indices, i_dirvox)] - - # Duplicating the voxel indices where divergence happens - i_indices = np.repeat(i_indices, 27) - return i_indices, i_dirvox # returning dirichlet voxel indices - def __assemble_Amatrix(self): + def assemble_Amatrix(self): print("Initializing large data structures ... ", flush=True, end='') I, J = np.zeros((2, 27 * self.len_xyz), dtype=np.uint32) V = np.zeros(27 * self.len_xyz, dtype=float) @@ -304,54 +209,10 @@ def __assemble_Amatrix(self): self._print_A(self.print_matrices[2]) print("Done") - def __solve(self): - print("Solving Ax=b system ... ", end='') - - info = 0 - if self.solver_type == 'direct': - print("Direct solver", end='') - x = spsolve(self.Amat, self.bvec) - - else: # iterative solvers - Tinitial_guess = np.zeros((self.len_x, self.len_y, self.len_z), dtype=float) - for i in range(self.len_x - 1): - Tinitial_guess[i] = i / (self.len_x - 2.) - Tinitial_guess = Tinitial_guess.flatten('F') - - if self.solver_type == 'gmres': - print("gmres:") - if self.display_iter: - x, info = gmres(self.Amat, self.bvec.todense(), x0=Tinitial_guess, atol=self.tolerance, - maxiter=self.maxiter, callback=SolverDisplay(), M=self.M) - else: - x, info = gmres(self.Amat, self.bvec.todense(), x0=Tinitial_guess, atol=self.tolerance, - maxiter=self.maxiter, M=self.M) - - elif self.solver_type == 'cg': - print("Conjugate Gradient:") - if self.display_iter: - x, info = cg(self.Amat, self.bvec.todense(), x0=Tinitial_guess, atol=self.tolerance, - maxiter=self.maxiter, callback=SolverDisplay(), M=self.M) - else: - x, info = cg(self.Amat, self.bvec.todense(), x0=Tinitial_guess, atol=self.tolerance, - maxiter=self.maxiter, M=self.M) - - else: - if self.solver_type != 'bicgstab': - print_warning("Unrecognized solver, defaulting to bicgstab.") - print("Bicgstab:") - if self.display_iter: - x, info = bicgstab(self.Amat, self.bvec.todense(), x0=Tinitial_guess, atol=self.tolerance, - maxiter=self.maxiter, M=self.M, callback=SolverDisplay()) - else: - x, info = bicgstab(self.Amat, self.bvec.todense(), x0=Tinitial_guess, atol=self.tolerance, - maxiter=self.maxiter, M=self.M) - - if info != 0: - raise Exception("Solver error: " + str(info)) - - del self.Amat, self.bvec - self.T = x.reshape([self.len_x, self.len_y, self.len_z], order='F') + def compute_effective_coefficient(self): + # reshaping solution + self.T = self.x.reshape([self.len_x, self.len_y, self.len_z], order='F') + del self.x # Mirroring boundaries for flux computation self.T[0] = self.T[1] @@ -361,9 +222,7 @@ def __solve(self): self.T[:, -1] = self.T[:, -2] self.T[:, :, 0] = self.T[:, :, 1] self.T[:, :, -1] = self.T[:, :, -2] - return True, print(" ... Done") - def __compute_effective_coefficient(self): self.__compute_fluxes() # Accumulating and volume averaging stresses @@ -381,6 +240,115 @@ def __compute_effective_coefficient(self): self.q = self.q.transpose(2, 1, 0, 3)[:, :, :, [2, 1, 0]] self.keff = [self.keff[2], self.keff[1], self.keff[0]] + d = {'x': 'first', 'y': 'second', 'z': 'third'} + print(f'\nEffective conductivity tensor ({d[self.direction]} row): \n{self.keff}') + + def __compute_Kmat(self, i, i_cv): + # reset layer of Cmat + self.Kmat[i].fill(0) + + for key, value in self.mat_cond.items(): + mask = self.ws_pad[i_cv] == key + if len(value) == 6: # passing input conductivity + self.Kmat[i, mask] = value + else: # tensor rotation of input conductivity with orientation + phi = np.arctan2(self.orient_pad[i_cv, mask, 1], self.orient_pad[i_cv, mask, 0]) + theta = np.arcsin(self.orient_pad[i_cv, mask, 2]) + + size = np.sum(mask) + Rz_kinit = np.zeros((size, 3, 3), dtype=float) + Ry_krot = np.zeros((size, 3, 3), dtype=float) + + Rz_kinit[:, 0, 0] = np.cos(phi) + Rz_kinit[:, 1, 1] = Rz_kinit[:, 0, 0] + Rz_kinit[:, 1, 0] = np.sin(phi) + Rz_kinit[:, 0, 1] = -Rz_kinit[:, 1, 0] + Rz_kinit[:, 2, 2] = 1 + Ry_krot[:, 1, 1] = 1 + Ry_krot[:, 0, 0] = np.cos(theta) + Ry_krot[:, 2, 2] = Ry_krot[:, 0, 0] + Ry_krot[:, 0, 2] = np.sin(theta) + Ry_krot[:, 2, 0] = -Ry_krot[:, 0, 2] + + R = Rz_kinit @ Ry_krot + + Rz_kinit.fill(0) + Rz_kinit[:, [0, 1, 2], [0, 1, 2]] = [value[0], value[1], value[1]] + + Ry_krot = R @ Rz_kinit @ np.linalg.inv(R) + self.Kmat[i, mask] = Ry_krot[:, [0, 1, 2, 0, 0, 1], [0, 1, 2, 1, 2, 2]] + + def __compute_transmissibility(self, i, i_cv): + # reset layers + self.Emat[i].fill(0) + self.unstable[i].fill(False) + self.kf.fill(0) + + # if any of the surrounding CV have a zero diagonal cond, then set IV as unstable to skip computation + flatten_Kmat_find_unstable_iv(self.len_y, self.len_z, self.Kmat[i:i + 2], self.kf, self.unstable[i]) + + # creating C + self.mpfa12x12.fill(0) + self.mpfa12x12[:, :, self.Cind[0], self.Cind[1]] = fill_Cmpfa(self.kf) + + # Computing transmissibility matrix as: A @ (Cinv @ D) + B + if not np.all(self.unstable[i]): + + # creating D + self.Emat[i, :, :, self.Dind[0], self.Dind[1]] = fill_Dmpfa(self.kf) + self.Emat[i, self.unstable[i]] = 0 + + # computing: Cinv + self.mpfa12x12[~self.unstable[i]] = np.linalg.inv(self.mpfa12x12[~self.unstable[i]]) + + # computing: Cinv @ D + self.Emat[i, ~self.unstable[i]] = self.mpfa12x12[~self.unstable[i]] @ self.Emat[i, ~self.unstable[i]] + + # creating A + self.mpfa12x12.fill(0) + self.mpfa12x12[:, :, self.Aind[0], self.Aind[1]] = fill_Ampfa(self.kf) + + # computing: A @ (Cinv @ D) + self.Emat[i, ~self.unstable[i]] = self.mpfa12x12[~self.unstable[i]] @ self.Emat[i, ~self.unstable[i]] + + # creating and adding B: A @ (Cinv @ D) + B + self.Emat[i, ~self.unstable[i]] += fill_Bmpfa(self.kf, self.zeros)[~self.unstable[i]] + + if self.print_matrices[1]: + self._print_E(i, i_cv, self.print_matrices[1]) + + def __initialize_MPFA(self): + # Initialize matrix slice of conductivities + self.Kmat = np.zeros((3, self.len_y, self.len_z, 6), dtype=float) # per CV: kxx, kyy, kzz, kxy, kxz, kyz + self.__compute_Kmat(0, 0) # Computing first layer of Kmat + self.__compute_Kmat(1, 1) # Computing second layer of Kmat + + # Initialize MPFA variables + self.kf = np.zeros((48, self.len_y - 1, self.len_z - 1), dtype=float) # per IV + self.Emat = np.zeros((2, self.len_y - 1, self.len_z - 1, 12, 8), dtype=float) + self.unstable = np.zeros((2, self.len_y - 1, self.len_z - 1), dtype=bool) + self.mpfa12x12 = np.zeros((self.len_y - 1, self.len_z - 1, 12, 12), dtype=float) # A, C + self.zeros = np.zeros(self.kf[0].shape) + self.Aind, self.Cind, self.Dind = create_mpfa_indices() + self.__compute_transmissibility(0, 0) # Computing first layer of E + + def __creating_indices(self, i): + # Finding all indices for slice + i_indices = np.ones_like(self.ws_pad[i], dtype=np.uint32) + i_indices[[0, -1], :] = 0 + i_indices[:, [0, -1]] = 0 + i_indices = np.where(i_indices > 0) + i_indices = self.len_x * (self.len_y * i_indices[1] + i_indices[0]) + np.full(i_indices[0].size, i) + + # Removing dirichlet voxels + i_dirvox = np.where(self.dir_vox[i]) + i_dirvox = self.len_x * (self.len_y * i_dirvox[1] + i_dirvox[0]) + np.full(i_dirvox[0].size, i) + i_indices = i_indices[~np.in1d(i_indices, i_dirvox)] + + # Duplicating the voxel indices where divergence happens + i_indices = np.repeat(i_indices, 27) + return i_indices, i_dirvox # returning dirichlet voxel indices + def __compute_fluxes(self): # Initialize required data structures self.q = np.zeros((self.len_x - 2, self.len_y - 2, self.len_z - 2, 3), dtype=float) @@ -480,13 +448,12 @@ def _print_A(self, dec=4): print(self.Amat.toarray()) def _print_b(self, dec=1): - vector = self.bvec.toarray() print() print("b vector:") for k in range(self.len_z): for i in range(self.len_x): for j in range(self.len_y): - print('{:.{}f}'.format(vector[self.len_x * (self.len_y * k + j) + i, 0], dec), end=' ') + print('{:.{}f}'.format(self.bvec[self.len_x * (self.len_y * k + j) + i, 0], dec), end=' ') print() print() diff --git a/python/pumapy/physicsmodels/mpsa_elasticity.py b/python/pumapy/physicsmodels/mpsa_elasticity.py index 19baa4d..f2fb06e 100644 --- a/python/pumapy/physicsmodels/mpsa_elasticity.py +++ b/python/pumapy/physicsmodels/mpsa_elasticity.py @@ -4,25 +4,23 @@ from pumapy.physicsmodels.mpxa_matrices import fill_Ampsa, fill_Bmpsa, fill_Cmpsa, fill_Dmpsa, create_mpsa_indices from pumapy.utilities.workspace import Workspace from pumapy.utilities.boundary_conditions import ElasticityBC -from pumapy.physicsmodels.isotropic_conductivity import SolverDisplay -from pumapy.utilities.logger import print_warning -import numpy as np +from pumapy.utilities.linear_solvers import PropertySolver +from pumapy.utilities.timer import Timer from scipy.sparse import csr_matrix, diags -from scipy.sparse.linalg import bicgstab, spsolve, cg, gmres +import numpy as np import sys -class Elasticity: +class Elasticity(PropertySolver): + def __init__(self, workspace, elast_map, direction, side_bc, prescribed_bc, tolerance, maxiter, solver_type, display_iter, print_matrices): - self.ws = workspace + allowed_solvers = ['direct', 'gmres', 'cg', 'bicgstab'] + super().__init__(workspace, solver_type, allowed_solvers, tolerance, maxiter, display_iter) + self.elast_map = elast_map self.direction = direction self.side_bc = side_bc - self.tolerance = tolerance - self.maxiter = maxiter - self.solver_type = solver_type - self.display_iter = display_iter self.prescribed_bc = prescribed_bc self.print_matrices = print_matrices self.mat_elast = dict() @@ -34,19 +32,17 @@ def __init__(self, workspace, elast_map, direction, side_bc, prescribed_bc, tole self.u = np.zeros([1, 1, 1]) self.s = np.zeros([1, 1, 1, 3]) self.t = np.zeros([1, 1, 1, 3]) - self.len_x = self.ws.matrix.shape[0] - self.len_y = self.ws.matrix.shape[1] - self.len_z = self.ws.matrix.shape[2] - self.len_xy = self.len_x * self.len_y - self.len_xyz = self.len_xy * self.len_z def compute(self): + t = Timer() self.initialize() self.assemble_bvector() self.assemble_Amatrix() - if not self.solve(): - return None + print("Time to assemble matrices: ", t.elapsed()); t.reset() + super().solve() + print("Time to solve: ", t.elapsed()) self.compute_effective_coefficient() + self.solve_time = t.elapsed() def initialize(self): print("Initializing and padding domains ... ", flush=True, end='') @@ -108,6 +104,13 @@ def initialize(self): self.dir_vox[1:-1, 1:-1, 1:-1][self.prescribed_bc.dirichlet != np.Inf] = True print("Done") + # Initialize initial guess for iterative solver + if self.solver_type != 'direct' and self.solver_type != 'spsolve': + self.initial_guess = np.zeros((self.len_x, self.len_y, self.len_z, 3), dtype=float) + for i in range(self.len_x - 1): + self.initial_guess[i, :, :, 0] = i / (self.len_x - 2.) + self.initial_guess = self.initial_guess.flatten('F') + def assemble_bvector(self): print("Assembling b vector ... ", flush=True, end='') @@ -154,6 +157,142 @@ def assemble_bvector(self): self._print_b(self.print_matrices[0]) print("Done") + def assemble_Amatrix(self): + print("Initializing large data structures ... ", flush=True, end='') + I, J = np.zeros((2, 81 * 3 * self.len_xyz), dtype=np.uint32) + V = np.zeros(81 * 3 * self.len_xyz, dtype=float) + counter = 0 # counter to keep record of the index in Amat + I_dirvox = [] + self.__initialize_MPSA() + j_indices = np.zeros((81 * 3 * (self.len_y - 2) * (self.len_z - 2)), dtype=np.uint32) + values = np.zeros((81 * 3 * (self.len_y - 2) * (self.len_z - 2)), dtype=float) + self.dir_vox = self.dir_vox.astype(np.uint8) + print("Done") + + # Iterating through interior + for i in range(1, self.len_x - 1): + self.__compute_Cmat(2, i + 1) # Computing third layer of Cmat + self.__compute_transmissibility(1, i) # Computing second layer of E + + # If all surrounding IV are unstable (i.e. partly or all gaseous), then put middle CV as Dirichlet + find_unstable_vox(i, self.len_y, self.len_z, self.dir_vox, self.unstable) + + # Creating j indices and divergence values for slice + j_indices.fill(-1) + values.fill(np.NaN) + divP(i, self.len_x, self.len_y, self.len_z, self.dir_vox, j_indices, values, self.Emat) + + # Creating i indices for slice + i_indices, i_dirvox = self.__creating_indices(i) + if i_indices.size > 0: + I[counter:counter + i_indices.size] = i_indices + I_dirvox.extend(i_dirvox) + + if j_indices[j_indices != -1].size > 0: + J[counter:counter + i_indices.size] = j_indices[~np.isnan(values)] + V[counter:counter + i_indices.size] = values[~np.isnan(values)] + counter += i_indices.size + + # Passing second layer to first + self.Emat[0] = self.Emat[1] + self.unstable[0] = self.unstable[1] + self.Cmat[:2] = self.Cmat[1:] + sys.stdout.write("\rAssembling A matrix ... {:.1f}% ".format(i / (self.len_x - 2) * 100)) + + # Clear unnecessary variables before creating A + del self.Emat, self.Cf, self.Cmat, self.mpsa36x36, self.unstable + del self.dir_vox, i_indices, i_dirvox, i, j_indices, values + + # Adding all dirichlet voxels + I[counter:counter + len(I_dirvox)] = I_dirvox + J[counter:counter + len(I_dirvox)] = I_dirvox + V[counter:counter + len(I_dirvox)] = 1 + counter += len(I_dirvox) + del I_dirvox + + # Add diagonal 1s for exterior voxels + diag_1s = np.ones_like(self.ws_pad, dtype=int) + diag_1s[1:-1, 1:-1, 1:-1] = 0 # interior to 0 + ind = np.array(np.where(diag_1s > 0)) # indices of contour + diag_1s = self.len_x * (self.len_y * ind[2] + ind[1]) + ind[0] + diag_1s = np.hstack((diag_1s, self.len_xyz + diag_1s, 2 * self.len_xyz + diag_1s)) + diag_1s = diag_1s.astype(np.uint32) + del ind + I[counter:counter + diag_1s.size] = diag_1s + J[counter:counter + diag_1s.size] = diag_1s + V[counter:counter + diag_1s.size] = 1 + counter += diag_1s.size + + # Add non-diagonal 1s for exterior voxels + if self.side_bc is not "d" and self.side_bc is not "f": + I[counter:counter + diag_1s.size] = diag_1s + nondiag1s = np.ones_like(diag_1s, dtype=np.int8) + add_nondiag(diag_1s, nondiag1s, self.len_x, self.len_y, self.len_z, self.side_bc) + J[counter:counter + diag_1s.size] = diag_1s # CAREFUL: diag_1s reused for nondiag to optimize memory + if self.side_bc == "s": + V[counter:counter + diag_1s.size] = nondiag1s + else: + V[counter:counter + diag_1s.size] = -1 + del nondiag1s + del diag_1s, counter + + # Assemble sparse A matrix + self.Amat = csr_matrix((V, (I, J)), shape=(3 * self.len_xyz, 3 * self.len_xyz)) + + # Simple preconditioner + diag = self.Amat.diagonal() + if np.any(diag == 0): + self.M = None # identity matrix if singularity has happened in MPSA + else: + self.M = diags(1. / self.Amat.diagonal(), 0).tocsr() + + if self.print_matrices[2]: + self._print_A(self.print_matrices[2]) + print("Done") + + def compute_effective_coefficient(self): + # reshaping solution + self.u = self.x.reshape([self.len_x, self.len_y, self.len_z, 3], order='F') + del self.x + + # Mirroring boundaries for flux computation + if self.direction is not None: + self.u[0] = self.u[1] + self.u[-1] = self.u[-2] + if self.side_bc == "d" or self.side_bc == "f": + self.u[:, 0] = self.u[:, 1] + self.u[:, -1] = self.u[:, -2] + self.u[:, :, 0] = self.u[:, :, 1] + self.u[:, :, -1] = self.u[:, :, -2] + if self.print_matrices[3]: + show_u(self.u, self.print_matrices[3]) + print(" ... Done") + + self.__compute_stresses() + + if self.direction is not None: + # Accumulating and volume averaging stresses + stresses = [np.sum(self.s[:, :, :, i]) / ((self.len_x - 2) * (self.len_y - 2) * (self.len_z - 2)) for i in + range(3)] + stresses += [np.sum(self.t[:, :, :, i]) / ((self.len_x - 2) * (self.len_y - 2) * (self.len_z - 2)) for i in + range(3)] + self.Ceff = [stresses[i] * (self.len_x - 2) * self.ws.voxel_length for i in range(6)] + + # Rotating output back + if self.direction == 'y': + self.u = self.u.transpose(2, 0, 1, 3)[:, :, :, [2, 0, 1]] + self.s = self.s.transpose(2, 0, 1, 3)[:, :, :, [2, 0, 1]] + self.t = self.t.transpose(2, 0, 1, 3)[:, :, :, [2, 0, 1]] + self.Ceff = [self.Ceff[2], self.Ceff[0], self.Ceff[1], self.Ceff[5], self.Ceff[3], self.Ceff[4]] + elif self.direction == 'z': + self.u = self.u.transpose(1, 2, 0, 3)[:, :, :, [1, 2, 0]] + self.s = self.s.transpose(1, 2, 0, 3)[:, :, :, [1, 2, 0]] + self.t = self.t.transpose(1, 2, 0, 3)[:, :, :, [1, 2, 0]] + self.Ceff = [self.Ceff[1], self.Ceff[2], self.Ceff[0], self.Ceff[4], self.Ceff[5], self.Ceff[3]] + + d = {'x': 'first', 'y': 'second', 'z': 'third'} + print(f'\nEffective elasticity tensor ({d[self.direction]} row): \n{self.Ceff}') + def index_at(self, index, size): if self.side_bc == "p": if index == 0: @@ -292,185 +431,6 @@ def __creating_indices(self, i): i_indices = np.repeat(i_indices, 81) return i_indices, i_dirvox # returning dirichlet voxel indices - def assemble_Amatrix(self): - print("Initializing large data structures ... ", flush=True, end='') - I, J = np.zeros((2, 81 * 3 * self.len_xyz), dtype=np.uint32) - V = np.zeros(81 * 3 * self.len_xyz, dtype=float) - counter = 0 # counter to keep record of the index in Amat - I_dirvox = [] - self.__initialize_MPSA() - j_indices = np.zeros((81 * 3 * (self.len_y - 2) * (self.len_z - 2)), dtype=np.uint32) - values = np.zeros((81 * 3 * (self.len_y - 2) * (self.len_z - 2)), dtype=float) - self.dir_vox = self.dir_vox.astype(np.uint8) - print("Done") - - # Iterating through interior - for i in range(1, self.len_x - 1): - self.__compute_Cmat(2, i + 1) # Computing third layer of Cmat - self.__compute_transmissibility(1, i) # Computing second layer of E - - # If all surrounding IV are unstable (i.e. partly or all gaseous), then put middle CV as Dirichlet - find_unstable_vox(i, self.len_y, self.len_z, self.dir_vox, self.unstable) - - # Creating j indices and divergence values for slice - j_indices.fill(-1) - values.fill(np.NaN) - divP(i, self.len_x, self.len_y, self.len_z, self.dir_vox, j_indices, values, self.Emat) - - # Creating i indices for slice - i_indices, i_dirvox = self.__creating_indices(i) - if i_indices.size > 0: - I[counter:counter + i_indices.size] = i_indices - I_dirvox.extend(i_dirvox) - - if j_indices[j_indices != -1].size > 0: - J[counter:counter + i_indices.size] = j_indices[~np.isnan(values)] - V[counter:counter + i_indices.size] = values[~np.isnan(values)] - counter += i_indices.size - - # Passing second layer to first - self.Emat[0] = self.Emat[1] - self.unstable[0] = self.unstable[1] - self.Cmat[:2] = self.Cmat[1:] - sys.stdout.write("\rAssembling A matrix ... {:.1f}% ".format(i / (self.len_x - 2) * 100)) - - # Clear unnecessary variables before creating A - del self.Emat, self.Cf, self.Cmat, self.mpsa36x36, self.unstable - del self.dir_vox, i_indices, i_dirvox, i, j_indices, values - - # Adding all dirichlet voxels - I[counter:counter + len(I_dirvox)] = I_dirvox - J[counter:counter + len(I_dirvox)] = I_dirvox - V[counter:counter + len(I_dirvox)] = 1 - counter += len(I_dirvox) - del I_dirvox - - # Add diagonal 1s for exterior voxels - diag_1s = np.ones_like(self.ws_pad, dtype=int) - diag_1s[1:-1, 1:-1, 1:-1] = 0 # interior to 0 - ind = np.array(np.where(diag_1s > 0)) # indices of contour - diag_1s = self.len_x * (self.len_y * ind[2] + ind[1]) + ind[0] - diag_1s = np.hstack((diag_1s, self.len_xyz + diag_1s, 2 * self.len_xyz + diag_1s)) - diag_1s = diag_1s.astype(np.uint32) - del ind - I[counter:counter + diag_1s.size] = diag_1s - J[counter:counter + diag_1s.size] = diag_1s - V[counter:counter + diag_1s.size] = 1 - counter += diag_1s.size - - # Add non-diagonal 1s for exterior voxels - if self.side_bc is not "d" and self.side_bc is not "f": - I[counter:counter + diag_1s.size] = diag_1s - nondiag1s = np.ones_like(diag_1s, dtype=np.int8) - add_nondiag(diag_1s, nondiag1s, self.len_x, self.len_y, self.len_z, self.side_bc) - J[counter:counter + diag_1s.size] = diag_1s # CAREFUL: diag_1s reused for nondiag to optimize memory - if self.side_bc == "s": - V[counter:counter + diag_1s.size] = nondiag1s - else: - V[counter:counter + diag_1s.size] = -1 - del nondiag1s - del diag_1s, counter - - # Assemble sparse A matrix - self.Amat = csr_matrix((V, (I, J)), shape=(3 * self.len_xyz, 3 * self.len_xyz)) - - # Simple preconditioner - diag = self.Amat.diagonal() - if np.any(diag == 0): - self.M = None # identity matrix if singularity has happened in MPSA - else: - self.M = diags(1. / self.Amat.diagonal(), 0).tocsr() - - if self.print_matrices[2]: - self._print_A(self.print_matrices[2]) - print("Done") - - def solve(self): - print("Solving Ax=b system ... ", end='') - - info = 0 - if self.solver_type == 'direct': - print("Direct solver", end='') - x = spsolve(self.Amat, self.bvec) - - else: # iterative solvers - u_initial_guess = np.zeros((self.len_x, self.len_y, self.len_z, 3), dtype=float) - for i in range(self.len_x - 1): - u_initial_guess[i, :, :, 0] = i / (self.len_x - 2.) - u_initial_guess = u_initial_guess.flatten('F') - - if self.solver_type == 'gmres': - print("gmres:") - if self.display_iter: - x, info = gmres(self.Amat, self.bvec.todense(), x0=u_initial_guess, atol=self.tolerance, - maxiter=self.maxiter, callback=SolverDisplay(), M=self.M) - else: - x, info = gmres(self.Amat, self.bvec.todense(), x0=u_initial_guess, atol=self.tolerance, - maxiter=self.maxiter, M=self.M) - - elif self.solver_type == 'cg': - print("Conjugate Gradient:") - if self.display_iter: - x, info = cg(self.Amat, self.bvec.todense(), x0=u_initial_guess, atol=self.tolerance, - maxiter=self.maxiter, callback=SolverDisplay(), M=self.M) - else: - x, info = cg(self.Amat, self.bvec.todense(), x0=u_initial_guess, atol=self.tolerance, - maxiter=self.maxiter, M=self.M) - - else: - if self.solver_type != 'bicgstab': - print_warning("Unrecognized solver, defaulting to bicgstab.") - print("Bicgstab:") - if self.display_iter: - x, info = bicgstab(self.Amat, self.bvec.todense(), x0=u_initial_guess, atol=self.tolerance, - maxiter=self.maxiter, M=self.M, callback=SolverDisplay()) - else: - x, info = bicgstab(self.Amat, self.bvec.todense(), x0=u_initial_guess, atol=self.tolerance, - maxiter=self.maxiter, M=self.M) - - if info != 0: - raise Exception("Solver error: " + str(info)) - - del self.Amat, self.bvec - self.u = x.reshape([self.len_x, self.len_y, self.len_z, 3], order='F') - - # Mirroring boundaries for flux computation - if self.direction is not None: - self.u[0] = self.u[1] - self.u[-1] = self.u[-2] - if self.side_bc == "d" or self.side_bc == "f": - self.u[:, 0] = self.u[:, 1] - self.u[:, -1] = self.u[:, -2] - self.u[:, :, 0] = self.u[:, :, 1] - self.u[:, :, -1] = self.u[:, :, -2] - if self.print_matrices[3]: - show_u(self.u, self.print_matrices[3]) - print(" ... Done") - return True - - def compute_effective_coefficient(self): - self.__compute_stresses() - - if self.direction is not None: - # Accumulating and volume averaging stresses - stresses = [np.sum(self.s[:, :, :, i]) / ((self.len_x - 2) * (self.len_y - 2) * (self.len_z - 2)) for i in - range(3)] - stresses += [np.sum(self.t[:, :, :, i]) / ((self.len_x - 2) * (self.len_y - 2) * (self.len_z - 2)) for i in - range(3)] - self.Ceff = [stresses[i] * (self.len_x - 2) * self.ws.voxel_length for i in range(6)] - - # Rotating output back - if self.direction == 'y': - self.u = self.u.transpose(2, 0, 1, 3)[:, :, :, [2, 0, 1]] - self.s = self.s.transpose(2, 0, 1, 3)[:, :, :, [2, 0, 1]] - self.t = self.t.transpose(2, 0, 1, 3)[:, :, :, [2, 0, 1]] - self.Ceff = [self.Ceff[2], self.Ceff[0], self.Ceff[1], self.Ceff[5], self.Ceff[3], self.Ceff[4]] - elif self.direction == 'z': - self.u = self.u.transpose(1, 2, 0, 3)[:, :, :, [1, 2, 0]] - self.s = self.s.transpose(1, 2, 0, 3)[:, :, :, [1, 2, 0]] - self.t = self.t.transpose(1, 2, 0, 3)[:, :, :, [1, 2, 0]] - self.Ceff = [self.Ceff[1], self.Ceff[2], self.Ceff[0], self.Ceff[4], self.Ceff[5], self.Ceff[3]] - def __compute_stresses(self): # Initialize required data structures self.s, self.t = np.zeros((2, self.len_x - 2, self.len_y - 2, self.len_z - 2, 3)) @@ -546,6 +506,7 @@ def log_input(self): for i in range(self.elast_map.get_size()): low, high, cond = self.elast_map.get_material(i) self.ws.log.log_line(" - Material " + str(i) + "[" + str(low) + "," + str(high) + "," + str(cond) + "]") + self.ws.log.log_line("Solver Type: " + str(self.solver_type)) self.ws.log.log_line("Solver Tolerance: " + str(self.tolerance)) self.ws.log.log_line("Max Iterations: " + str(self.maxiter)) self.ws.log.write_log() @@ -653,7 +614,6 @@ def _print_A(self, dec=4): print(self.Amat.toarray()) def _print_b(self, dec=1): - vector = self.bvec.toarray() print() print("b vector:") print(" o---> y") @@ -662,10 +622,10 @@ def _print_b(self, dec=1): for k in range(self.len_z): for i in range(self.len_x): for j in range(self.len_y): - print('({:.{}f}, {:.{}f}, {:.{}f})'.format(vector[self.len_x * (self.len_y * k + j) + i, 0], dec, - vector[self.len_xyz + self.len_x * ( + print('({:.{}f}, {:.{}f}, {:.{}f})'.format(self.bvec[self.len_x * (self.len_y * k + j) + i, 0], dec, + self.bvec[self.len_xyz + self.len_x * ( self.len_y * k + j) + i, 0], dec, - vector[2 * self.len_xyz + self.len_x * ( + self.bvec[2 * self.len_xyz + self.len_x * ( self.len_y * k + j) + i, 0], dec), end=' ') print() print() diff --git a/python/pumapy/segmentation/porespace.py b/python/pumapy/segmentation/porespace.py index be871e4..c7261ca 100644 --- a/python/pumapy/segmentation/porespace.py +++ b/python/pumapy/segmentation/porespace.py @@ -12,6 +12,13 @@ def identify_porespace(workspace, solid_cutoff): :type solid_cutoff: tuple(int, int) :return: porespace marked as: 0 solid, 1 largest pore (likely open porosity), >1 other pores :rtype: ndarray + + :Example: + >>> import pumapy as puma + >>> ws = puma.generate_random_spheres((200, 200, 200), diameter=20, porosity=0.8, allow_intersect=True) + >>> ws.binarize_range((0, 128)) # invert material, i.e. consider spheres as pores + >>> pores = puma.identify_porespace(ws, (1, 1)) + >>> puma.render_volume(pores, (1, pores.max()), solid_color=None, cmap='jet') """ # error check @@ -47,6 +54,14 @@ def fill_closed_pores(workspace, solid_cutoff, fill_value, return_pores=False): added filler material. In addition, if return_pores==True, then it also returns the porespace marked as: 0 solid, 1 largest pore (likely open porosity), >1 other pores :rtype: Workspace + + :Example: + >>> import pumapy as puma + >>> ws = puma.generate_random_spheres((200, 200, 200), diameter=20, porosity=0.8, allow_intersect=True) + >>> ws.binarize_range((0, 128)) # invert material, i.e. consider spheres as pores + >>> filled_ws, pores = puma.fill_closed_pores(ws, solid_cutoff=(1, 1), fill_value=2, return_pores=True) + >>> puma.render_volume(pores, (1, pores.max()), solid_color=None, cmap='jet') + >>> puma.render_volume(filled_ws) """ pores = identify_porespace(workspace, solid_cutoff) diff --git a/python/pumapy/utilities/all_cpp_files.h b/python/pumapy/utilities/all_cpp_files.h deleted file mode 100644 index dd14277..0000000 --- a/python/pumapy/utilities/all_cpp_files.h +++ /dev/null @@ -1,83 +0,0 @@ -/* This file was partly generated using the following python code run from the pumapy/utilities/cpp folder: -all_files = [] -for x in os.walk(os.path.abspath("../../../../src")): - folder = x[0] - for f in os.listdir(folder): - if os.path.isfile(os.path.join(folder, f)): - all_files.append(f) -all_files.sort() -print(all_files) -*/ - -#include "operation.h" -#include "logger.cpp" -#include "timer.cpp" -#include "iterativesolvers.cpp" -#include "AMatrix.h" -#include "ej_diffusion.cpp" -#include "ej_AMatrix.cpp" -#include "fv_diffusion.cpp" -#include "fv_symmetricboundary.cpp" -#include "fv_AMatrix.cpp" -#include "fv_constantvalueboundary.cpp" -#include "fv_boundarycondition.h" -#include "fv_periodicboundary.cpp" -#include "fv_anisotropic_diffusion.cpp" -#include "fv_anisotropic_AMatrix.cpp" -#include "Printer.cpp" -#include "matrix.h" -#include "workspace.h" -#include "triangle.h" -#include "pstring.h" -#include "vector.h" -#include "cutoff.h" -#include "MarchingCubes.cpp" -#include "isosurfacehelper.cpp" -#include "LookUpTable.h" -#include "isosurface.cpp" -#include "prng_engine.h" -#include "filter.h" -#include "meanfilter3d.cpp" -#include "medianfilter3d.cpp" -#include "bilateralfilter.cpp" -#include "fio.h" -#include "err.h" -#include "swapit.h" -#include "export_STL_helper.cpp" -#include "export_STL.cpp" -#include "ostr.h" -#include "materialproperty.h" -#include "orientation.cpp" -#include "raycasting.cpp" -#include "artificialflux_diffusion.cpp" -#include "artificialflux.cpp" -#include "artificialflux_AMatrix.cpp" -#include "structuretensor.cpp" -#include "mp_volumefractionhelper.cpp" -#include "mp_volumefraction.cpp" -#include "meaninterceptlength.cpp" -#include "surfacearea.cpp" -#include "ej_tortuosity.cpp" -#include "fv_tortuosity.cpp" -#include "particles_isosurfacetortuosity.cpp" -#include "particles_cuberilletortuosity.cpp" -#include "tortuosity_unified.cpp" -#include "fv_anisotropic_thermalconductivity.cpp" -#include "ej_thermalconductivity.cpp" -#include "fv_thermalconductivity.cpp" -#include "ej_electricalconductivity.cpp" -#include "fv_electricalconductivity.cpp" -#include "generate.h" -#include "porespace.cpp" -#include "curvedcirclefiber.cpp" -#include "straightcirclefiber.cpp" -#include "randomfibersinput.h" -#include "fiber.cpp" -#include "randomfibers.cpp" -#include "curvedflowerfiber.cpp" -#include "straightflowerfiber.cpp" -#include "prescribedfibers.cpp" -#include "randomspheres.cpp" -#include "sphere.cpp" -#include "tpmsinput.h" -#include "tpms.cpp" diff --git a/python/pumapy/utilities/example_files.py b/python/pumapy/utilities/example_files.py new file mode 100644 index 0000000..10c340e --- /dev/null +++ b/python/pumapy/utilities/example_files.py @@ -0,0 +1,44 @@ +import os.path +import ntpath + + +def path_to_example_file(example_filename): + """ Path to example data that is installed with pumapy (used for testing and tutorial) + + :param example_filename: name of the example file (check python/pumapy/data for a list of example files) + :type example_filename: str + :return: path to the example file, which can be used to import it + :rtype: str + + :Example: + >>> import pumapy as puma + >>> ws_example = puma.import_3Dtiff(puma.path_to_example_file("200_fiberform.tif")) # import example file + >>> puma.plot_slices(ws_example) # visualize example file + """ + + path = ntpath.split(os.path.dirname(os.path.realpath(__file__)))[0] + file_path = os.path.join(path, 'data', example_filename) + + if not os.path.isfile(file_path): + raise Exception("Example file not found.") + + return file_path + + +def list_example_files(): + """ List all example files available inside the folder python/pumapy/data + + :return: List of example file names + :rtype: list + """ + + path = ntpath.split(os.path.dirname(os.path.realpath(__file__)))[0] + file_path = os.path.join(path, 'data') + + file_list = os.listdir(file_path) + return_list = [] + for file in file_list: + if file[-4:] == ".tif" or file[-7:] == ".pumapy" or file[-4:] == ".vti": + return_list.append(file) + + return return_list diff --git a/python/pumapy/utilities/isosurface.py b/python/pumapy/utilities/isosurface.py index e9a89a9..ddeda9c 100644 --- a/python/pumapy/utilities/isosurface.py +++ b/python/pumapy/utilities/isosurface.py @@ -19,6 +19,13 @@ def generate_isosurface(workspace, cutoff, flag_closed_edges=True, flag_gaussian :type flag_gaussian: bool, optional :return: triangulated surface :rtype: TriMesh + + :Example: + >>> import pumapy as puma + >>> ws_isosurface = puma.import_3Dtiff(puma.path_to_example_file("200_fiberform.tif")) + >>> ws_copy = ws_isosurface.copy() + >>> puma.utilities.isosurface.generate_isosurface(ws_copy, (128, 255)) + >>> puma.compare_slices(ws_copy, ws_isosurface) """ iso = Isosurface(workspace, cutoff, flag_closed_edges, flag_gaussian) diff --git a/python/pumapy/utilities/linear_solvers.py b/python/pumapy/utilities/linear_solvers.py new file mode 100644 index 0000000..a7df1fb --- /dev/null +++ b/python/pumapy/utilities/linear_solvers.py @@ -0,0 +1,99 @@ +import numpy as np +from pumapy.utilities.logger import print_warning +from scipy.sparse.linalg import bicgstab, spsolve, cg, gmres, minres +import inspect +import sys + + +class PropertySolver: + + def __init__(self, workspace, solver_type, allowed_solvers, tolerance, maxiter, display_iter): + self.ws = workspace + self.tolerance = tolerance + self.maxiter = maxiter + self.solver_type = solver_type + self.allowed_solvers = allowed_solvers + + # First two sparse matrices need to be defined in Property child class, last two are optional + self.Amat = None + self.bvec = None + self.initial_guess = None + self.M = None + + # it returns answer in + self.x = None + + self.del_matrices = True + + self.len_x, self.len_y, self.len_z = self.ws.matrix.shape + self.len_xy = self.len_x * self.len_y + self.len_xyz = self.len_xy * self.len_z + + self.callback = None + if display_iter: + if self.solver_type == "minres": + self.callback = MinResSolverDisplay() + else: + self.callback = SolverDisplay() + + def solve(self): + if self.solver_type not in self.allowed_solvers: + print_warning(f"Unrecognized solver, defaulting to {self.allowed_solvers[0]}.") + self.solver_type = self.allowed_solvers[0] + + print(f"Solving Ax=b using {self.solver_type} solver ... ", end='') + + info = 0 + if (self.solver_type == 'direct') and self.solver_type in self.allowed_solvers: + self.x = spsolve(self.Amat, self.bvec) + else: # in order to use UMFPACK in spsolve, bvec needs to be a sparse matrix + if not isinstance(self.bvec, np.ndarray): + self.bvec = self.bvec.todense() + + # iterative solvers + if self.solver_type == 'gmres' and self.solver_type in self.allowed_solvers: + self.x, info = gmres(self.Amat, self.bvec, x0=self.initial_guess, M=self.M, + atol=self.tolerance, maxiter=self.maxiter, callback=self.callback) + + elif self.solver_type == 'minres' and self.solver_type in self.allowed_solvers: + self.x, info = minres(self.Amat, self.bvec, x0=self.initial_guess, M=self.M, + tol=self.tolerance, maxiter=self.maxiter, callback=self.callback) + + elif self.solver_type == 'cg' and self.solver_type in self.allowed_solvers: + self.x, info = cg(self.Amat, self.bvec, x0=self.initial_guess, M=self.M, + atol=self.tolerance, maxiter=self.maxiter, callback=self.callback) + + elif self.solver_type == 'bicgstab' and self.solver_type in self.allowed_solvers: + self.x, info = bicgstab(self.Amat, self.bvec, x0=self.initial_guess, M=self.M, + atol=self.tolerance, maxiter=self.maxiter, callback=self.callback) + + if info > 0: + raise Exception("Convergence to tolerance not achieved.") + elif info < 0: + raise Exception("Solver illegal input or breakdown") + + if self.del_matrices: + del self.Amat, self.bvec, self.initial_guess + print(" ... Done") + + +class SolverDisplay(object): + def __init__(self): + self.niter = 0 + + def __call__(self, rk=None): + self.niter += 1 + frame = inspect.currentframe().f_back + sys.stdout.write("\rIteration: {}, driving modified residual = {:0.10f} --> target = {:0.10f}" + .format(self.niter, frame.f_locals['resid'], frame.f_locals['atol'])) + + +class MinResSolverDisplay(object): + def __init__(self): + self.niter = 0 + + def __call__(self, rk=None): + self.niter += 1 + frame = inspect.currentframe().f_back + sys.stdout.write("\rIteration: {}, driving either residual ({:0.10f}, {:0.10f}) --> target = {:0.10f}" + .format(self.niter, frame.f_locals['test1'], frame.f_locals['test2'], frame.f_locals['tol'])) diff --git a/python/pumapy/utilities/puma_v3_wrapper.cpp b/python/pumapy/utilities/puma_v3_wrapper.cpp deleted file mode 100755 index 16bd3ac..0000000 --- a/python/pumapy/utilities/puma_v3_wrapper.cpp +++ /dev/null @@ -1,1045 +0,0 @@ -#include "all_cpp_files.h" - -#include -#include -#include -#include - - -/* -------------------------------------------------------------------------- */ -// Helper Functions (definition at the bottom of the file) -/* -------------------------------------------------------------------------- */ -template -void py3DArrayDouble_to_pumaData(PyArrayObject *arrayin, WSorpumaMat *something, npy_intp *dims, int numThreads); -void pyDict_to_map(PyObject *pyDict, std::map *cMap); -void pyDict_to_map(PyObject *pyDict, std::map> *cMap); -void pumaMatrix_to_pyObject(puma::Matrix *pumaMat, PyObject *pyObj, const npy_intp *dims); - - -/* ---------------------------------------------------------------------------------------- */ -// The PuMA functions are wrapped into the first static void functions as required for use in Python. -// The second accompanying static PyObject functions read the arguments that are called in python as: -// The O refers to a PyObject or PyArrayObject as an argument (used for numpy arrays and dictionaries). -// O! PyDict_Type -// d refers to a double. -// i refers to an integer. -// s refers to a string. -// The PyObjects are used to derive corresponding C-Objects, which are used in calling the PuMA functions. -/* ---------------------------------------------------------------------------------------- */ - -static void electricalConductivityFV(puma::Workspace *WS, puma::Matrix *T, const std::map& matCond, - std::string sideBC, std::string solverType, char dir, double solverTol, - int solverMaxIt, bool print, int numThreads, puma::Vec3 *cond) { - - puma::Vec3 k = puma::compute_FVElectricalConductivity(WS, T, matCond, std::move(sideBC), std::move(solverType), dir, solverTol, - solverMaxIt, print, numThreads); - *cond = k; -} - -static PyObject *puma_electricalconductivityFV(PyObject *self, PyObject *args) -{ - PyArrayObject *WS_py; - double voxelLength; - PyObject *matCond_py; - const char *sideBC_py; - const char *solverType_py; - const char *dir_py; - double solverTol; - int solverMaxIt; - int print_py; - int Tfield_py; - int numThreads; - - // Reads the python arguments - if (!PyArg_ParseTuple(args, "OdO!sssdiiii", &WS_py, &voxelLength, &PyDict_Type, &matCond_py, &sideBC_py, &solverType_py, - &dir_py, &solverTol, &solverMaxIt, &print_py, &Tfield_py, &numThreads)) { - return nullptr; - } - - // Move Dictionary Data to Map - std::map matCond_c; - pyDict_to_map(matCond_py, &matCond_c); - - // Change python data types for use in PuMA - std::string sideBC_c = sideBC_py; - std::string solverType_c = solverType_py; - char dir_c = dir_py[0]; - bool print_c = print_py; - bool Tfield_c = Tfield_py; - - puma::Vec3 k; - puma::Matrix T; - npy_intp *dims = PyArray_DIMS(WS_py); - - // Move Numpy Data to PuMA Workspace - puma::Workspace WS(voxelLength); - py3DArrayDouble_to_pumaData(WS_py, &WS, dims, numThreads); - - // Run the PuMA Function - electricalConductivityFV(&WS,&T,matCond_c,sideBC_c,solverType_c,dir_c,solverTol,solverMaxIt,print_c,numThreads,&k); - - if (Tfield_c) - { - // Move temperature field to python object - PyObject* T_py = PyList_New(dims[0]*dims[1]*dims[2]); - pumaMatrix_to_pyObject(&T, T_py, dims); - - // Move conductivity to a python tuple and return - Py_ssize_t len = 4; - PyObject *tup = PyTuple_New(len); - PyTuple_SetItem(tup,0,PyFloat_FromDouble(k.x)); - PyTuple_SetItem(tup,1,PyFloat_FromDouble(k.y)); - PyTuple_SetItem(tup,2,PyFloat_FromDouble(k.z)); - PyTuple_SetItem(tup,3,T_py); - return tup; - } - else - { - // Move conductivity to a python tuple and return - Py_ssize_t len = 3; - PyObject *tup = PyTuple_New(len); - PyTuple_SetItem(tup,0,PyFloat_FromDouble(k.x)); - PyTuple_SetItem(tup,1,PyFloat_FromDouble(k.y)); - PyTuple_SetItem(tup,2,PyFloat_FromDouble(k.z)); - return tup; - } -} - - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - -static void thermalConductivityFV(puma::Workspace *WS, puma::Matrix *T, const std::map& matCond, - std::string sideBC, std::string solverType, char dir, double solverTol, - int solverMaxIt, bool print, int numThreads, puma::Vec3 *cond) { - - puma::Vec3 k = puma::compute_FVThermalConductivity(WS, T, matCond, std::move(sideBC), std::move(solverType), dir, solverTol, - solverMaxIt, print, numThreads); - *cond = k; -} - -static PyObject *puma_thermalconductivityFV(PyObject *self, PyObject *args) -{ - PyArrayObject *WS_py; - double voxelLength; - PyObject *matCond_py; - const char *sideBC_py; - const char *solverType_py; - const char *dir_py; - double solverTol; - int solverMaxIt; - int print_py; - int Tfield_py; - int numThreads; - - // Reads the python arguments - if (!PyArg_ParseTuple(args, "OdO!sssdiiii", &WS_py, &voxelLength, &PyDict_Type, &matCond_py, &sideBC_py, &solverType_py, - &dir_py, &solverTol, &solverMaxIt, &print_py, &Tfield_py, &numThreads)) { - return nullptr; - } - - // Move Dictionary Data to Map - std::map matCond_c; - pyDict_to_map(matCond_py, &matCond_c); - - // Change python data types for use in PuMA - std::string sideBC_c = sideBC_py; - std::string solverType_c = solverType_py; - char dir_c = dir_py[0]; - bool print_c = print_py; - bool Tfield_c = Tfield_py; - - puma::Vec3 k; - puma::Matrix T; - npy_intp *dims = PyArray_DIMS(WS_py); - - // Move Numpy Data to PuMA Workspace - puma::Workspace WS(voxelLength); - py3DArrayDouble_to_pumaData(WS_py, &WS, dims, numThreads); - - // Run the PuMA Function - thermalConductivityFV(&WS,&T,matCond_c,sideBC_c,solverType_c,dir_c,solverTol,solverMaxIt,print_c,numThreads,&k); - - if (Tfield_c) - { - // Move temperature field to python object - PyObject* T_py = PyList_New(dims[0]*dims[1]*dims[2]); - pumaMatrix_to_pyObject(&T, T_py, dims); - - // Move conductivity to a python tuple and return - Py_ssize_t len = 4; - PyObject *tup = PyTuple_New(len); - PyTuple_SetItem(tup,0,PyFloat_FromDouble(k.x)); - PyTuple_SetItem(tup,1,PyFloat_FromDouble(k.y)); - PyTuple_SetItem(tup,2,PyFloat_FromDouble(k.z)); - PyTuple_SetItem(tup,3,T_py); - return tup; - } - else - { - // Move conductivity to a python tuple and return - Py_ssize_t len = 3; - PyObject *tup = PyTuple_New(len); - PyTuple_SetItem(tup,0,PyFloat_FromDouble(k.x)); - PyTuple_SetItem(tup,1,PyFloat_FromDouble(k.y)); - PyTuple_SetItem(tup,2,PyFloat_FromDouble(k.z)); - return tup; - } -} - - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - -static void tortuosityFV(puma::Workspace *WS, puma::Matrix *C, int lowvoid, int highvoid, - std::string sideBC, std::string solverType, char dir, double solverTol, - int solverMaxIt, bool print, int numThreads, puma::Vec3 *tort) { - - puma::Vec3 tau = puma::compute_FVTortuosity(WS, C, puma::Cutoff(lowvoid, highvoid), std::move(sideBC), std::move(solverType), dir, - solverTol, solverMaxIt, print, numThreads); - - *tort = tau; -} - -static PyObject *puma_tortuosityFV(PyObject *self, PyObject *args) -{ - PyArrayObject *WS_py; - double voxelLength; - int lowvoid; - int highvoid; - const char *sideBC_py; - const char *solverType_py; - const char *dir_py; - double solverTol; - int solverMaxIt; - int print_py; - int Cfield_py; - int numThreads; - - // Reads the python arguments - if (!PyArg_ParseTuple(args, "Odiisssdiiii", &WS_py, &voxelLength, &lowvoid, &highvoid, &sideBC_py, &solverType_py, - &dir_py, &solverTol, &solverMaxIt, &print_py, &Cfield_py, &numThreads)) { - return nullptr; - } - - // Change python data types for use in PuMA - std::string sideBC_c = sideBC_py; - std::string solverType_c = solverType_py; - char dir_c = dir_py[0]; - bool print_c = print_py; - bool Cfield_c = Cfield_py; - - puma::Vec3 tau; - puma::Matrix C; - npy_intp *dims = PyArray_DIMS(WS_py); - - // Move Numpy Data to PuMA Workspace - puma::Workspace WS(voxelLength); - py3DArrayDouble_to_pumaData(WS_py, &WS, dims, numThreads); - - // Run the PuMA Function - tortuosityFV(&WS,&C,lowvoid,highvoid,sideBC_c,solverType_c,dir_c,solverTol,solverMaxIt,print_c,numThreads,&tau); - - if (Cfield_c) - { - // Move temperature field to python object - PyObject* C_py = PyList_New(dims[0]*dims[1]*dims[2]); - pumaMatrix_to_pyObject(&C, C_py, dims); - - // Move conductivity to a python tuple and return - Py_ssize_t len = 4; - PyObject *tup = PyTuple_New(len); - PyTuple_SetItem(tup,0,PyFloat_FromDouble(tau.x)); - PyTuple_SetItem(tup,1,PyFloat_FromDouble(tau.y)); - PyTuple_SetItem(tup,2,PyFloat_FromDouble(tau.z)); - PyTuple_SetItem(tup,3,C_py); - return tup; - } - else - { - // Move conductivity to a python tuple and return - Py_ssize_t len = 3; - PyObject *tup = PyTuple_New(len); - PyTuple_SetItem(tup,0,PyFloat_FromDouble(tau.x)); - PyTuple_SetItem(tup,1,PyFloat_FromDouble(tau.y)); - PyTuple_SetItem(tup,2,PyFloat_FromDouble(tau.z)); - return tup; - } -} - - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - -static void tortuosityParticlesCube(puma::Workspace *WS, int lowCutoff, int highCutoff, - int numParticles, double meanFreePath, double meanVelocity, int numThreads, - int randomSeed, double totalLength, puma::Vec3 *tort) { - - puma::TortuosityReturn tau = puma::compute_particle_cuberille_Tortuosity(WS, puma::Cutoff(lowCutoff, highCutoff), numParticles, meanFreePath, - meanVelocity, randomSeed, totalLength, numThreads); - *tort = tau.tortuosity; -} - -static PyObject *puma_tortuosityParticlesCube(PyObject *self, PyObject *args) -{ - - PyArrayObject *WS_py; - double voxelLength; - int lowCutoff; - int highCutoff; - int numParticles; - double meanFreePath; - double meanVelocity; - int numThreads; - int randomSeed; - double totalLength; - - // Reads the python arguments - if (!PyArg_ParseTuple(args, "Odiiiddiid", &WS_py, &voxelLength, &lowCutoff, &highCutoff, &numParticles, - &meanFreePath, &meanVelocity, &numThreads, &randomSeed, &totalLength)) { - return nullptr; - } - - puma::Vec3 tau; - npy_intp *dims = PyArray_DIMS(WS_py); - - // Move Numpy Data to PuMA Workspace - puma::Workspace WS(voxelLength); - py3DArrayDouble_to_pumaData(WS_py, &WS, dims, numThreads); - - // Run the PuMA Function - tortuosityParticlesCube(&WS,lowCutoff,highCutoff,numParticles,meanFreePath,meanVelocity,numThreads,randomSeed,totalLength,&tau); - - // Move conductivity to a python tuple and return - Py_ssize_t len = 3; - PyObject *tup = PyTuple_New(len); - PyTuple_SetItem(tup,0,PyFloat_FromDouble(tau.x)); - PyTuple_SetItem(tup,1,PyFloat_FromDouble(tau.y)); - PyTuple_SetItem(tup,2,PyFloat_FromDouble(tau.z)); - return tup; -} - - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - -static void diffusivityParticlesCube(puma::Workspace *WS, int lowCutoff, int highCutoff, - int numParticles, double meanFreePath, double meanVelocity, int numThreads, - int randomSeed, double totalLength, puma::Vec3 *diff) { - - puma::TortuosityReturn alpha = puma::compute_particle_cuberille_Tortuosity(WS, puma::Cutoff(lowCutoff, highCutoff), numParticles, meanFreePath, meanVelocity, randomSeed, totalLength, numThreads); - *diff = alpha.diffusivity; -} - -static PyObject *puma_diffusivityParticlesCube(PyObject *self, PyObject *args) -{ - - PyArrayObject *WS_py; - double voxelLength; - int lowCutoff; - int highCutoff; - int numParticles; - double meanFreePath; - double meanVelocity; - int numThreads; - int randomSeed; - double totalLength; - - // Reads the python arguments - if (!PyArg_ParseTuple(args, "Odiiiddiid", &WS_py, &voxelLength, &lowCutoff, &highCutoff, &numParticles, - &meanFreePath, &meanVelocity, &numThreads, &randomSeed, &totalLength)) { - return nullptr; - } - - puma::Vec3 diff; - npy_intp *dims = PyArray_DIMS(WS_py); - - // Move Numpy Data to PuMA Workspace - puma::Workspace WS(voxelLength); - py3DArrayDouble_to_pumaData(WS_py, &WS, dims, numThreads); - - // Run the PuMA Function - diffusivityParticlesCube(&WS,lowCutoff,highCutoff,numParticles,meanFreePath,meanVelocity,numThreads,randomSeed,totalLength,&diff); - - // Move conductivity to a python tuple and return - Py_ssize_t len = 3; - PyObject *tup = PyTuple_New(len); - PyTuple_SetItem(tup,0,PyFloat_FromDouble(diff.x)); - PyTuple_SetItem(tup,1,PyFloat_FromDouble(diff.y)); - PyTuple_SetItem(tup,2,PyFloat_FromDouble(diff.z)); - return tup; -} - - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - -static void meanInterceptLength(puma::Workspace *WS, int lowCutoff, int highCutoff, int numThreads, puma::Vec3 *mil) { - puma::Vec3 MIL = puma::compute_MeanInterceptLength(WS,puma::Cutoff(lowCutoff,highCutoff), numThreads); - *mil = MIL; -} - -static PyObject *puma_meaninterceptlength(PyObject *self, PyObject *args) -{ - PyArrayObject *WS_py; - double voxelLength; - int lowCutoff; - int highCutoff; - int numThreads; - - // Reads the python arguments - if (!PyArg_ParseTuple(args, "Odiii", &WS_py, &voxelLength, &lowCutoff, &highCutoff, &numThreads)) { - return nullptr; - } - - puma::Vec3 mil; - npy_intp *dims = PyArray_DIMS(WS_py); - - // Move Numpy Data to PuMA Workspace - puma::Workspace WS(voxelLength); - py3DArrayDouble_to_pumaData(WS_py, &WS, dims, numThreads); - - // Run the PuMA Function - meanInterceptLength(&WS,lowCutoff,highCutoff, numThreads, &mil); - - // Move conductivity to a python tuple and return - Py_ssize_t len = 3; - PyObject *tup = PyTuple_New(len); - PyTuple_SetItem(tup,0,PyFloat_FromDouble(mil.x)); - PyTuple_SetItem(tup,1,PyFloat_FromDouble(mil.y)); - PyTuple_SetItem(tup,2,PyFloat_FromDouble(mil.z)); - return tup; -} - - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - -static void surfaceAreaMC(puma::Workspace *grayWS, int lowCutoff, int highCutoff, bool interpVerts, std::pair *sa) { - std::pair area = puma::compute_SurfaceAreaMarchingCubes(grayWS, puma::Cutoff(lowCutoff, highCutoff), interpVerts); - *sa = area; -} - -static PyObject *puma_surfaceareaTriGrid(PyObject *self, PyObject *args) -{ - PyArrayObject *WS_py; - double voxelLength; - int lowCutOff; - int highCutOff; - int interpVerts_py; - int numThreads; - - // Reads the python arguments - if (!PyArg_ParseTuple(args, "Odiiii", &WS_py, &voxelLength, &lowCutOff, &highCutOff, &interpVerts_py, &numThreads)) { - return nullptr; - } - - // Move Numpy Data to PuMA Workspace - puma::Workspace WS(voxelLength); - npy_intp *dims = PyArray_DIMS(WS_py); - py3DArrayDouble_to_pumaData(WS_py, &WS, dims, numThreads); - - // Change python data types for use in PuMA - bool interpVerts_c = interpVerts_py; - - // Run the PuMA Function - std::pair surfArea; - surfaceAreaMC(&WS, lowCutOff, highCutOff, interpVerts_c, &surfArea); - - // Move conductivity to a python tuple and return - Py_ssize_t len = 2; - PyObject *tup = PyTuple_New(len); - PyTuple_SetItem(tup,0,PyFloat_FromDouble(surfArea.first)); - PyTuple_SetItem(tup,1,PyFloat_FromDouble(surfArea.second)); - return tup; -} - - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - -static void surfaceAreaV(puma::Workspace *grayWS, int lowCutoff, int highCutoff, std::pair *sa) { - std::pair area = puma::compute_SurfaceAreaVoxels(grayWS, puma::Cutoff(lowCutoff, highCutoff)); - *sa = area; -} - -static PyObject *puma_surfaceareaCubeGrid(PyObject *self, PyObject *args) -{ - PyArrayObject *WS_py; - double voxelLength; - int lowCutOff; - int highCutOff; - int numThreads; - - // Reads the python arguments - if (!PyArg_ParseTuple(args, "Odiii", &WS_py, &voxelLength, &lowCutOff, &highCutOff, &numThreads)) { - return nullptr; - } - - // Move Numpy Data to PuMA Workspace - puma::Workspace WS(voxelLength); - npy_intp *dims = PyArray_DIMS(WS_py); - py3DArrayDouble_to_pumaData(WS_py, &WS, dims, numThreads); - - // Run the PuMA Function - std::pair surfArea; - surfaceAreaV(&WS, lowCutOff, highCutOff, &surfArea); - - // Move conductivity to a python tuple and return - Py_ssize_t len = 2; - PyObject *tup = PyTuple_New(len); - PyTuple_SetItem(tup,0,PyFloat_FromDouble(surfArea.first)); - PyTuple_SetItem(tup,1,PyFloat_FromDouble(surfArea.second)); - return tup; -} - - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - -static void volumeFraction(puma::Workspace *grayWS, int lowCutoff, int highCutoff, int numThreads, double *vf) { - double VF = puma::compute_VolumeFraction(grayWS, puma::Cutoff(lowCutoff, highCutoff), numThreads); - *vf = VF; -} - -static PyObject *puma_volumefraction(PyObject *self, PyObject *args) -{ - PyArrayObject *WS_py; - double voxelLength; - int lowCutoff; - int highCutoff; - int numThreads; - - // Reads the python arguments - if (!PyArg_ParseTuple(args, "Odiii", &WS_py, &voxelLength, &lowCutoff, &highCutoff, &numThreads)) { - return nullptr; - } - - double vf; - npy_intp *dims = PyArray_DIMS(WS_py); - - // Move Numpy Data to PuMA Workspace - puma::Workspace WS(voxelLength); - py3DArrayDouble_to_pumaData(WS_py, &WS, dims, numThreads); - - // Run the PuMA Function - volumeFraction(&WS,lowCutoff,highCutoff, numThreads, &vf); - - // Return as python double - return PyFloat_FromDouble(vf); -} - - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - -static void anisotropicThermalConductivityFV(puma::Workspace *WS, puma::Matrix *T, puma::MatVec3 *q, const std::map>& matCond, - const std::string& method, const std::string& sideBC, const std::string& solverType, char dir, double solverTol, - int solverMaxIt, bool print, int numThreads, puma::Vec3 *cond) { // puma::MatVec3 *direction - - puma::Vec3 k = puma::compute_FVanisotropicThermalConductivity(WS,T,q,matCond,method,sideBC,solverType,dir,solverTol,solverMaxIt,print,numThreads); - *cond = k; -} - -static PyObject *puma_anisotropicThermalConductivityFV(PyObject *self, PyObject *args) -{ - PyArrayObject *WS_py; - double solverTol_py; - PyObject *matCond_py; - int numThreads,solverMaxIt_py,print_py, Tfield_py; - const char *method_py, *sideBC_py, *solverType_py, *dir_py; -// puma::MatVec3 direction_c(1,1,1); - - // Reads the python arguments -// int argCount = PyTuple_GET_SIZE(args); -// if (argCount == 13) { // for Homogeneous material - if (!PyArg_ParseTuple(args, "OO!ssssdiiii", &WS_py, &PyDict_Type, &matCond_py, &method_py, &sideBC_py, - &solverType_py, &dir_py, &solverTol_py, &solverMaxIt_py, &print_py, &Tfield_py, &numThreads)){ - return nullptr; - } -// } else { // for Heterogeneous material (direction matrix) -// PyArrayObject *FibDirX_py, *FibDirY_py, *FibDirZ_py; -// if (!PyArg_ParseTuple(args, "OidO!sssdiisOOOii:PuMA", &WS_py, &segmented_py, &voxelLength, &PyDict_Type, &matCond_py, &sideBC_py, &solverType_py, -// &dir_py, &solverTol_py, &solverMaxIt_py, &print_py, &method_py, &FibDirX_py, &FibDirY_py, &FibDirZ_py, &Tfield_py, &numThreads)){ -// return nullptr; -// } -// puma::Matrix< double > dirX_c,dirY_c,dirZ_c; -// npy_intp *dims = PyArray_DIMS(WS_py); -// py3DArrayDouble_to_pumaData(FibDirX_py, &dirX_c, dims, numThreads); -// py3DArrayDouble_to_pumaData(FibDirY_py, &dirY_c, dims, numThreads); -// py3DArrayDouble_to_pumaData(FibDirZ_py, &dirZ_c, dims, numThreads); -// direction_c.resize(dims[0], dims[1], dims[2]); -// for(int i=0; i> matCond_c; - pyDict_to_map(matCond_py, &matCond_c); - - std::string sideBC_c = sideBC_py; - char dir_c = dir_py[0]; - std::string solverType_c = solverType_py; - bool print_c = print_py; - bool Tfield_c = Tfield_py; - std::string method_c = method_py; - - npy_intp *dims = PyArray_DIMS(WS_py); - puma::Matrix T(dims[0], dims[1], dims[2]); - puma::MatVec3 q(dims[0], dims[1], dims[2]); - - puma::Vec3 k; - - // Move Numpy Data to PuMA Workspace - puma::Workspace WS_c; - py3DArrayDouble_to_pumaData(WS_py, &WS_c, dims, numThreads); - - // Run the PuMA Function - anisotropicThermalConductivityFV(&WS_c, &T, &q, matCond_c, method_c, sideBC_c, solverType_c, dir_c, solverTol_py, solverMaxIt_py, print_c, numThreads, &k); // &direction_c - - if (Tfield_c) - { - // Move temperature and flux to python object - PyObject* T_py = PyList_New(dims[0]*dims[1]*dims[2]); - pumaMatrix_to_pyObject(&T, T_py, dims); - - PyObject* qX_py = PyList_New(dims[0]*dims[1]*dims[2]); - PyObject* qY_py = PyList_New(dims[0]*dims[1]*dims[2]); - PyObject* qZ_py = PyList_New(dims[0]*dims[1]*dims[2]); - for(long i=0;i *dirs, puma::MatVec3 *tangents, puma::Matrix *error, int lowCutoff, int highCutoff, int numThreads, std::pair *MeanSD) { - - *MeanSD = puma::compute_orientationComparison(ws, dirs, tangents, error, puma::Cutoff(lowCutoff, highCutoff), numThreads); -} - -static PyObject *puma_orientationComparison(PyObject *self, PyObject *args) -{ - PyArrayObject *WS_py, *dirs_py, *tangents_py; - int lowCutoff, highCutoff; - int numThreads; - - // Reads the python arguments - if (!PyArg_ParseTuple(args, "OOOiii", &WS_py, &dirs_py, &tangents_py, &lowCutoff, &highCutoff, &numThreads)){ - return nullptr; - } - - npy_intp *dims = PyArray_DIMS(WS_py); - - puma::Matrix error; - long size = dims[0]*dims[1]*dims[2]; - - // Move Numpy Data to PuMA Workspace - puma::Workspace WS_c; - py3DArrayDouble_to_pumaData(WS_py, &WS_c, dims, numThreads); - - // Computed Mean and Standard Deviation - std::pair MeanSD; - - puma::MatVec3 dirs_c(dims[0],dims[1],dims[2]), tangents_c(dims[0],dims[1],dims[2]); - - // Passing numpy array arranged as dirs[x-y-z as 0-1-2][i,j,k] to puma::MatVec3 - double *data_c; - data_c = (double *) dirs_py->data; - - omp_set_num_threads(numThreads); -#pragma omp parallel for - for (long l=0; l(data_c[l], data_c[size+l], data_c[size*2+l]); - } - - data_c = (double *) tangents_py->data; - - omp_set_num_threads(numThreads); -#pragma omp parallel for - for (long l=0; l(data_c[l], data_c[size+l], data_c[size*2+l]); - } - - // Run the PuMA Function - orientationComparison(&WS_c,&dirs_c,&tangents_c,&error,lowCutoff,highCutoff,numThreads,&MeanSD); - - // Move temperature field to python object - PyObject* error_py = PyList_New(dims[0]*dims[1]*dims[2]); - pumaMatrix_to_pyObject(&error, error_py, dims); - - // Move three direction matrices to a python tuple and return - Py_ssize_t len = 3; - PyObject *tup = PyTuple_New(len); - PyTuple_SetItem(tup,0,PyFloat_FromDouble(MeanSD.first)); - PyTuple_SetItem(tup,1,PyFloat_FromDouble(MeanSD.second)); - PyTuple_SetItem(tup,2,error_py); - return tup; -} - - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - -static void orientationRC(puma::Workspace *WS, int lowCutoff, int highCutoff, int initAccuracy, int degreeAccuracy, - puma::MatVec3 *direction, int print, int numThreads) { - - puma::compute_orientationRC(WS,puma::Cutoff(lowCutoff,highCutoff),initAccuracy,degreeAccuracy,direction,print,numThreads); -} - -static PyObject *puma_orientationRC(PyObject *self, PyObject *args) -{ - PyArrayObject *WS_py; - int lowCutoff, highCutoff; - int degreeAccuracy, initAccuracy; - int print, numThreads; - - // Reads the python arguments - if (!PyArg_ParseTuple(args, "Oiiiiii", &WS_py, &lowCutoff, &highCutoff, &initAccuracy, °reeAccuracy, &print, &numThreads)){ - return nullptr; - } - - npy_intp *dims = PyArray_DIMS(WS_py); - puma::MatVec3 direction_c; - - // Move Numpy Data to PuMA Workspace - puma::Workspace WS_c; - py3DArrayDouble_to_pumaData(WS_py, &WS_c, dims, numThreads); - - // Run the PuMA Function - orientationRC(&WS_c, lowCutoff, highCutoff, initAccuracy, degreeAccuracy, &direction_c, print, numThreads); - - // Move direction vectors to python object (different than other cases since vectors inside puma Matrix) - long X=dims[0], Y=dims[1], Z=dims[2]; - PyObject* Xdir_py = PyList_New(X*Y*Z); - PyObject* Ydir_py = PyList_New(X*Y*Z); - PyObject* Zdir_py = PyList_New(X*Y*Z); - for(long i=0;i *q, int lowCutoff, int highCutoff, - double solverTol, int solverMaxIt, int print, int numThreads) { - - puma::compute_orientationAF(WS, q, puma::Cutoff(lowCutoff, highCutoff), solverTol, solverMaxIt, print, numThreads); -} - - -static PyObject *puma_orientationAF(PyObject *self, PyObject *args) -{ - PyArrayObject *WS_py; - int lowCutoff, highCutoff; - double solverTol; - int solverMaxIt; - int print; - int numThreads; - - // Reads the python arguments - if (!PyArg_ParseTuple(args, "Oiidiii", &WS_py, &lowCutoff, &highCutoff, &solverTol, &solverMaxIt, &print, &numThreads)){ - return nullptr; - } - - puma::MatVec3 q, qY, qZ; - npy_intp *dims = PyArray_DIMS(WS_py); - - // Move Numpy Data to PuMA Workspace - puma::Workspace WS; - py3DArrayDouble_to_pumaData(WS_py, &WS, dims, numThreads); - - // Run the PuMA Function - orientationAF(&WS,&q,lowCutoff,highCutoff,solverTol,solverMaxIt,print,numThreads); - - // Move q vectors to python object (different than other cases since vectors inside puma Matrix) - long X=dims[0], Y=dims[1], Z=dims[2]; - PyObject* qX_py = PyList_New(X*Y*Z); - PyObject* qY_py = PyList_New(X*Y*Z); - PyObject* qZ_py = PyList_New(X*Y*Z); - for(long i=0;i *direction, bool print, int numThreads) { - - puma::compute_orientationST(WS,dogSigma,gausRho,puma::Cutoff(lowCutoff,highCutoff),direction,print,numThreads); -} - -static PyObject *puma_orientationST(PyObject *self, PyObject *args) -{ - PyArrayObject *WS_py; - int lowCutoff, highCutoff; - double dogSigma, gausRho; - int print, numThreads; - - // Reads the python arguments - if (!PyArg_ParseTuple(args, "Oddiiii", &WS_py, &dogSigma, &gausRho, &lowCutoff, &highCutoff, &print, &numThreads)){ - return nullptr; - } - - npy_intp *dims = PyArray_DIMS(WS_py); - puma::MatVec3 direction_c; - - // Move Numpy Data to PuMA Workspace - puma::Workspace WS_c; - py3DArrayDouble_to_pumaData(WS_py, &WS_c, dims, numThreads); - - // Run the PuMA Function - orientationST(&WS_c, dogSigma, gausRho, lowCutoff, highCutoff, &direction_c, print, numThreads); - - // Move direction vectors to python object (different than other cases since vectors inside puma Matrix) - long X=dims[0], Y=dims[1], Z=dims[2]; - PyObject* Xdir_py = PyList_New(X*Y*Z); - PyObject* Ydir_py = PyList_New(X*Y*Z); - PyObject* Zdir_py = PyList_New(X*Y*Z); - for(long i=0;i -void py3DArrayDouble_to_pumaData(PyArrayObject *arrayin, WSorpumaMat *something, npy_intp *dims, int numThreads) { - - something->resize(dims[0],dims[1],dims[2]); // Set Workspace dimensions - - int itemsize = PyArray_ITEMSIZE(arrayin); - if (itemsize==1){ // unsigned char case - unsigned char *data_c; - data_c = (unsigned char *) arrayin->data; - - // Fill PuMA Workspace with array values - omp_set_num_threads(numThreads); -#pragma omp parallel for - for (long l=0; lat(l) = data_c[l]; - } - } - else if (itemsize==2){ // unsigned short case - unsigned short *data_c; - data_c = (unsigned short *) arrayin->data; - - omp_set_num_threads(numThreads); -#pragma omp parallel for - for (long l=0; lat(l) = data_c[l]; - } - } - else if (itemsize==4){ // unsigned int case - unsigned int *data_c; - data_c = (unsigned int *) arrayin->data; - - omp_set_num_threads(numThreads); -#pragma omp parallel for - for (long l=0; lat(l) = data_c[l]; - } - } - else if (itemsize==8){ // double case - double *data_c; - data_c = (double *) arrayin->data; - - omp_set_num_threads(numThreads); -#pragma omp parallel for - for (long l=0; lat(l) = data_c[l]; - } - } -} - -// Convert a python Dictionary into a map (of doubles) -void pyDict_to_map(PyObject *pyDict, std::map *cMap) { - - PyObject *key, *value; - Py_ssize_t pos = 0; - while (PyDict_Next(pyDict,&pos,&key,&value)){ - auto key_c = PyLong_AsLong(key); - double value_c = PyFloat_AsDouble(value); - (*cMap)[key_c] = value_c; - } -} - -// Convert a python Dictionary into a map (of vector doubles) -void pyDict_to_map(PyObject *pyDict, std::map> *cMap) { - - PyObject *key, *value; - std::vector value_c; - Py_ssize_t pos = 0; - while (PyDict_Next(pyDict,&pos,&key,&value)){ - long key_c = PyLong_AsLong(key); - Py_ssize_t sizevalueindict = PyList_Size(value); - value_c.resize(sizevalueindict); - for(long i=0;i *pumaMat, PyObject *pyObj, const npy_intp *dims) { - - for(long i=0;iat(i,j,k))); - } - } - } -} diff --git a/python/pumapy/utilities/workspace.py b/python/pumapy/utilities/workspace.py index 7a3837e..c47ffb4 100644 --- a/python/pumapy/utilities/workspace.py +++ b/python/pumapy/utilities/workspace.py @@ -309,6 +309,17 @@ def rescale(self, scale, segmented, anti_aliasing=True, interpolation_order=1): :type interpolation_order: int, optional :return: None """ + + unit_dim_check = None + if min(self.get_shape()) == 1: + if self.len_x() == 1: + unit_dim_check = 0 + elif self.len_y() == 1: + unit_dim_check = 1 + elif self.len_z() == 1: + unit_dim_check = 2 + self.matrix = np.squeeze(self.matrix) + if self.orientation.shape[:3] == self.matrix.shape: self.orientation = trans.rescale(self.orientation, scale, order=0, multichannel=True, preserve_range=True, anti_aliasing=False) @@ -317,6 +328,10 @@ def rescale(self, scale, segmented, anti_aliasing=True, interpolation_order=1): else: self.matrix = trans.rescale(self.matrix, scale, order=interpolation_order, anti_aliasing=anti_aliasing, preserve_range=True) + + if unit_dim_check is not None: + self.matrix = np.expand_dims(self.matrix, axis=unit_dim_check) + self.matrix = self.matrix.astype('uint16') print("Rescaled workspace size: {}".format(self.get_shape())) diff --git a/python/pumapy/visualization/render.py b/python/pumapy/visualization/render.py index 7c17fb3..4499bac 100644 --- a/python/pumapy/visualization/render.py +++ b/python/pumapy/visualization/render.py @@ -41,6 +41,11 @@ def render_volume(workspace, cutoff=None, solid_color=(1., 1., 1.), style='surfa :type notebook: bool, optional :return: None is plot_directly is True, otherwise a plotter object :rtype: pyvista.Plotter object or None + + :Example + >>> import pumapy as puma + >>> ws_volume = puma.import_3Dtiff(puma.path_to_example_file("200_fiberform.tif"), 1.3e-6) + >>> puma.render_volume(ws_volume) """ if cutoff is None: solid_color = None @@ -84,6 +89,11 @@ def render_contour(workspace, cutoff, solid_color=(1., 1., 1.), style='surface', :type notebook: bool, optional :return: None is plot_directly is True, otherwise a plotter object :rtype: pyvista.Plotter object or None + + :Example: + >>> import pumapy as puma + >>> ws_contour = puma.import_3Dtiff(puma.path_to_example_file("50_artfibers.tif")) + >>> puma.render_contour(ws_contour, (128,255)) """ r = Renderer(add_to_plot, "contour", workspace, cutoff, solid_color, style, origin, window_size, opacity, background, show_grid, plot_directly, show_axes, show_outline, None, None, notebook) @@ -125,6 +135,12 @@ def render_orientation(workspace, scale_factor=1., solid_color=(1., 1., 1.), sty :type notebook: bool, optional :return: None is plot_directly is True, otherwise a plotter object :rtype: pyvista.Plotter object or None + + :Example: + >>> import pumapy as puma + >>> ws_orientation = puma.import_3Dtiff(puma.path_to_example_file("100_fiberform.tif"), 1.3e-6) + >>> puma.compute_orientation_st(ws_orientation, 0.7, 1.4, (90, 255)) + >>> puma.render_orientation(ws_orientation) """ r = Renderer(add_to_plot, "glyph", workspace, None, solid_color, style, origin, window_size, opacity, background, show_grid, plot_directly, show_axes, show_outline, None, scale_factor, notebook) @@ -166,6 +182,10 @@ def render_contour_multiphase(workspace, cutoffs, solid_colors=None, style='surf :type notebook: bool, optional :return: None is plot_directly is True, otherwise a plotter object :rtype: pyvista.Plotter object or None + + >>> import pumapy as puma + >>> ws_multiphase = puma.import_3Dtiff(puma.path_to_example_file("100_fiberform.tif"), 1.3e-6) + >>> puma.render_contour_multiphase(ws_multiphase, ((100, 150), (150, 255))) """ if add_to_plot is None: diff --git a/python/pumapy/visualization/slicer.py b/python/pumapy/visualization/slicer.py index 116e6bc..04bf5a3 100644 --- a/python/pumapy/visualization/slicer.py +++ b/python/pumapy/visualization/slicer.py @@ -18,6 +18,10 @@ def plot_slices(ws_nparray, slice_direction='z', crange=None, cmap='gray', index :type: int :return: slicer object :rtype: PlotSlicer + + >>> import pumapy as puma + >>> ws = puma.import_3Dtiff(puma.path_to_example_file("100_fiberform.tif"), 1.3e-6) + >>> puma.plot_slices(ws) """ img, _ = PlotSlicer.error_checks(ws_nparray, None, slice_direction) @@ -50,6 +54,12 @@ def compare_slices(ws_nparray1, ws_nparray2, slice_direction='z', crange1=None, :type index: int :return: slicer object :rtype: CompareSlicer + + >>> import pumapy as puma + >>> ws = puma.import_3Dtiff(puma.path_to_example_file("100_fiberform.tif"), 1.3e-6) + >>> ws2 = ws.copy() + >>> ws2.binarize_range((100, 255)) + >>> puma.compare_slices(ws, ws2) """ img1, img2 = CompareSlicer.error_checks(ws_nparray1, ws_nparray2, slice_direction) diff --git a/python/test/test_isoconductivity.py b/python/test/test_isotropic_conductivity.py similarity index 100% rename from python/test/test_isoconductivity.py rename to python/test/test_isotropic_conductivity.py diff --git a/python/test/test_permeability.py b/python/test/test_permeability.py new file mode 100644 index 0000000..863e1ae --- /dev/null +++ b/python/test/test_permeability.py @@ -0,0 +1,37 @@ +import unittest +import numpy as np +import pumapy as puma + + +class TestAnisotropicTC(unittest.TestCase): + + def test_analytical_direct(self): + ws = puma.generate_2d_square_array(100, 1. - 2. * np.pi * (0.1 ** 2.)) + ws.binarize_range((128, 255)) + ws.voxel_length = 1. / ws.matrix.shape[0] + keff, _, _, _ = puma.compute_permeability(ws, (1, 1), solver_type='direct') + np.testing.assert_array_almost_equal(keff, np.array([[2.71223274e-02, 0., 0.], [0., 2.71223274e-02, 0.], [0., 0., 5.48134246e-02]])) + + def test_analytical_bicgstab(self): + ws = puma.generate_2d_square_array(100, 1. - 2. * np.pi * (0.1 ** 2.)) + ws.binarize_range((128, 255)) + ws.voxel_length = 1. / ws.matrix.shape[0] + keff, _, _, _ = puma.compute_permeability(ws, (1, 1), solver_type='bicgstab', tol=1e-7, maxiter=10000) + np.testing.assert_array_almost_equal(keff, np.array([[2.71223274e-02, 0., 0.], [0., 2.71223274e-02, 0.], [0., 0., 5.48134246e-02]]), decimal=4) + + def test_analytical_cg(self): + ws = puma.generate_2d_square_array(100, 1. - 2. * np.pi * (0.1 ** 2.)) + ws.binarize_range((128, 255)) + ws.voxel_length = 1. / ws.matrix.shape[0] + keff, _, _, _ = puma.compute_permeability(ws, (1, 1), solver_type='cg', tol=1e-7, maxiter=10000) + np.testing.assert_array_almost_equal(keff, np.array([[2.71223274e-02, 0., 0.], [0., 2.71223274e-02, 0.], [0., 0., 5.48134246e-02]]), decimal=4) + + def test_analytical_minres(self): + ws = puma.generate_2d_square_array(100, 1. - 2. * np.pi * (0.1 ** 2.)) + ws.binarize_range((128, 255)) + ws.voxel_length = 1. / ws.matrix.shape[0] + keff, _, _, _ = puma.compute_permeability(ws, (1, 1), solver_type='minres', tol=1e-8, maxiter=10000) + np.testing.assert_array_almost_equal(keff, np.array([[2.71223274e-02, 0., 0.], [0., 2.71223274e-02, 0.], [0., 0., 5.48134246e-02]]), decimal=4) + +if __name__ == '__main__': + unittest.main() diff --git a/python/test/test_radiation.py b/python/test/test_radiation.py index 7790b38..bc7eea7 100644 --- a/python/test/test_radiation.py +++ b/python/test/test_radiation.py @@ -27,7 +27,7 @@ def test_artfib(self): np.random.seed(0) beta, beta_std, _ = puma.compute_radiation(ws, (1, 1), 100, 15, boundary_behavior=0) print(beta) - np.testing.assert_almost_equal(beta, [0.18048920415267472, 0.17922697533941973, 0.1241739185326434]) + np.testing.assert_almost_equal(beta, [0.18048920415267472, 0.17922697533941973, 0.1241739185326434], decimal=4) if __name__ == '__main__': diff --git a/python/test/test_weave_io.py b/python/test/test_weave_io.py index 2bb0b79..eedae9f 100644 --- a/python/test/test_weave_io.py +++ b/python/test/test_weave_io.py @@ -2,61 +2,65 @@ import os pumadir = os.path.abspath('..') import pumapy as puma -from TexGen.Core import * +try: + from TexGen.Core import * -if os.path.exists(pumadir + "/python/TexGen/install/lib"): - class TestWeaveIO(unittest.TestCase): - def test_weave_io(self): - # Create a textile - Textile = CTextile() + if os.path.exists(pumadir + "/python/TexGen/install/lib"): + class TestWeaveIO(unittest.TestCase): - # Create a python list containing 4 yarns - Yarns = [CYarn(), CYarn(), CYarn(), CYarn()] + def test_weave_io(self): + # Create a textile + Textile = CTextile() - # Add nodes to the yarns to describe their paths - Yarns[0].AddNode(CNode(XYZ(0, 0, 0))) - Yarns[0].AddNode(CNode(XYZ(0.22, 0, 0.05))) - Yarns[0].AddNode(CNode(XYZ(0.44, 0, 0))) + # Create a python list containing 4 yarns + Yarns = [CYarn(), CYarn(), CYarn(), CYarn()] - Yarns[1].AddNode(CNode(XYZ(0, 0.22, 0.05))) - Yarns[1].AddNode(CNode(XYZ(0.22, 0.22, 0))) - Yarns[1].AddNode(CNode(XYZ(0.44, 0.22, 0.05))) + # Add nodes to the yarns to describe their paths + Yarns[0].AddNode(CNode(XYZ(0, 0, 0))) + Yarns[0].AddNode(CNode(XYZ(0.22, 0, 0.05))) + Yarns[0].AddNode(CNode(XYZ(0.44, 0, 0))) - Yarns[2].AddNode(CNode(XYZ(0, 0, 0.05))) - Yarns[2].AddNode(CNode(XYZ(0, 0.22, 0))) - Yarns[2].AddNode(CNode(XYZ(0, 0.44, 0.05))) + Yarns[1].AddNode(CNode(XYZ(0, 0.22, 0.05))) + Yarns[1].AddNode(CNode(XYZ(0.22, 0.22, 0))) + Yarns[1].AddNode(CNode(XYZ(0.44, 0.22, 0.05))) - Yarns[3].AddNode(CNode(XYZ(0.22, 0, 0))) - Yarns[3].AddNode(CNode(XYZ(0.22, 0.22, 0.05))) - Yarns[3].AddNode(CNode(XYZ(0.22, 0.44, 0))) + Yarns[2].AddNode(CNode(XYZ(0, 0, 0.05))) + Yarns[2].AddNode(CNode(XYZ(0, 0.22, 0))) + Yarns[2].AddNode(CNode(XYZ(0, 0.44, 0.05))) - # Loop over all the yarns in the list - for Yarn in Yarns: - # Set the interpolation function - Yarn.AssignInterpolation(CInterpolationCubic()) + Yarns[3].AddNode(CNode(XYZ(0.22, 0, 0))) + Yarns[3].AddNode(CNode(XYZ(0.22, 0.22, 0.05))) + Yarns[3].AddNode(CNode(XYZ(0.22, 0.44, 0))) - # Assign a constant cross-section all along the yarn of elliptical shape - Yarn.AssignSection(CYarnSectionConstant(CSectionEllipse(0.18, 0.04))) + # Loop over all the yarns in the list + for Yarn in Yarns: + # Set the interpolation function + Yarn.AssignInterpolation(CInterpolationCubic()) - # Set the resolution of the surface mesh created - Yarn.SetResolution(20) + # Assign a constant cross-section all along the yarn of elliptical shape + Yarn.AssignSection(CYarnSectionConstant(CSectionEllipse(0.18, 0.04))) - # Add repeat vectors to the yarn - Yarn.AddRepeat(XYZ(0.44, 0, 0)) - Yarn.AddRepeat(XYZ(0, 0.44, 0)) + # Set the resolution of the surface mesh created + Yarn.SetResolution(20) - # Add the yarn to our textile - Textile.AddYarn(Yarn) + # Add repeat vectors to the yarn + Yarn.AddRepeat(XYZ(0.44, 0, 0)) + Yarn.AddRepeat(XYZ(0, 0.44, 0)) - self.assertEqual(puma.export_weave_vtu(os.path.join(pumadir, "test", "out", "weavetest"), Textile, - CDomainPlanes(XYZ(0, 0, -0.02), XYZ(0.44, 0.44, 0.07)), 100), - os.path.join(pumadir, "test", "out", "weavetest_100_100_21")) + # Add the yarn to our textile + Textile.AddYarn(Yarn) - ws = puma.import_weave_vtu(os.path.join(pumadir, "test", "out", "weavetest_100_100_21.vtu")) - self.assertEqual(max(ws.matrix.shape), 100) + self.assertEqual(puma.export_weave_vtu(os.path.join(pumadir, "test", "out", "weavetest"), Textile, + CDomainPlanes(XYZ(0, 0, -0.02), XYZ(0.44, 0.44, 0.07)), 100), + os.path.join(pumadir, "test", "out", "weavetest_100_100_21")) + ws = puma.import_weave_vtu(os.path.join(pumadir, "test", "out", "weavetest_100_100_21.vtu")) + self.assertEqual(max(ws.matrix.shape), 100) + +except: + puma.print_warning("Could not run test_weave_io because of failed TexGen import.") if __name__ == '__main__': unittest.main() diff --git a/setup.py b/setup.py index 91378ab..0d50daa 100644 --- a/setup.py +++ b/setup.py @@ -18,42 +18,26 @@ def run(self): try: from Cython.Build import cythonize extensions = cythonize([ - Extension("pumapy.generation.tpms_utils", ["python/pumapy/generation/tpms_utils.pyx"]), - Extension("pumapy.physicsmodels.isotropic_conductivity_utils", ["python/pumapy/physicsmodels/isotropic_conductivity_utils.pyx"]), - Extension("pumapy.physicsmodels.anisotropic_conductivity_utils", ["python/pumapy/physicsmodels/anisotropic_conductivity_utils.pyx"]), - Extension("pumapy.physicsmodels.elasticity_utils", ["python/pumapy/physicsmodels/elasticity_utils.pyx"]), + Extension("pumapy.generation.tpms_utils", + [os.path.join("python", "pumapy", "generation", "tpms_utils.pyx")]), + Extension("pumapy.physicsmodels.isotropic_conductivity_utils", [os.path.join("python", "pumapy", "physicsmodels", "isotropic_conductivity_utils.pyx")]), + Extension("pumapy.physicsmodels.anisotropic_conductivity_utils", [os.path.join("python", "pumapy", "physicsmodels", "anisotropic_conductivity_utils.pyx")]), + Extension("pumapy.physicsmodels.elasticity_utils", [os.path.join("python", "pumapy", "physicsmodels", "elasticity_utils.pyx")]), ]) -except ImportError: +except ImportError: # if cython not found, use existing C code extensions = [ - Extension("pumapy.generation.tpms_utils", ["python/pumapy/generation/tpms_utils.c"]), - Extension("pumapy.physicsmodels.isotropic_conductivity_utils", ["python/pumapy/physicsmodels/isotropic_conductivity_utils.c"]), - Extension("pumapy.physicsmodels.anisotropic_conductivity_utils", ["python/pumapy/physicsmodels/anisotropic_conductivity_utils.c"]), - Extension("pumapy.physicsmodels.elasticity_utils", ["python/pumapy/physicsmodels/elasticity_utils.c"]), + Extension("pumapy.generation.tpms_utils", [os.path.join("python", "pumapy", "generation", "tpms_utils.c")]), + Extension("pumapy.physicsmodels.isotropic_conductivity_utils", [os.path.join("python", "pumapy", "physicsmodels", "isotropic_conductivity_utils.c")]), + Extension("pumapy.physicsmodels.anisotropic_conductivity_utils", [os.path.join("python", "pumapy", "physicsmodels", "anisotropic_conductivity_utils.c")]), + Extension("pumapy.physicsmodels.elasticity_utils", [os.path.join("python", "pumapy", "physicsmodels", "elasticity_utils.c")]), ] -# add PuMA C++ library to the extensions -# env_dir = os.environ['CONDA_PREFIX'] -# src_path = "./cpp/src" -# include_dirs = [x[0] for x in os.walk(os.path.abspath(src_path))] -# include_dirs.append(np.get_include()) -# include_dirs.append(env_dir + "/include") -# include_dirs.append(env_dir + "/include/eigen3/Eigen") -# include_dirs.append(os.path.abspath(src_path)) -# if platform == "darwin": -# extra_compile_args = ["-Xpreprocessor", "-fopenmp", "--std=c++0x", "-Wno-format", "-Wno-literal-conversion", -# "-Wno-deprecated-register", "-Wno-return-type"] -# else: # linux -# extra_compile_args = ["-fopenmp", "--std=c++0x"] -# extensions.append(Extension('pumapy.utilities.libPuMA', sources=['/python/pumapy/utilities/puma_v3_wrapper.cpp'], -# libraries=["omp", "fftw3", "fftw3_threads"], include_dirs=include_dirs, -# extra_compile_args=extra_compile_args)) - with open("README.md", "r", encoding="utf-8") as fh: long_description = fh.read() setup( name="pumapy", - version="3.0.0", + version="3.1.0", author="PuMA team", maintainer_email="federico.semeraro@nasa.gov, joseph.ferguson@stanford.edu", description="A package to compute material properties from micro-CT data.", @@ -63,7 +47,7 @@ def run(self): project_urls={ "Bug Tracker": "https://github.com/nasa/puma/issues", }, - platforms=["Linux", "Mac"], + platforms=["Linux", "Mac", "Windows"], package_dir={"": "python"}, packages=find_packages(where="python"), ext_modules=extensions, @@ -75,7 +59,7 @@ def run(self): "wheel", "numpy", ], - install_requires=[ # TexGen and fenics-dolfin also required but not listed here because not installable with pip + install_requires=[ # TexGen also required, but it can be installed as add-on "numpy", "scikit-image", "scipy", @@ -83,5 +67,12 @@ def run(self): "pyevtk", "pyvista", ], - package_data={'': ['data/*']}, # copy over all the example data + package_data={'': [os.path.join('data', '*')]}, # copy over all the example data + classifiers=[ + 'Development Status :: 5 - Production/Stable', + 'Operating System :: OS Independent', + 'Programming Language :: Python :: 3', + 'Topic :: Scientific/Engineering', + 'Topic :: Scientific/Engineering :: Physics', + ], ) diff --git a/tutorial/puma_tutorial.ipynb b/tutorial/puma_tutorial.ipynb index 8c3c5bb..4365afa 100644 --- a/tutorial/puma_tutorial.ipynb +++ b/tutorial/puma_tutorial.ipynb @@ -34,7 +34,7 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -67,7 +67,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 1, "metadata": {}, "outputs": [], "source": [ @@ -225,22 +225,13 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": null, "metadata": { "pycharm": { "name": "#%%\n" } }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Importing /Users/fsemerar/opt/anaconda3/envs/puma/lib/python3.7/site-packages/pumapy/data/200_fiberform.tif ... Done\n", - "Shape of workspace: (200, 200, 200)\n" - ] - } - ], + "outputs": [], "source": [ "ws_raw = puma.import_3Dtiff(puma.path_to_example_file(\"200_fiberform.tif\"), 1.3e-6)\n", "print(f\"Shape of workspace: {ws_raw.matrix.shape}\")" @@ -280,24 +271,9 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "36dae0ce276a4475a0505bf0c5b6b4ab", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "Canvas(toolbar=Toolbar(toolitems=[('Home', 'Reset original view', 'home', 'home'), ('Back', 'Back to previous …" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ "slices = puma.plot_slices(ws_raw, slice_direction='z', crange=None, cmap='gray', index=1)" ] @@ -311,24 +287,9 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "3b229951a70e4741aa7b8952c6c7d176", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "ViewInteractiveWidget(height=1200, layout=Layout(height='auto', width='100%'), width=1920)" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ "puma.render_volume(ws_raw, notebook=True)" ] @@ -563,7 +524,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "And that's it for exportint to vti! Let's repeat the same steps for .pumapy and 3D tiffs." + "And that's it for exporting to vti! Let's repeat the same steps for .pumapy and 3D tiffs." ] }, { @@ -813,7 +774,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Note that the contour renders for the segmented images are significantly less smooth than for the non-segmented images. This is because for segmented images, the triangulation algorithms have significantly less degrees of freedom when assigning triangle angles, resulting in a rougher surface than for non-segmented images. " + "Note that the contour renders for the segmented images are significantly less smooth than for the non-segmented images. This is because the triangulation algorithms have significantly less degrees of freedom when assigning triangle angles for segmented images, resulting in a rougher surface than for non-segmented images. " ] }, { @@ -883,7 +844,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "If you would like to visualize the individual sices, this can be done using the plot_slices function" + "If you would like to visualize the individual slices, this can be done using the plot_slices function" ] }, { @@ -1063,7 +1024,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Next, we will visualize the 3d Domains. To render the domain, the grayscale range corresponding to the material must be specified. In this case, the range of [128,255] corresponds to the material. " + "Next, we will visualize the 3D domains. To render the domain, the grayscale range corresponding to the material must be specified. In this case, the range of [128,255] corresponds to the material. " ] }, { @@ -1288,17 +1249,9 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Importing /Users/fsemerar/Documents/puma_playground/puma-dev/python/pumapy/data/100_fiberform.tif ... Done\n" - ] - } - ], + "outputs": [], "source": [ "ws = puma.import_3Dtiff(puma.path_to_example_file(\"100_fiberform.tif\"), 1.3e-6)" ] @@ -1314,34 +1267,9 @@ }, { "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [ - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "c0ca25ec50d34134a77a479265156cf2", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "Canvas(toolbar=Toolbar(toolitems=[('Home', 'Reset original view', 'home', 'home'), ('Back', 'Back to previous …" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 7, - "metadata": {}, - "output_type": "execute_result" - } - ], + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "ws_median = ws.copy()\n", "\n", @@ -1360,34 +1288,9 @@ }, { "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [ - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "8c7e88bb43dd4eba971aef1941656558", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "Canvas(toolbar=Toolbar(toolitems=[('Home', 'Reset original view', 'home', 'home'), ('Back', 'Back to previous …" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "ws_gaussian = ws.copy()\n", "\n", @@ -1405,34 +1308,9 @@ }, { "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [ - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "0ff94920a16744d9a799c2f050f48a0e", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "Canvas(toolbar=Toolbar(toolitems=[('Home', 'Reset original view', 'home', 'home'), ('Back', 'Back to previous …" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 10, - "metadata": {}, - "output_type": "execute_result" - } - ], + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "ws_edt = ws.copy()\n", "\n", @@ -1450,34 +1328,9 @@ }, { "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [ - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "a0145c9fa9a2459395809684221b6c0d", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "Canvas(toolbar=Toolbar(toolitems=[('Home', 'Reset original view', 'home', 'home'), ('Back', 'Back to previous …" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 11, - "metadata": {}, - "output_type": "execute_result" - } - ], + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "ws_mean = ws.copy()\n", "\n", @@ -1496,34 +1349,9 @@ }, { "cell_type": "code", - "execution_count": 15, - "metadata": {}, - "outputs": [ - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "b3a8bff871884ff4928b2957581ca4c1", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "Canvas(toolbar=Toolbar(toolitems=[('Home', 'Reset original view', 'home', 'home'), ('Back', 'Back to previous …" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 15, - "metadata": {}, - "output_type": "execute_result" - } - ], + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "ws_erode = ws.copy()\n", "\n", @@ -1545,34 +1373,9 @@ }, { "cell_type": "code", - "execution_count": 17, - "metadata": {}, - "outputs": [ - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "4bfd4cdc2aad4385b7fb91b683ef4f19", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "Canvas(toolbar=Toolbar(toolitems=[('Home', 'Reset original view', 'home', 'home'), ('Back', 'Back to previous …" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 17, - "metadata": {}, - "output_type": "execute_result" - } - ], + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "ws_dilate = ws.copy()\n", "\n", @@ -1594,34 +1397,9 @@ }, { "cell_type": "code", - "execution_count": 18, - "metadata": {}, - "outputs": [ - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "c4d3068ae5a945759c22bf219934ca91", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "Canvas(toolbar=Toolbar(toolitems=[('Home', 'Reset original view', 'home', 'home'), ('Back', 'Back to previous …" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 18, - "metadata": {}, - "output_type": "execute_result" - } - ], + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "ws_opening = ws.copy()\n", "\n", @@ -1643,34 +1421,9 @@ }, { "cell_type": "code", - "execution_count": 19, - "metadata": {}, - "outputs": [ - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "3cac681996bc460bbff8e36978229daf", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "Canvas(toolbar=Toolbar(toolitems=[('Home', 'Reset original view', 'home', 'home'), ('Back', 'Back to previous …" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 19, - "metadata": {}, - "output_type": "execute_result" - } - ], + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "ws_closing = ws.copy()\n", "\n", @@ -1697,7 +1450,7 @@ "\n", "The pumapy STL generation uses the Lewiner marching cubes implementation from scikit-image. The C++ version of PuMA also includes an implementation of the original and Lewiner marching cubes. \n", "\n", - "The Lewiner marching cubes method is used to generate STLs because the surface is guaranteed to be topologically correct (i.e watertight). The original marching cubes is suitable for visualization purposes, but had ambiguitites that resulted in small holes in the surface mesh. " + "The Lewiner marching cubes method is used to generate STLs because the surface is guaranteed to be topologically correct (i.e watertight). The original marching cubes is suitable for visualization purposes, but had ambiguities that resulted in small holes in the surface mesh." ] }, { @@ -1729,7 +1482,7 @@ "\n", "In this case, the appropriate grayscale cutoff for the imported tomography sample is 90, such that [90,255] is material and [0,89] is the void. These values will be different for each tomography image. \n", "\n", - "It is usually better to generate an STL based on a non-segmented material. This is because the segmentation process removes most of the information defining the surface from the tomography data. As an illustration, the code below will visualze the segmented and non-segmented versions of the imported tomography file. " + "It is usually better to generate an STL based on a non-segmented material. This is because the segmentation process removes most of the information defining the surface from the tomography data. As an illustration, the code below will visualize the segmented and non-segmented versions of the imported tomography file." ] }, { @@ -1914,7 +1667,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "An unsegmented domain is recommended because the surface are relies on the marching cubes triangulation of the isosurface, which is much more accurate for an unsegmented domain than a segmented domain. \n", + "An unsegmented domain is recommended because the surface area relies on the marching cubes triangulation of the isosurface, which is much more accurate for an unsegmented domain than a segmented domain.\n", "\n", "To calculate the surface area, we use the puma.compute_surface_area function: The function returns both the raw area and the specific surface area. The specific surface area is the more often used quantity, and defines the surface area divided by the volume of the domain, with units of 1/m. " ] @@ -1971,30 +1724,9 @@ }, { "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Importing /Users/fsemerar/opt/anaconda3/envs/puma/lib/python3.7/site-packages/pumapy/data/100_fiberform.tif ... Done\n", - "First gradient computation ... Done\n", - "Blurring of gradients ... Done\n", - "Computing eigenvalue analysis ... Done\n" - ] - }, - { - "data": { - "text/plain": [ - "True" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "ws = puma.import_3Dtiff(puma.path_to_example_file(\"100_fiberform.tif\"), 1.3e-6)\n", "\n", @@ -2012,24 +1744,9 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "f5234fb0e3b542bbb885b59eb7f2f2cd", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "ViewInteractiveWidget(height=1200, layout=Layout(height='auto', width='100%'), width=1920)" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ "p = pv.Plotter(shape=(1, 2), notebook=True)\n", "p.subplot(0, 0)\n", @@ -2113,7 +1830,7 @@ "#. 6. maxiter - maximum number of iterations, defaults to 10,000\n", "#. 7. solver_type - the iterative solver used. Can be 'bicgstab', 'cg', 'gmres', or 'direct'. Defaults to 'bicgstab'\n", "\n", - "k_eff_x, T_x, q_x = puma.compute_thermal_conductivity(ws_fiberform, cond_map, 'x', 's', tolerance=1e-2, solver_type='cg')\n", + "k_eff_x, T_x, q_x = puma.compute_thermal_conductivity(ws_fiberform, cond_map, 'x', 's', tolerance=1e-3, solver_type='cg')\n", "\n", "print(\"Effective thermal conductivity tensor:\")\n", "print(k_eff_x)" @@ -2179,7 +1896,7 @@ "#. 6. maxiter (optional) - maximum number of iterations, defaults to 10,000\n", "#. 7. solver_type (optional) - the iterative solver used. Can be 'bicgstab', 'cg', 'gmres', or 'direct'. Defaults to 'bicgstab'\n", "\n", - "k_eff_y, T_y, q_y = puma.compute_thermal_conductivity(ws_fiberform, cond_map, 'y', 's', tolerance=1e-2, solver_type='cg')\n", + "k_eff_y, T_y, q_y = puma.compute_thermal_conductivity(ws_fiberform, cond_map, 'y', 's', tolerance=1e-3, solver_type='cg')\n", "\n", "print(\"Effective thermal conductivity tensor:\")\n", "print(k_eff_y)" @@ -2270,7 +1987,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "If the local phases are isotropic, the anisotropic solver can still be used (although it would not be convenient because slower). As proof that the two solvers are actually giving the same answer, we could run the following case, in which we compute the orientation and then set the same conductivity to both the conductivity components (i.e. along and across a fiber):" + "If the local phases are isotropic, the anisotropic solver can still be used (although it would not be convenient because it is slower). As proof that the two solvers are actually giving the same answer, we could run the following case, in which we compute the orientation and then set the same conductivity to both the conductivity components (i.e. along and across a fiber):" ] }, { @@ -2287,9 +2004,9 @@ "cond_map.add_material((90, 255), 12)\n", "\n", "print(\"\\nIsotropic solver\")\n", - "k_eff_x, T_x, q_x = puma.compute_thermal_conductivity(ws_fiberform, cond_map, 'x', 's', tolerance=1e-2)\n", - "k_eff_y, T_y, q_y = puma.compute_thermal_conductivity(ws_fiberform, cond_map, 'y', 's', tolerance=1e-2)\n", - "k_eff_z, T_z, q_z = puma.compute_thermal_conductivity(ws_fiberform, cond_map, 'z', 's', tolerance=1e-2)\n", + "k_eff_x, T_x, q_x = puma.compute_thermal_conductivity(ws_fiberform, cond_map, 'x', 's', tolerance=1e-3)\n", + "k_eff_y, T_y, q_y = puma.compute_thermal_conductivity(ws_fiberform, cond_map, 'y', 's', tolerance=1e-3)\n", + "k_eff_z, T_z, q_z = puma.compute_thermal_conductivity(ws_fiberform, cond_map, 'z', 's', tolerance=1e-3)\n", "\n", "puma.compute_orientation_st(ws_fiberform, sigma=1.4, rho=0.7, cutoff=(90, 255))\n", "\n", @@ -2298,9 +2015,9 @@ "cond_map.add_material_to_orient((90, 255), 12., 12)\n", "\n", "print(\"\\nAnisotropic solver\")\n", - "k_eff_x_ani, T_x_ani, q_x_ani = puma.compute_thermal_conductivity(ws_fiberform, cond_map, 'x', 's', tolerance=1e-2)\n", - "k_eff_y_ani, T_y_ani, q_y_ani = puma.compute_thermal_conductivity(ws_fiberform, cond_map, 'y', 's', tolerance=1e-2)\n", - "k_eff_z_ani, T_z_ani, q_z_ani = puma.compute_thermal_conductivity(ws_fiberform, cond_map, 'z', 's', tolerance=1e-2)\n", + "k_eff_x_ani, T_x_ani, q_x_ani = puma.compute_thermal_conductivity(ws_fiberform, cond_map, 'x', 's', tolerance=1e-3)\n", + "k_eff_y_ani, T_y_ani, q_y_ani = puma.compute_thermal_conductivity(ws_fiberform, cond_map, 'y', 's', tolerance=1e-3)\n", + "k_eff_z_ani, T_z_ani, q_z_ani = puma.compute_thermal_conductivity(ws_fiberform, cond_map, 'z', 's', tolerance=1e-3)\n", "\n", "print(\"\\nEffective conductivity using isotropic solver\")\n", "print(np.round(k_eff_x, 5))\n", @@ -2370,9 +2087,9 @@ "#. 6. maxiter - maximum number of iterations, defaults to 10,000\n", "#. 7. solver_type - the iterative solver used. Can be 'bicgstab', 'cg', 'gmres', or 'direct'. Defaults to 'bicgstab'\n", "\n", - "n_eff_x, Deff_x, poro, C_x = puma.compute_continuum_tortuosity(ws_fiberform, (0,89), 'x', side_bc='s', tolerance=1e-2, solver_type='cg')\n", - "n_eff_y, Deff_y, poro, C_y = puma.compute_continuum_tortuosity(ws_fiberform, (0,89), 'y', side_bc='s', tolerance=1e-2, solver_type='cg')\n", - "n_eff_z, Deff_z, poro, C_z = puma.compute_continuum_tortuosity(ws_fiberform, (0,89), 'z', side_bc='s', tolerance=1e-2, solver_type='cg')\n", + "n_eff_x, Deff_x, poro, C_x = puma.compute_continuum_tortuosity(ws_fiberform, (0,89), 'x', side_bc='s', tolerance=1e-3, solver_type='cg')\n", + "n_eff_y, Deff_y, poro, C_y = puma.compute_continuum_tortuosity(ws_fiberform, (0,89), 'y', side_bc='s', tolerance=1e-3, solver_type='cg')\n", + "n_eff_z, Deff_z, poro, C_z = puma.compute_continuum_tortuosity(ws_fiberform, (0,89), 'z', side_bc='s', tolerance=1e-3, solver_type='cg')\n", "\n", "print(\"\\nEffective tortuosity factors:\")\n", "print(n_eff_x)\n", @@ -2417,9 +2134,9 @@ "#. 6. maxiter - maximum number of iterations, defaults to 10,000\n", "#. 7. solver_type - the iterative solver used. Can be 'bicgstab', 'cg', 'gmres', or 'direct'. Defaults to 'bicgstab'\n", "\n", - "n_eff_x, Deff_x, poro, C_x = puma.compute_continuum_tortuosity(ws_fiberform, (0,0), 'x', side_bc='s', tolerance=1e-2, solver_type='cg')\n", - "n_eff_y, Deff_y, poro, C_y = puma.compute_continuum_tortuosity(ws_fiberform, (0,0), 'y', side_bc='s', tolerance=1e-2, solver_type='cg')\n", - "n_eff_z, Deff_z, poro, C_z = puma.compute_continuum_tortuosity(ws_fiberform, (0,0), 'z', side_bc='s', tolerance=1e-2, solver_type='cg')\n", + "n_eff_x, Deff_x, poro, C_x = puma.compute_continuum_tortuosity(ws_fiberform, (0,0), 'x', side_bc='s', tolerance=1e-3, solver_type='cg')\n", + "n_eff_y, Deff_y, poro, C_y = puma.compute_continuum_tortuosity(ws_fiberform, (0,0), 'y', side_bc='s', tolerance=1e-3, solver_type='cg')\n", + "n_eff_z, Deff_z, poro, C_z = puma.compute_continuum_tortuosity(ws_fiberform, (0,0), 'z', side_bc='s', tolerance=1e-3, solver_type='cg')\n", "\n", "print(\"\\nEffective tortuosity factors:\")\n", "print(n_eff_x)\n", @@ -2627,7 +2344,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "The second case is for a fully built-in homogeneous beam with a z displacement in the middle. Because of the simmetry of this case, we only model only half of it." + "The second case is for a fully built-in homogeneous beam with a z displacement in the middle. Because of the symmetry of this case, we only model half of it." ] }, { @@ -3212,7 +2929,7 @@ "source": [ "Computing the surface area of each individual phase is a little bit more tricky. To demonstrate, refer to the simple 2D schematic below of a 2-phase material.\n", "\n", - "![image info](https://github.com/nasa/puma/raw/main/python/tutorials/pictures/multiphase.png)\n", + "![image info](https://github.com/nasa/puma/raw/main/tutorial/pictures/multiphase.png)\n", "\n", "The materials are each labeled, 1, and 2, and the edge lengths are labeled a, b, and c. The total surface area of both materials is defined as Atotal = a + b. Assuming that your materials are stored with grayscale values 1 and 2, this total surface area is calculated as before in the 3-material example: \n", "\n", @@ -3335,9 +3052,9 @@ "ws_cropped = ws_multiphase.copy() # creating a copy of the workspace to crop\n", "ws_cropped.matrix = ws_cropped.matrix[50:150,50:150,50:150] # cropping the sample to 100^3\n", "\n", - "n_eff_x, Deff_x, poro, C_x = puma.compute_continuum_tortuosity(ws_cropped, (0,0), 'x', side_bc='s', tolerance=1e-2, solver_type='cg')\n", - "n_eff_y, Deff_y, poro, C_y = puma.compute_continuum_tortuosity(ws_cropped, (0,0), 'y', side_bc='s', tolerance=1e-2, solver_type='cg')\n", - "n_eff_z, Deff_z, poro, C_z = puma.compute_continuum_tortuosity(ws_cropped, (0,0), 'z', side_bc='s', tolerance=1e-2, solver_type='cg')\n", + "n_eff_x, Deff_x, poro, C_x = puma.compute_continuum_tortuosity(ws_cropped, (0,0), 'x', side_bc='s', tolerance=1e-3, solver_type='cg')\n", + "n_eff_y, Deff_y, poro, C_y = puma.compute_continuum_tortuosity(ws_cropped, (0,0), 'y', side_bc='s', tolerance=1e-3, solver_type='cg')\n", + "n_eff_z, Deff_z, poro, C_z = puma.compute_continuum_tortuosity(ws_cropped, (0,0), 'z', side_bc='s', tolerance=1e-3, solver_type='cg')\n", "\n", "print(\"Effective tortuosity factors:\")\n", "print(n_eff_x)\n", @@ -3393,9 +3110,9 @@ "#. 6. maxiter - maximum number of iterations, defaults to 10,000\n", "#. 7. solver_type - the iterative solver used. Can be 'bicgstab', 'cg', 'gmres', or 'direct'. Defaults to 'bicgstab'\n", "\n", - "k_eff_x, T_x, q_x = puma.compute_thermal_conductivity(ws_cropped,cond_map, 'x', 's', tolerance=1e-2, solver_type='bicgstab')\n", - "k_eff_y, T_y, q_y = puma.compute_thermal_conductivity(ws_cropped,cond_map, 'y', 's', tolerance=1e-2, solver_type='bicgstab')\n", - "k_eff_z, T_z, q_z = puma.compute_thermal_conductivity(ws_cropped,cond_map, 'z', 's', tolerance=1e-2, solver_type='bicgstab')\n", + "k_eff_x, T_x, q_x = puma.compute_thermal_conductivity(ws_cropped,cond_map, 'x', 's', tolerance=1e-3, solver_type='bicgstab')\n", + "k_eff_y, T_y, q_y = puma.compute_thermal_conductivity(ws_cropped,cond_map, 'y', 's', tolerance=1e-3, solver_type='bicgstab')\n", + "k_eff_z, T_z, q_z = puma.compute_thermal_conductivity(ws_cropped,cond_map, 'z', 's', tolerance=1e-3, solver_type='bicgstab')\n", "\n", "print(\"Effective thermal conductivity tensor:\")\n", "print(k_eff_x)\n", @@ -4219,7 +3936,7 @@ "puma::Workspace grayWS(1e-6, false);\n", "\n", "RandomFibersInput input;\n", - "input.curvedFlower(100,100,100,5,0,100,0,90,90,15,false,0.95,100,120,0,1e-2,4,1,5,2,0);\n", + "input.curvedFlower(100,100,100,5,0,100,0,90,90,15,false,0.95,100,120,0,1e-3,4,1,5,2,0);\n", "\n", "puma::generateRandomFibers(&grayWS, input);\n", "\n", @@ -4227,7 +3944,7 @@ "puma::Workspace grayWS2(1e-6, false);\n", "\n", "RandomFibersInput input2;\n", - "input2.curvedFlower(100,100,100,5,0,100,0,90,90,15,true,0.95,100,120,0,1e-2,4,1,5,2,0);\n", + "input2.curvedFlower(100,100,100,5,0,100,0,90,90,15,true,0.95,100,120,0,1e-3,4,1,5,2,0);\n", "\n", "puma::generateRandomFibers(&grayWS2, input2);\n", "\n", @@ -4246,7 +3963,7 @@ "puma::Workspace grayWS(1e-6, false);\n", "\n", "RandomFibersInput input;\n", - "input.curvedFlower_Hollow(100,100,100,5,0,100,0,90,90,15,false,0.95,100,120,0,1e-2,4,1,5,2,0,1,2.5,0);\n", + "input.curvedFlower_Hollow(100,100,100,5,0,100,0,90,90,15,false,0.95,100,120,0,1e-3,4,1,5,2,0,1,2.5,0);\n", "\n", "puma::generateRandomFibers(&grayWS, input);\n", "\n", @@ -4254,7 +3971,7 @@ "puma::Workspace grayWS2(1e-6, false);\n", "\n", "RandomFibersInput input2;\n", - "input2.curvedFlower_Hollow(100,100,100,5,0,100,0,90,90,15,true,0.95,100,120,0,1e-2,4,1,5,2,0,1,2.5,0);\n", + "input2.curvedFlower_Hollow(100,100,100,5,0,100,0,90,90,15,true,0.95,100,120,0,1e-3,4,1,5,2,0,1,2.5,0);\n", "\n", "puma::generateRandomFibers(&grayWS2, input2);\n", "\n", @@ -4854,7 +4571,7 @@ "matCond[9] = {10,10,10,0,0,0};\n", "\n", "// Running simulation\n", - "puma::Vec3 k = puma::compute_FVanisotropicThermalConductivity(&segWS, &T, &q, matCond, \"mpfa\", \"symmetric\",\"bicgstab\",'x',1e-2,10000,true);\n", + "puma::Vec3 k = puma::compute_FVanisotropicThermalConductivity(&segWS, &T, &q, matCond, \"mpfa\", \"symmetric\",\"bicgstab\",'x',1e-3,10000,true);\n", "\n", "cout << endl << \"Conductivity: \" << endl;\n", "cout << \"kxx \" << k.x << \" kxy \" << k.y << \" kxz \" << k.z << endl;\n",