├── .coveragerc
├── .github
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── FUNDING.yml
├── ISSUE_TEMPLATE
│ ├── bug_report.md
│ └── feature_request.md
├── PULL_REQUEST_TEMPLATE.md
├── SECURITY.md
└── workflows
│ ├── codeql-analysis.yml
│ ├── documentation.yaml
│ ├── ossar-analysis.yml
│ ├── python_package.yaml
│ └── python_publish.yaml
├── .gitignore
├── .readthedocs.yaml
├── CHANGELOG.rst
├── LICENSE.rst
├── MANIFEST.in
├── README.rst
├── docs
├── publications
│ ├── cmame2020.bib
│ └── swx2020.bib
├── requirements.txt
└── source
│ ├── .gitignore
│ ├── _static
│ ├── favicon.ico
│ ├── github.svg
│ ├── logo
│ │ ├── browserconfig.xml
│ │ ├── logo.png
│ │ ├── logo.svg
│ │ ├── logo_114x114.png
│ │ ├── logo_120x120.png
│ │ ├── logo_128x128.png
│ │ ├── logo_144x144.png
│ │ ├── logo_180x180.png
│ │ ├── logo_192x192.png
│ │ ├── logo_196x196.png
│ │ ├── logo_228x228.png
│ │ ├── logo_32x32.png
│ │ ├── logo_57x57.png
│ │ ├── logo_72x72.png
│ │ ├── logo_76x76.png
│ │ ├── logo_96x96.png
│ │ ├── pad_logo.png
│ │ ├── pad_logo.svg
│ │ └── social.png
│ ├── pypi.svg
│ └── rtd.svg
│ ├── _templates
│ └── layout.html
│ ├── api
│ ├── cli.rst
│ ├── geometry
│ │ ├── box.rst
│ │ ├── circle.rst
│ │ ├── cube.rst
│ │ ├── ellipse.rst
│ │ ├── ellipsoid.rst
│ │ ├── factory.rst
│ │ ├── index.rst
│ │ ├── n_box.rst
│ │ ├── n_sphere.rst
│ │ ├── rectangle.rst
│ │ ├── sphere.rst
│ │ └── square.rst
│ ├── index.rst
│ ├── meshing
│ │ ├── index.rst
│ │ ├── polymesh.rst
│ │ ├── rastermesh.rst
│ │ └── trimesh.rst
│ ├── seeding
│ │ ├── index.rst
│ │ ├── seed.rst
│ │ └── seedlist.rst
│ └── verification.rst
│ ├── changelog.rst
│ ├── cli
│ ├── domain.rst
│ ├── index.rst
│ ├── introduction.rst
│ ├── material.rst
│ └── settings.rst
│ ├── conf.py
│ ├── contents.rst
│ ├── docutils.conf
│ ├── examples
│ ├── cli
│ │ ├── basalt.rst
│ │ ├── colormap.rst
│ │ ├── elliptical_grains.rst
│ │ ├── minimal.rst
│ │ └── two_phase_3d.rst
│ ├── index.rst
│ ├── intro
│ │ ├── intro_1.rst
│ │ ├── intro_2.rst
│ │ ├── intro_3.rst
│ │ ├── intro_4.rst
│ │ ├── intro_5.rst
│ │ └── intro_6.rst
│ └── package
│ │ ├── foam.rst
│ │ ├── from_image.rst
│ │ ├── grain_neighborhoods.rst
│ │ ├── logo.rst
│ │ ├── mesh_process.rst
│ │ ├── standard_voronoi.rst
│ │ └── uniform_seeding.rst
│ ├── file_formats.rst
│ ├── getting_started.rst
│ ├── index.rst
│ ├── package_guide.rst
│ ├── sphinx_gallery
│ ├── README.rst
│ ├── geometry
│ │ ├── README.rst
│ │ ├── plot_ellipse.py
│ │ └── plot_rectangle.py
│ └── plot_demos.py
│ ├── troubleshooting.rst
│ └── welcome.rst
├── requirements.txt
├── setup.cfg
├── setup.py
├── src
└── microstructpy
│ ├── __init__.py
│ ├── _misc.py
│ ├── cli.py
│ ├── examples
│ ├── .gitignore
│ ├── aluminum_micro.png
│ ├── aphanitic_cdf.csv
│ ├── basalt_circle.xml
│ ├── colormap.xml
│ ├── docs_banner.py
│ ├── elliptical_grains.xml
│ ├── foam.py
│ ├── from_image.py
│ ├── grain_neighborhoods.py
│ ├── intro_1_basic.xml
│ ├── intro_2_quality.xml
│ ├── intro_3_size_shape.xml
│ ├── intro_4_oriented.xml
│ ├── intro_5_plotting.xml
│ ├── intro_6_culmination.xml
│ ├── logo.py
│ ├── minimal.xml
│ ├── minimal_paired.xml
│ ├── olivine_cdf.csv
│ ├── standard_voronoi.py
│ ├── two_phase_3D.xml
│ └── uniform_seeding.py
│ ├── geometry
│ ├── __init__.py
│ ├── box.py
│ ├── circle.py
│ ├── ellipse.py
│ ├── ellipsoid.py
│ ├── n_box.py
│ ├── n_sphere.py
│ ├── rectangle.py
│ └── sphere.py
│ ├── meshing
│ ├── __init__.py
│ ├── polymesh.py
│ └── trimesh.py
│ ├── seeding
│ ├── __init__.py
│ ├── seed.py
│ └── seedlist.py
│ └── verification.py
├── tests
├── cli
│ ├── test_includes.py
│ └── test_includes_files
│ │ ├── different_dir
│ │ └── input.xml
│ │ ├── expected_input.xml
│ │ ├── fine_grained.xml
│ │ ├── input.xml
│ │ └── materials.xml
├── geometry
│ └── test_n_sphere.py
├── meshing
│ └── test_polymesh.py
└── test_misc.py
└── tox.ini
/.coveragerc:
--------------------------------------------------------------------------------
1 | [run]
2 | omit =
3 | src/microstructpy/cli.py
4 | src/microstructpy/__init__.py
5 | src/microstructpy/*/__init__.py
6 |
--------------------------------------------------------------------------------
/.github/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | In the interest of fostering an open and welcoming environment, we as
6 | contributors and maintainers pledge to making participation in our project and
7 | our community a harassment-free experience for everyone, regardless of age, body
8 | size, disability, ethnicity, sex characteristics, gender identity and expression,
9 | level of experience, education, socio-economic status, nationality, personal
10 | appearance, race, religion, or sexual identity and orientation.
11 |
12 | ## Our Standards
13 |
14 | Examples of behavior that contributes to creating a positive environment
15 | include:
16 |
17 | * Using welcoming and inclusive language
18 | * Being respectful of differing viewpoints and experiences
19 | * Gracefully accepting constructive criticism
20 | * Focusing on what is best for the community
21 | * Showing empathy towards other community members
22 |
23 | Examples of unacceptable behavior by participants include:
24 |
25 | * The use of sexualized language or imagery and unwelcome sexual attention or
26 | advances
27 | * Trolling, insulting/derogatory comments, and personal or political attacks
28 | * Public or private harassment
29 | * Publishing others' private information, such as a physical or electronic
30 | address, without explicit permission
31 | * Other conduct which could reasonably be considered inappropriate in a
32 | professional setting
33 |
34 | ## Our Responsibilities
35 |
36 | Project maintainers are responsible for clarifying the standards of acceptable
37 | behavior and are expected to take appropriate and fair corrective action in
38 | response to any instances of unacceptable behavior.
39 |
40 | Project maintainers have the right and responsibility to remove, edit, or
41 | reject comments, commits, code, wiki edits, issues, and other contributions
42 | that are not aligned to this Code of Conduct, or to ban temporarily or
43 | permanently any contributor for other behaviors that they deem inappropriate,
44 | threatening, offensive, or harmful.
45 |
46 | ## Scope
47 |
48 | This Code of Conduct applies both within project spaces and in public spaces
49 | when an individual is representing the project or its community. Examples of
50 | representing a project or community include using an official project e-mail
51 | address, posting via an official social media account, or acting as an appointed
52 | representative at an online or offline event. Representation of a project may be
53 | further defined and clarified by project maintainers.
54 |
55 | ## Enforcement
56 |
57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
58 | reported by contacting the project team at conduct@microstructpy.org. All
59 | complaints will be reviewed and investigated and will result in a response that
60 | is deemed necessary and appropriate to the circumstances. The project team is
61 | obligated to maintain confidentiality with regard to the reporter of an incident.
62 | Further details of specific enforcement policies may be posted separately.
63 |
64 | Project maintainers who do not follow or enforce the Code of Conduct in good
65 | faith may face temporary or permanent repercussions as determined by other
66 | members of the project's leadership.
67 |
68 | ## Attribution
69 |
70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
72 |
73 | [homepage]: https://www.contributor-covenant.org
74 |
75 | For answers to common questions about this code of conduct, see
76 | https://www.contributor-covenant.org/faq
77 |
--------------------------------------------------------------------------------
/.github/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | # Contributing to MicroStructPy
5 |
6 | Whether you are a novice or experienced software developer,
7 | all contributions and suggestions are welcome!
8 |
9 | ## Getting Started
10 |
11 | If you are looking to contribute to the *MicroStructPy* codebase,
12 | the best place to start is the
13 | [GitHub "issues" tab](https://github.com/kip-hart/MicroStructPy/issues).
14 | This is also a great place for filing bug reports and making suggestions for
15 | ways in which we can improve the code and documentation.
16 |
17 | ## Filing Issues
18 |
19 | If you notice a bug in the code or documentation, or have suggestions for
20 | how we can improve either, feel free to create an issue on the
21 | [GitHub "issues" tab](https://github.com/kip-hart/MicroStructPy/issues) using
22 | [GitHub's "issue" form](https://github.com/kip-hart/MicroStructPy/issues/new).
23 | The form contains some questions that will help us best address your issue.
24 |
25 | ## Contributing to the Codebase
26 |
27 | The code is hosted on [GitHub](https://www.github.com/kip-hart/MicroStructPy),
28 | so you will need to use [Git](http://git-scm.com/) to clone the project and
29 | make changes to the codebase.
30 | Once you have obtained a copy of the code, you should create a development
31 | environment that is separate from your existing Python environment so that
32 | you can make and test changes without compromising your own work environment.
33 | Consider using the Python
34 | [venv](https://docs.python.org/3/library/venv.html#module-venv) module to
35 | create a development environment.
36 |
37 | Before submitting your changes for review, make sure to check that your
38 | changes do not break any tests.
39 | Install [tox](https://tox.readthedocs.io) and run it from the top-level project
40 | directory.
41 | Tox will run tests on the code, the documentation, the build, and the code
42 | style.
43 | Please ensure that all tests are passing before pushing to the repository.
44 |
45 | Once your changes are ready to be submitted, make sure to push your changes to
46 | GitHub before creating a pull request.
47 | We will review your changes, and you may be asked to make additional changes
48 | before it is finally ready to merge.
49 | However, once it's ready, we will merge it, and you will have successfully
50 | contributed to the codebase!
51 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | tidelift: "pypi/microstructpy"
2 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Describe the bug**
11 | A clear and concise description of what the bug is.
12 |
13 | **To Reproduce**
14 | Steps to reproduce the behavior:
15 | 1. Go to '...'
16 | 2. Click on '....'
17 | 3. Scroll down to '....'
18 | 4. See error
19 |
20 | **Expected behavior**
21 | A clear and concise description of what you expected to happen.
22 |
23 | **Screenshots**
24 | If applicable, add screenshots to help explain your problem.
25 |
26 | **Desktop (please complete the following information):**
27 | - OS: [e.g. iOS]
28 | - Browser [e.g. chrome, safari]
29 | - Version [e.g. 22]
30 |
31 | **Smartphone (please complete the following information):**
32 | - Device: [e.g. iPhone6]
33 | - OS: [e.g. iOS8.1]
34 | - Browser [e.g. stock browser, safari]
35 | - Version [e.g. 22]
36 |
37 | **Additional context**
38 | Add any other context about the problem here.
39 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Is your feature request related to a problem? Please describe.**
11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
12 |
13 | **Describe the solution you'd like**
14 | A clear and concise description of what you want to happen.
15 |
16 | **Describe alternatives you've considered**
17 | A clear and concise description of any alternative solutions or features you've considered.
18 |
19 | **Additional context**
20 | Add any other context or screenshots about the feature request here.
21 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | ## PR Summary
2 | ### Purpose
3 | _Describe the problem or feature in addition to a link to the issues._
4 |
5 | ### Approach
6 | _How does this change address the problem?_
7 |
8 | ### Learning
9 | _Describe the research stage_
10 |
11 | _Links to blog posts, patterns, libraries or addons used to solve this problem_
12 |
13 | ## PR Checklist
14 | - [ ] All ``tox`` commands succeed
15 | - [ ] Docs have been added / updated (for bug fixes / features)
16 | - [ ] Has pytest style unit tests
17 |
18 | ## Closing Issues
19 |
20 | Fixes #
21 |
22 |
23 |
51 |
--------------------------------------------------------------------------------
/.github/SECURITY.md:
--------------------------------------------------------------------------------
1 | # Brand Promise
2 |
3 | The MicroStructPy team and community take security bugs in MicroStructPy seriously. We appreciate your efforts to responsibly disclose your findings, and will make every effort to acknowledge your contributions.
4 |
5 | # Scope
6 |
7 | If you believe you've found a security issue in software that is maintained in this repository, we encourage you to notify us.
8 |
9 | | Version | In scope | Source code |
10 | | ------- | ------------------ | ----------------------------------------------------- |
11 | | latest | :white_check_mark: | https://github.com/kip-hart/MicroStructPy |
12 | | v1.1.0 | :white_check_mark: | https://github.com/kip-hart/MicroStructPy/tree/v1.1.0 |
13 | | v1.0.1 | :white_check_mark: | https://github.com/kip-hart/MicroStructPy/tree/v1.0.1 |
14 | | v1.0.0 | :white_check_mark: | https://github.com/kip-hart/MicroStructPy/tree/v1.0.0 |
15 |
16 | # How to Submit a Report
17 |
18 | To submit a vulnerability report, please use Tidelift (https://tidelift.com/security). Your submission will be reviewed and validated by a member of our team.
19 |
20 | # Safe Harbor
21 |
22 | We support safe harbor for security researchers who:
23 |
24 | * Make a good faith effort to avoid privacy violations, destruction of data, and interruption or degradation of our services.
25 | * Only interact with accounts you own or with explicit permission of the account holder. If you do encounter Personally Identifiable Information (PII) contact us immediately, do not proceed with access, and immediately purge any local information.
26 | * Provide us with a reasonable amount of time to resolve vulnerabilities prior to any disclosure to the public or a third-party.
27 |
28 | We will consider activities conducted consistent with this policy to constitute "authorized" conduct and will not pursue civil action or initiate a complaint to law enforcement. We will help to the extent we can if legal action is initiated by a third party against you.
29 |
30 | Please submit a report to us before engaging in conduct that may be inconsistent with or unaddressed by this policy.
31 |
32 | # Preferences
33 |
34 | * Please provide detailed reports with reproducible steps and a clearly defined impact.
35 | * Include the version number of the vulnerable package in your report
36 | * Social engineering (e.g. phishing, vishing, smishing) is prohibited.
37 |
--------------------------------------------------------------------------------
/.github/workflows/codeql-analysis.yml:
--------------------------------------------------------------------------------
1 | name: "CodeQL"
2 |
3 | on:
4 | push:
5 | branches: [master, ]
6 | pull_request:
7 | # The branches below must be a subset of the branches above
8 | branches: [master]
9 | schedule:
10 | - cron: '0 20 * * 3'
11 |
12 | jobs:
13 | analyze:
14 | name: Analyze
15 | runs-on: ubuntu-latest
16 |
17 | steps:
18 | - name: Checkout repository
19 | uses: actions/checkout@v3
20 | with:
21 | # We must fetch at least the immediate parents so that if this is
22 | # a pull request then we can checkout the head.
23 | fetch-depth: 2
24 |
25 | # Initializes the CodeQL tools for scanning.
26 | - name: Initialize CodeQL
27 | uses: github/codeql-action/init@v1
28 | # Override language selection by uncommenting this and choosing your languages
29 | # with:
30 | # languages: go, javascript, csharp, python, cpp, java
31 |
32 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
33 | # If this step fails, then you should remove it and run the build manually (see below)
34 | - name: Autobuild
35 | uses: github/codeql-action/autobuild@v1
36 |
37 | # ℹ️ Command-line programs to run using the OS shell.
38 | # 📚 https://git.io/JvXDl
39 |
40 | # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
41 | # and modify them (or add more) to build your code if your project
42 | # uses a compiled language
43 |
44 | #- run: |
45 | # make bootstrap
46 | # make release
47 |
48 | - name: Perform CodeQL Analysis
49 | uses: github/codeql-action/analyze@v1
50 |
--------------------------------------------------------------------------------
/.github/workflows/documentation.yaml:
--------------------------------------------------------------------------------
1 |
2 | name: Documentation check
3 |
4 | on: [pull_request]
5 |
6 | jobs:
7 | docs-checks:
8 | name: ${{ matrix.doc-type }}
9 | strategy:
10 | matrix:
11 | doc-type: [html, latex, epub]
12 |
13 | runs-on: ubuntu-latest
14 | steps:
15 | - name: Checkout
16 | uses: actions/checkout@main
17 | - name: Set up Python
18 | uses: actions/setup-python@main
19 | with:
20 | python-version: '3.10'
21 | - name: Setup Linux Environment
22 | run: |
23 | sudo apt-get install libglu1
24 | - name: Install docs dependencies
25 | run: |
26 | python -m pip install -r docs/requirements.txt
27 | - name: Install package
28 | run: |
29 | if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
30 | pip install -e .
31 | - name: Build ${{ matrix.doc-type }} documentation
32 | run: sphinx-build -Wnb ${{ matrix.doc-type }} docs/source/ docs/build-${{ matrix.doc-type }}/
33 |
34 | - name: Prepare documentation artifact
35 | run: |
36 | # Define Path to Upload
37 | if [ "${{ matrix.doc-type }}" = html ]; then echo "art_path=docs/build-html" >> $GITHUB_ENV; fi
38 | if [ "${{ matrix.doc-type }}" = latex ]; then echo "art_path=docs/build-latex/MicroStructPy.pdf" >> $GITHUB_ENV; fi
39 | if [ "${{ matrix.doc-type }}" = epub ]; then echo "art_path=docs/build-epub/MicroStructPy.epub" >> $GITHUB_ENV; fi
40 |
41 | - name: Build PDF (latex only)
42 | if: matrix.doc-type == 'latex'
43 | run: |
44 | # Update apt
45 | sudo apt-get update
46 |
47 | # Install LaTeX packages
48 | # Recommended by Sphinx on their docs page:
49 | # https://www.sphinx-doc.org/en/master/usage/builders/index.html#sphinx.builders.latex.LaTeXBuilder
50 | sudo apt install texlive-latex-recommended
51 | sudo apt install texlive-fonts-recommended
52 | sudo apt install tex-gyre # (if latex_engine left to default)
53 | sudo apt install texlive-latex-extra
54 | sudo apt install latexmk
55 |
56 | # Make
57 | cd docs/build-latex
58 | make
59 | cd -
60 |
61 | - name: Upload artifact
62 | uses: actions/upload-artifact@main
63 | with:
64 | name: microstructpy_${{ matrix.doc-type }}_documentation
65 | path: ${{ env.art_path }}
66 |
67 |
--------------------------------------------------------------------------------
/.github/workflows/ossar-analysis.yml:
--------------------------------------------------------------------------------
1 | # This workflow integrates a collection of open source static analysis tools
2 | # with GitHub code scanning. For documentation, or to provide feedback, visit
3 | # https://github.com/github/ossar-action
4 | name: OSSAR
5 |
6 | on:
7 | push:
8 | pull_request:
9 |
10 | jobs:
11 | OSSAR-Scan:
12 | # OSSAR runs on windows-latest.
13 | # ubuntu-latest and macos-latest support coming soon
14 | runs-on: windows-latest
15 |
16 | steps:
17 | # Checkout your code repository to scan
18 | - name: Checkout repository
19 | uses: actions/checkout@main
20 | with:
21 | # We must fetch at least the immediate parents so that if this is
22 | # a pull request then we can checkout the head.
23 | fetch-depth: 2
24 |
25 | # If this run was triggered by a pull request event, then checkout
26 | # the head of the pull request instead of the merge commit.
27 | - run: git checkout HEAD^2
28 | if: ${{ github.event_name == 'pull_request' }}
29 |
30 | # Install dotnet, used by OSSAR
31 | - name: Install .NET
32 | uses: actions/setup-dotnet@main
33 | with:
34 | dotnet-version: '6.0.x'
35 |
36 | # Run open source static analysis tools
37 | - name: Run OSSAR
38 | uses: github/ossar-action@main
39 | id: ossar
40 |
41 | # Upload results to the Security tab
42 | - name: Upload OSSAR results
43 | uses: github/codeql-action/upload-sarif@main
44 | with:
45 | sarif_file: ${{ steps.ossar.outputs.sarifFile }}
46 |
--------------------------------------------------------------------------------
/.github/workflows/python_package.yaml:
--------------------------------------------------------------------------------
1 | name: CI
2 |
3 | on: [push]
4 |
5 | jobs:
6 | pytest:
7 | name: pytest for py${{ matrix.python-version }} on ${{ matrix.os }}
8 |
9 | runs-on: ${{ matrix.os }}
10 | strategy:
11 | matrix:
12 | python-version: [3.9, '3.10', '3.11', '3.12']
13 | os: ['ubuntu-latest', 'macos-latest', 'windows-latest']
14 |
15 | steps:
16 | - uses: actions/checkout@main
17 | - name: Set up Python ${{ matrix.python-version }}
18 | uses: actions/setup-python@main
19 | with:
20 | python-version: ${{ matrix.python-version }}
21 |
22 | - name: Setup Ubuntu environment
23 | if: startsWith(matrix.os, 'ubuntu')
24 | run: sudo apt-get install -y python3-gmsh libglu1
25 | - name: Setup MacOS environment
26 | if: startsWith(matrix.os, 'macos')
27 | run: brew install gmsh
28 |
29 | - name: Install test dependencies
30 | run: |
31 | python -m pip install --upgrade pip
32 | pip install setuptools wheel
33 | pip install flake8 pytest==6.2.5 pytest-cov coveralls
34 | - name: Install package requirements
35 | run: pip install -r requirements.txt
36 | - name: Install package
37 | run: pip install -e .
38 |
39 | - name: Lint with flake8
40 | run: |
41 | # stop the build if there are Python syntax errors or undefined names
42 | flake8 src tests setup.py --exclude=__init__.py --count --select=E9,F63,F7,F82 --show-source --statistics
43 | # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
44 | flake8 src tests setup.py --exclude=__init__.py --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
45 | - name: Test with pytest
46 | run: pytest --cov=src tests/
47 |
48 | - name: Coveralls
49 | env:
50 | COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_REPO_TOKEN }}
51 | COVERALLS_FLAG_NAME: py${{ matrix.python-version }} on ${{ matrix.os }}
52 | run: coveralls
53 |
54 | package-checks:
55 | name: package checks
56 |
57 | runs-on: ubuntu-latest
58 | steps:
59 | - uses: actions/checkout@main
60 | - name: Set up Python
61 | uses: actions/setup-python@main
62 | with:
63 | python-version: '3.x'
64 | - name: Cache pip
65 | uses: actions/cache@main
66 | with:
67 | # This path is specific to Ubuntu
68 | path: ~/.cache/pip
69 | # Look to see if there is a cache hit for the corresponding requirements file
70 | key: ${{ runner.os }}-pip-${{ hashFiles('requirements.txt') }}
71 | restore-keys: |
72 | ${{ runner.os }}-pip-
73 | ${{ runner.os }}-
74 | - name: Install check dependencies
75 | run: |
76 | python -m pip install --upgrade pip
77 | pip install setuptools wheel check-manifest isort twine
78 | - name: Check package import order
79 | run: |
80 | isort --verbose --check-only --diff src tests setup.py
81 | - name: Check package contents
82 | run: |
83 | python setup.py sdist check --strict --metadata
84 | check-manifest
85 | twine check dist/*
86 |
--------------------------------------------------------------------------------
/.github/workflows/python_publish.yaml:
--------------------------------------------------------------------------------
1 | # This workflow uses actions that are not certified by GitHub.
2 | # They are provided by a third-party and are governed by
3 | # separate terms of service, privacy policy, and support
4 | # documentation.
5 | #
6 | # For more information see: https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions#publishing-to-package-registries
7 |
8 | name: Upload Python Package
9 |
10 | on:
11 | release:
12 | types: [created]
13 |
14 | jobs:
15 | deploy:
16 | runs-on: ubuntu-latest
17 | steps:
18 | - uses: actions/checkout@v3
19 | - name: Set up Python
20 | uses: actions/setup-python@v4
21 | with:
22 | python-version: '3.x'
23 | - name: Install dependencies
24 | run: |
25 | python -m pip install --upgrade pip
26 | pip install build
27 | - name: Build package
28 | run: python -m build
29 | - name: Publish package
30 | uses: pypa/gh-action-pypi-publish@27b31702a0e7fc50959f5ad993c78deac1bdfc29
31 | with:
32 | user: __token__
33 | password: ${{ secrets.PYPI_MICROSTRUCTPY_TOKEN }}
34 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | # #
3 | # PROJECT-SPECIFIC .GITIGNORE #
4 | # #
5 | ###############################################################################
6 | test_reports/
7 | .vscode/
8 | docs/build*/
9 |
10 | ###############################################################################
11 | # #
12 | # SNIPPET FROM .GITIGNORE GIST #
13 | # #
14 | ###############################################################################
15 | # source: https://gist.github.com/octocat/9257657
16 |
17 | # OS generated files #
18 | ######################
19 | .DS_Store
20 | .DS_Store?
21 | ._*
22 | .Spotlight-V100
23 | .Trashes
24 | ehthumbs.db
25 | Thumbs.db
26 |
27 | ###############################################################################
28 | # #
29 | # GITHUB'S STANDARD PYTHON .GITIGNORE #
30 | # #
31 | ###############################################################################
32 |
33 | # Byte-compiled / optimized / DLL files
34 | __pycache__/
35 | *.py[cod]
36 | *$py.class
37 |
38 | # C extensions
39 | *.so
40 |
41 | # Distribution / packaging
42 | .Python
43 | build/
44 | develop-eggs/
45 | dist/
46 | downloads/
47 | eggs/
48 | .eggs/
49 | lib/
50 | lib64/
51 | parts/
52 | sdist/
53 | var/
54 | wheels/
55 | *.egg-info/
56 | .installed.cfg
57 | *.egg
58 | MANIFEST
59 |
60 | # PyInstaller
61 | # Usually these files are written by a python script from a template
62 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
63 | *.manifest
64 | *.spec
65 |
66 | # Installer logs
67 | pip-log.txt
68 | pip-delete-this-directory.txt
69 |
70 | # Unit test / coverage reports
71 | htmlcov/
72 | .tox/
73 | .nox/
74 | .coverage
75 | .coverage.*
76 | .cache
77 | nosetests.xml
78 | coverage.xml
79 | *.cover
80 | .hypothesis/
81 | .pytest_cache/
82 |
83 | # Translations
84 | *.mo
85 | *.pot
86 |
87 | # Django stuff:
88 | *.log
89 | local_settings.py
90 | db.sqlite3
91 |
92 | # Flask stuff:
93 | instance/
94 | .webassets-cache
95 |
96 | # Scrapy stuff:
97 | .scrapy
98 |
99 | # Sphinx documentation
100 | docs/_build/
101 |
102 | # PyBuilder
103 | target/
104 |
105 | # Jupyter Notebook
106 | .ipynb_checkpoints
107 |
108 | # IPython
109 | profile_default/
110 | ipython_config.py
111 |
112 | # pyenv
113 | .python-version
114 |
115 | # celery beat schedule file
116 | celerybeat-schedule
117 |
118 | # SageMath parsed files
119 | *.sage.py
120 |
121 | # Environments
122 | .env
123 | .venv
124 | env/
125 | venv/
126 | ENV/
127 | env.bak/
128 | venv.bak/
129 |
130 | # Spyder project settings
131 | .spyderproject
132 | .spyproject
133 |
134 | # Rope project settings
135 | .ropeproject
136 |
137 | # mkdocs documentation
138 | /site
139 |
140 | # mypy
141 | .mypy_cache/
142 | .dmypy.json
143 | dmypy.json
144 |
145 | # Pyre type checker
146 | .pyre/
147 |
--------------------------------------------------------------------------------
/.readthedocs.yaml:
--------------------------------------------------------------------------------
1 | # Read the Docs configuration file for Sphinx projects
2 | # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
3 |
4 | # Required
5 | version: 2
6 |
7 | formats: all
8 |
9 | # Set the OS, Python version and other tools you might need
10 | build:
11 | os: ubuntu-22.04
12 | tools:
13 | python: "3.8"
14 | apt_packages:
15 | - freeglut3-dev
16 |
17 | # Build documentation in the "docs/" directory with Sphinx
18 | sphinx:
19 | configuration: docs/source/conf.py
20 |
21 | # Optional but recommended, declare the Python requirements required
22 | # to build your documentation
23 | # See https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html
24 | python:
25 | install:
26 | - requirements: docs/requirements.txt
27 | - method: pip
28 | path: .
29 |
--------------------------------------------------------------------------------
/LICENSE.rst:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019-2024 Georgia Tech Research Corporation
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/MANIFEST.in:
--------------------------------------------------------------------------------
1 | graft docs
2 | graft src
3 | graft tests
4 |
5 | include .azure-pipelines.yml
6 | include .bumpversion.cfg
7 | include .coveragerc
8 | include .editorconfig
9 | include .pyup.yml
10 | include .readthedocs.yaml
11 |
12 | include CHANGELOG.rst
13 | include LICENSE.rst
14 | include README.rst
15 |
16 | include tox.ini
17 | include requirements.txt
18 |
19 | prune .github
20 | prune docs/source/auto_examples
21 | prune docs/build*
22 | prune src/*/examples/*
23 | prune src/*.egg-info
24 | prune tests/tmp_out
25 |
26 | exclude coverage.xml
27 | exclude src/*/examples/*.png
28 | include src/microstructpy/examples/aluminum_micro.png
29 | exclude src/*/examples/*.txt
30 | exclude src/*/examples/.gitignore
31 |
32 | global-exclude *.py[cod] __pycache__ *.so *.dylib .DS_Store *.log Icon*
33 |
--------------------------------------------------------------------------------
/docs/publications/cmame2020.bib:
--------------------------------------------------------------------------------
1 | @article{Hart2020,
2 | author = {Hart, Kenneth A and Rimoli, Julian J},
3 | title = {Generation of statistically representative microstructures with direct grain geometry control},
4 | journal = {Computer Methods in Applied Mechanics and Engineering},
5 | volume = {370},
6 | artnum = {113242},
7 | year = {2020},
8 | issn = {0045-7825},
9 | doi = "https://doi.org/10.1016/j.cma.2020.113242",
10 | url = "http://www.sciencedirect.com/science/article/pii/S0045782520304278",
11 | keywords = "Microstructure, Polycrystal, Finite element modeling, Laguerre tessellation, Multi-sphere",
12 | abstract = "Microstructural characteristics play a significant role in the determination of effective properties of materials. Consequently, most numerical tools aimed at predicting such properties require, as a starting point, the availability of geometric representations of such microstructures. In this paper, we introduce a method for generating statistically representative synthetic microstructures for materials involving multiple phases. Our method is based on traditional seed placement and tessellation approaches, with three critical improvements: (i) allowing for controlled seed overlap to better represent microstructural statistics, (ii) multi-sphere representation of 3D ellipsoids to account for arbitrarily elongated grains, and (iii) novel application of the axis aligned bounding box tree structure for accelerated seed placement. Our method recreates a diverse set of microstructural features, including the presence of spherical and non-spherical grain geometries, amorphous phases, and voids. After the method is presented, we proceed with a rigorous numerical analysis demonstrating its ability to reproduce key statistical features of target microstructures. The algorithms presented are freely available and open source through the package MicroStructPy."
13 | }
14 |
--------------------------------------------------------------------------------
/docs/publications/swx2020.bib:
--------------------------------------------------------------------------------
1 | @article{Hart2020swX,
2 | title = "MicroStructPy: A statistical microstructure mesh generator in Python",
3 | journal = "SoftwareX",
4 | volume = "12",
5 | pages = "100595",
6 | year = "2020",
7 | issn = "2352-7110",
8 | doi = "https://doi.org/10.1016/j.softx.2020.100595",
9 | url = "http://www.sciencedirect.com/science/article/pii/S2352711020303083",
10 | author = "Kenneth A. Hart and Julian J. Rimoli",
11 | keywords = "Microstructure, Mesh generation, Polycrystal, Laguerre tessellation",
12 | abstract = "MicroStructPy is a statistical microstructure mesh generator written in Python. This software package includes classes and methods to generate a mesh by (i) creating a list of grain seed geometries, (ii) packing them into a domain, (iii) performing a Laguerre tessellation of the seed geometries, and (iv) performing quality unstructured meshing. Results can be visualized and compared with the specified microstructural properties. MicroStructPy accurately reproduces 2D and 3D polycrystalline microstructures with arbitrary number of phases, volume fractions and distributions, each including the possibility of elongated grains. It can also generate meshes for amorphous phases and porous materials. Meshes are suitable for direct numerical simulation, a prevalent technique in computational mechanics of materials and geomechanics. The package contains extensive documentation, including guides and demonstrations to facilitate adoption for new users."
13 | }
14 |
--------------------------------------------------------------------------------
/docs/requirements.txt:
--------------------------------------------------------------------------------
1 | gmsh==4.11.1
2 | matplotlib>=3.7.3
3 | numpy>=1.24.4
4 | pybind11==2.4.3
5 | requests>=2.32.0 # not directly required, pinned by Snyk to avoid a vulnerability
6 | setuptools>=70.0.0
7 | sphinx==5.3.0
8 | sphinx-gallery==0.8.1
9 | urllib3>=2.2.2 # not directly required, pinned by Snyk to avoid a vulnerability
10 | zipp>=3.19.1 # not directly required, pinned by Snyk to avoid a vulnerability
11 |
--------------------------------------------------------------------------------
/docs/source/.gitignore:
--------------------------------------------------------------------------------
1 | auto_examples/
--------------------------------------------------------------------------------
/docs/source/_static/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kip-hart/MicroStructPy/59f6bb14de2364f943943ec327b5014c1f5bb81d/docs/source/_static/favicon.ico
--------------------------------------------------------------------------------
/docs/source/_static/github.svg:
--------------------------------------------------------------------------------
1 |
2 |
64 |
--------------------------------------------------------------------------------
/docs/source/_static/logo/browserconfig.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | #FFFFFF
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/docs/source/_static/logo/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kip-hart/MicroStructPy/59f6bb14de2364f943943ec327b5014c1f5bb81d/docs/source/_static/logo/logo.png
--------------------------------------------------------------------------------
/docs/source/_static/logo/logo_114x114.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kip-hart/MicroStructPy/59f6bb14de2364f943943ec327b5014c1f5bb81d/docs/source/_static/logo/logo_114x114.png
--------------------------------------------------------------------------------
/docs/source/_static/logo/logo_120x120.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kip-hart/MicroStructPy/59f6bb14de2364f943943ec327b5014c1f5bb81d/docs/source/_static/logo/logo_120x120.png
--------------------------------------------------------------------------------
/docs/source/_static/logo/logo_128x128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kip-hart/MicroStructPy/59f6bb14de2364f943943ec327b5014c1f5bb81d/docs/source/_static/logo/logo_128x128.png
--------------------------------------------------------------------------------
/docs/source/_static/logo/logo_144x144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kip-hart/MicroStructPy/59f6bb14de2364f943943ec327b5014c1f5bb81d/docs/source/_static/logo/logo_144x144.png
--------------------------------------------------------------------------------
/docs/source/_static/logo/logo_180x180.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kip-hart/MicroStructPy/59f6bb14de2364f943943ec327b5014c1f5bb81d/docs/source/_static/logo/logo_180x180.png
--------------------------------------------------------------------------------
/docs/source/_static/logo/logo_192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kip-hart/MicroStructPy/59f6bb14de2364f943943ec327b5014c1f5bb81d/docs/source/_static/logo/logo_192x192.png
--------------------------------------------------------------------------------
/docs/source/_static/logo/logo_196x196.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kip-hart/MicroStructPy/59f6bb14de2364f943943ec327b5014c1f5bb81d/docs/source/_static/logo/logo_196x196.png
--------------------------------------------------------------------------------
/docs/source/_static/logo/logo_228x228.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kip-hart/MicroStructPy/59f6bb14de2364f943943ec327b5014c1f5bb81d/docs/source/_static/logo/logo_228x228.png
--------------------------------------------------------------------------------
/docs/source/_static/logo/logo_32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kip-hart/MicroStructPy/59f6bb14de2364f943943ec327b5014c1f5bb81d/docs/source/_static/logo/logo_32x32.png
--------------------------------------------------------------------------------
/docs/source/_static/logo/logo_57x57.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kip-hart/MicroStructPy/59f6bb14de2364f943943ec327b5014c1f5bb81d/docs/source/_static/logo/logo_57x57.png
--------------------------------------------------------------------------------
/docs/source/_static/logo/logo_72x72.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kip-hart/MicroStructPy/59f6bb14de2364f943943ec327b5014c1f5bb81d/docs/source/_static/logo/logo_72x72.png
--------------------------------------------------------------------------------
/docs/source/_static/logo/logo_76x76.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kip-hart/MicroStructPy/59f6bb14de2364f943943ec327b5014c1f5bb81d/docs/source/_static/logo/logo_76x76.png
--------------------------------------------------------------------------------
/docs/source/_static/logo/logo_96x96.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kip-hart/MicroStructPy/59f6bb14de2364f943943ec327b5014c1f5bb81d/docs/source/_static/logo/logo_96x96.png
--------------------------------------------------------------------------------
/docs/source/_static/logo/pad_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kip-hart/MicroStructPy/59f6bb14de2364f943943ec327b5014c1f5bb81d/docs/source/_static/logo/pad_logo.png
--------------------------------------------------------------------------------
/docs/source/_static/logo/social.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kip-hart/MicroStructPy/59f6bb14de2364f943943ec327b5014c1f5bb81d/docs/source/_static/logo/social.png
--------------------------------------------------------------------------------
/docs/source/_static/pypi.svg:
--------------------------------------------------------------------------------
1 |
2 |
48 |
--------------------------------------------------------------------------------
/docs/source/_static/rtd.svg:
--------------------------------------------------------------------------------
1 |
2 |
36 |
--------------------------------------------------------------------------------
/docs/source/_templates/layout.html:
--------------------------------------------------------------------------------
1 | {% extends "!layout.html" %}
2 | {%- block extrahead %}
3 | {%- if render_sidebar %}
4 |
5 | {{ super() }}
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 | {% endif %}
66 | {%- endblock %}
67 |
--------------------------------------------------------------------------------
/docs/source/api/cli.rst:
--------------------------------------------------------------------------------
1 | microstructpy.cli
2 | =================
3 |
4 | .. automodule:: microstructpy.cli
5 | :members:
6 | :undoc-members:
--------------------------------------------------------------------------------
/docs/source/api/geometry/box.rst:
--------------------------------------------------------------------------------
1 | .. _api_geometry_box:
2 |
3 | .. currentmodule:: microstructpy.geometry
4 |
5 | microstructpy.geometry.Box
6 | ==========================
7 |
8 | .. autoclass:: Box
9 | :members:
10 | :undoc-members:
11 | :inherited-members:
12 | :show-inheritance:
--------------------------------------------------------------------------------
/docs/source/api/geometry/circle.rst:
--------------------------------------------------------------------------------
1 | .. _api_geometry_circle:
2 |
3 | .. currentmodule:: microstructpy.geometry
4 |
5 | microstructpy.geometry.Circle
6 | =============================
7 |
8 | .. autoclass:: Circle
9 | :members:
10 | :undoc-members:
11 | :inherited-members:
12 | :show-inheritance:
--------------------------------------------------------------------------------
/docs/source/api/geometry/cube.rst:
--------------------------------------------------------------------------------
1 | .. _api_geometry_cube:
2 |
3 | .. currentmodule:: microstructpy.geometry
4 |
5 | microstructpy.geometry.Cube
6 | ===========================
7 |
8 | .. autoclass:: Cube
9 | :members:
10 | :undoc-members:
11 | :inherited-members:
12 |
--------------------------------------------------------------------------------
/docs/source/api/geometry/ellipse.rst:
--------------------------------------------------------------------------------
1 | .. _api_geometry_ellipse:
2 |
3 | .. currentmodule:: microstructpy.geometry
4 |
5 | microstructpy.geometry.Ellipse
6 | ==============================
7 |
8 | .. autoclass:: Ellipse
9 | :members:
10 | :undoc-members:
11 | :inherited-members:
12 | :show-inheritance:
--------------------------------------------------------------------------------
/docs/source/api/geometry/ellipsoid.rst:
--------------------------------------------------------------------------------
1 | .. _api_geometry_ellipsoid:
2 |
3 | .. currentmodule:: microstructpy.geometry
4 |
5 | microstructpy.geometry.Ellipsoid
6 | ================================
7 |
8 | .. autoclass:: Ellipsoid
9 | :members:
10 | :undoc-members:
11 | :inherited-members:
12 | :show-inheritance:
--------------------------------------------------------------------------------
/docs/source/api/geometry/factory.rst:
--------------------------------------------------------------------------------
1 | .. _api_geometry_factory:
2 |
3 | .. currentmodule:: microstructpy.geometry
4 |
5 | microstructpy.geometry.factory
6 | ==============================
7 |
8 | .. automethod:: microstructpy.geometry.factory
--------------------------------------------------------------------------------
/docs/source/api/geometry/index.rst:
--------------------------------------------------------------------------------
1 | microstructpy.geometry
2 | ======================
3 |
4 | .. automodule:: microstructpy.geometry
5 |
6 | The geometry module contains classes for several 2D and 3D geometries.
7 | The module also contains some N-D geometries, which are inherited by the
8 | 2D and 3D geometries.
9 |
10 | **2D Geometries**
11 |
12 | * :ref:`api_geometry_circle` † ‡
13 | * :ref:`api_geometry_ellipse` † ‡
14 | * :ref:`api_geometry_rectangle` † ‡
15 | * :ref:`api_geometry_square` † ‡
16 |
17 | **3D Geometries**
18 |
19 | * :ref:`api_geometry_box` ‡
20 | * :ref:`api_geometry_cube` ‡
21 | * :ref:`api_geometry_ellipsoid` †
22 | * :ref:`api_geometry_sphere` †
23 |
24 | **ND Geometries**
25 |
26 | * :ref:`api_geometry_n_box`
27 | * :ref:`api_geometry_n_sphere`
28 |
29 | †: These classes may be used to define seed particles.
30 |
31 | ‡: These classes may be used to define the microstructure domain.
32 |
33 | To assist with creating geometries, a factory method is included in the module:
34 |
35 | * :ref:`api_geometry_factory`
36 |
37 | .. only:: html
38 |
39 | **Module Contents**
40 |
41 | .. toctree::
42 |
43 | box
44 | circle
45 | cube
46 | ellipse
47 | ellipsoid
48 | n_box
49 | n_sphere
50 | rectangle
51 | sphere
52 | square
53 | factory
54 |
--------------------------------------------------------------------------------
/docs/source/api/geometry/n_box.rst:
--------------------------------------------------------------------------------
1 | .. _api_geometry_n_box:
2 |
3 | .. currentmodule:: microstructpy.geometry.n_box
4 |
5 | microstructpy.geometry.n_box.NBox
6 | =================================
7 |
8 | .. autoclass:: NBox
9 | :members:
10 | :undoc-members:
11 | :inherited-members:
12 | :show-inheritance:
--------------------------------------------------------------------------------
/docs/source/api/geometry/n_sphere.rst:
--------------------------------------------------------------------------------
1 | .. _api_geometry_n_sphere:
2 |
3 | .. currentmodule:: microstructpy.geometry.n_sphere
4 |
5 | microstructpy.geometry.n_sphere.NSphere
6 | =======================================
7 |
8 | .. autoclass:: NSphere
9 | :members:
10 | :undoc-members:
11 | :inherited-members:
12 | :show-inheritance:
--------------------------------------------------------------------------------
/docs/source/api/geometry/rectangle.rst:
--------------------------------------------------------------------------------
1 | .. _api_geometry_rectangle:
2 |
3 | .. currentmodule:: microstructpy.geometry
4 |
5 | microstructpy.geometry.Rectangle
6 | ================================
7 |
8 | .. autoclass:: Rectangle
9 | :members:
10 | :undoc-members:
11 | :inherited-members:
12 | :show-inheritance:
--------------------------------------------------------------------------------
/docs/source/api/geometry/sphere.rst:
--------------------------------------------------------------------------------
1 | .. _api_geometry_sphere:
2 |
3 | .. currentmodule:: microstructpy.geometry
4 |
5 | microstructpy.geometry.Sphere
6 | =============================
7 |
8 | .. autoclass:: Sphere
9 | :members:
10 | :undoc-members:
11 | :inherited-members:
12 | :show-inheritance:
--------------------------------------------------------------------------------
/docs/source/api/geometry/square.rst:
--------------------------------------------------------------------------------
1 | .. _api_geometry_square:
2 |
3 | .. currentmodule:: microstructpy.geometry
4 |
5 | microstructpy.geometry.Square
6 | =============================
7 |
8 | .. autoclass:: Square
9 | :members:
10 | :undoc-members:
11 | :inherited-members:
12 |
--------------------------------------------------------------------------------
/docs/source/api/index.rst:
--------------------------------------------------------------------------------
1 | .. _api-index:
2 |
3 | API
4 | ===
5 |
6 | .. toctree::
7 | :maxdepth: 2
8 |
9 | cli
10 | geometry/index
11 | meshing/index
12 | seeding/index
13 | verification
14 |
--------------------------------------------------------------------------------
/docs/source/api/meshing/index.rst:
--------------------------------------------------------------------------------
1 | microstructpy.meshing
2 | =====================
3 |
4 | .. automodule:: microstructpy.meshing
5 |
6 | The meshing module contains three mesh classes,
7 | the :class:`.PolyMesh`, the :class:`.RasterMesh` and the :class:`.TriMesh`.
8 | The polygonal mesh contains a 2D or 3D tessellation of the microstructure
9 | domain, while the raster aand triangular meshes are more suitable for
10 | direct numerical simulation (finite element analysis).
11 |
12 | .. only:: html
13 |
14 | **Module Contents**
15 |
16 | .. toctree::
17 |
18 | polymesh
19 | rastermesh
20 | trimesh
--------------------------------------------------------------------------------
/docs/source/api/meshing/polymesh.rst:
--------------------------------------------------------------------------------
1 | .. _api_meshing_polymesh:
2 |
3 | .. currentmodule:: microstructpy.meshing
4 |
5 | microstructpy.meshing.PolyMesh
6 | ==============================
7 |
8 | .. autoclass:: PolyMesh
9 | :members:
10 | :undoc-members:
11 | :inherited-members:
12 | :show-inheritance:
13 |
--------------------------------------------------------------------------------
/docs/source/api/meshing/rastermesh.rst:
--------------------------------------------------------------------------------
1 | .. _api_meshing_rastermesh:
2 |
3 | .. currentmodule:: microstructpy.meshing
4 |
5 | microstructpy.meshing.RasterMesh
6 | ================================
7 |
8 | .. autoclass:: RasterMesh
9 | :members:
10 | :undoc-members:
11 | :inherited-members:
12 |
--------------------------------------------------------------------------------
/docs/source/api/meshing/trimesh.rst:
--------------------------------------------------------------------------------
1 | .. _api_meshing_trimesh:
2 |
3 | .. currentmodule:: microstructpy.meshing
4 |
5 | microstructpy.meshing.TriMesh
6 | =============================
7 |
8 | .. autoclass:: TriMesh
9 | :members:
10 | :undoc-members:
11 | :inherited-members:
12 | :show-inheritance:
13 |
--------------------------------------------------------------------------------
/docs/source/api/seeding/index.rst:
--------------------------------------------------------------------------------
1 | microstructpy.seeding
2 | =====================
3 |
4 | .. automodule:: microstructpy.seeding
5 |
6 | The seeding module contains two classes: :class:`.Seed` and :class:`.SeedList`.
7 | The single :class:`.Seed` contains the geometry, phase number, and position
8 | of a seed, while a :class:`.SeedList` functions much like a list of
9 | :class:`.Seed` instances, but with more methods.
10 |
11 |
12 | .. only:: html
13 |
14 | **Module Contents**
15 |
16 | .. toctree::
17 |
18 | seed
19 | seedlist
--------------------------------------------------------------------------------
/docs/source/api/seeding/seed.rst:
--------------------------------------------------------------------------------
1 | .. _api_seeding_seed:
2 |
3 | .. currentmodule:: microstructpy.seeding
4 |
5 | microstructpy.seeding.Seed
6 | ==========================
7 |
8 | .. autoclass:: Seed
9 | :members:
10 | :undoc-members:
11 | :inherited-members:
12 | :show-inheritance:
--------------------------------------------------------------------------------
/docs/source/api/seeding/seedlist.rst:
--------------------------------------------------------------------------------
1 | .. _api_seeding_seedlist:
2 |
3 | .. currentmodule:: microstructpy.seeding
4 |
5 | microstructpy.seeding.SeedList
6 | ==============================
7 |
8 | .. autoclass:: SeedList
9 | :members:
10 | :undoc-members:
11 | :inherited-members:
12 | :show-inheritance:
--------------------------------------------------------------------------------
/docs/source/api/verification.rst:
--------------------------------------------------------------------------------
1 | microstructpy.verification
2 | ==========================
3 |
4 | .. automodule:: microstructpy.verification
5 | :members:
6 | :undoc-members:
--------------------------------------------------------------------------------
/docs/source/changelog.rst:
--------------------------------------------------------------------------------
1 | .. include:: ../../CHANGELOG.rst
2 |
--------------------------------------------------------------------------------
/docs/source/cli/index.rst:
--------------------------------------------------------------------------------
1 | .. _cli:
2 |
3 | ==================
4 | Command Line Guide
5 | ==================
6 |
7 | .. only:: html
8 |
9 | .. include:: introduction.rst
10 | :start-after: .. cli-start
11 | :end-before: .. cli-end
12 |
13 | .. rubric:: Guide Contents
14 |
15 | .. toctree::
16 | :maxdepth: 3
17 |
18 | introduction
19 |
20 |
21 |
--------------------------------------------------------------------------------
/docs/source/cli/introduction.rst:
--------------------------------------------------------------------------------
1 | ============
2 | Introduction
3 | ============
4 |
5 | Using the Command Line Interface
6 | --------------------------------
7 |
8 | .. cli-start
9 |
10 | The command line interface (CLI) for this package is ``microstructpy``.
11 | This command accepts the names of user-generated files and demonstration files.
12 | Multiple filenames can be specified.
13 |
14 | To run demos, you can specify a particular demo file or to run all of them::
15 |
16 | microstructpy --demo=minimal.xml
17 | microstructpy --demo=all
18 |
19 | Demo files are copied to the current working directory and then executed.
20 | Running all of the demonstration files may take several minutes.
21 |
22 | User-generated input files can be run in a number of ways::
23 |
24 | microstructpy /path/to/my/input_file.xml
25 | microstructpy input_1.xml input_2.xml input_3.xml
26 | microstructpy input_*.xml
27 |
28 | Both relative and absolute filepaths are acceptable.
29 |
30 | The following pages describe in detail the various uses and options for the
31 | material, domain, and settings fields of a MicroStructPy input file.
32 |
33 | .. cli-end
34 |
35 | Command Line Procedure
36 | ----------------------
37 |
38 | The following tasks are performed by the CLI:
39 |
40 | 1. Make the output directory, if necessary
41 | 2. **Create a list of unpositioned seeds**
42 | 3. **Position the seeds in the domain**
43 | 4. Save the seeds in a text file
44 | 5. Save a plot of the seeds to an image file
45 | 6. **Create a polygon mesh from the seeds**
46 | 7. Save the mesh to the output directory
47 | 8. Save a plot of the mesh to the output directory
48 | 9. **Create an unstructured (triangular or tetrahedral) mesh**
49 | 10. Save the unstructured mesh
50 | 11. Save a plot of the unstructured mesh
51 | 12. (optional) Verify the output mesh against the input file.
52 |
53 | Intermediate results are saved in steps 4, 7, and 10 to give the option of
54 | restarting the procedure.
55 | The format of the output files can be specified in the input file
56 | (e.g. PNG and/or PDF plots).
57 |
58 | Example Input File
59 | ------------------
60 |
61 | Input files for MicroStructPy must be in XML format.
62 | The three fields of the input file that MicroStructPy looks for are:
63 | ````, ````, and ```` (optional).
64 | For example:
65 |
66 | .. literalinclude:: ../../../src/microstructpy/examples/minimal_paired.xml
67 | :language: xml
68 |
69 |
70 | This will create a microstructure with approximately circular grains that
71 | fill a domain that is 11x larger and color them according to the colormap
72 | Paired.
73 |
74 | .. note::
75 |
76 | XML fields that are not recognized by MicroStructPy will be ignored by the
77 | software. For example, material properties or notes can be included in the
78 | input file without affecting program execution.
79 |
80 | .. note::
81 |
82 | The order of fields in the XML input file is not strictly important,
83 | since the file is converted into a Python dictionary.
84 | When fields are repeated, such as including multiple materials, the order
85 | is preserved.
86 |
87 |
88 | Including References to Other Input Files
89 | -----------------------------------------
90 |
91 | The input file can optionally *include* references to other input files.
92 | For example if the file ``materials.xml`` contains:
93 |
94 | .. code-block:: xml
95 |
96 |
97 |
98 | circle
99 | 0.1
100 |
101 |
102 |
103 | and another file, ``domain_1.xml``, contains:
104 |
105 | .. code-block:: xml
106 |
107 |
108 | materials.xml
109 |
110 | square
111 | 10
112 |
113 |
114 |
115 | then MicroStructPy will read the contents of ``materials.xml`` when
116 | ``microstructpy domain_1.xml`` is called. This functionality can allows multiple
117 | input files to reference the same material properties. For example, a mesh
118 | convergence study could keep the materials and domain definitions in a single
119 | file, then the input files for each mesh size would contain the run settings
120 | and a reference to the definitions file.
121 |
122 | This way, if a parameter such as the grain size distribution needs to be
123 | updated, it only needs to be changed in a single file.
124 |
125 | Advanced Usage
126 | ++++++++++++++
127 |
128 | The ```` tag can be included at any heirarchical level of the
129 | input file. It can also be nested, with ```` tags in the file being
130 | included. For example, if the file ``fine_grained.xml`` contains:
131 |
132 | .. code-block:: xml
133 |
134 |
135 | circle
136 | 0.1
137 |
138 |
139 | and the file ``materials.xml`` contains:
140 |
141 |
142 |
143 | .. code-block:: xml
144 |
145 |
146 |
147 | Fine 1
148 | fine_grained.xml
149 |
150 |
151 |
152 | Fine 2
153 | fine_grained.xml
154 |
155 |
156 |
157 | Coarse
158 | circle
159 | 0.3
160 |
161 |
162 |
163 | and the file ``input.xml`` contains:
164 |
165 | .. code-block:: xml
166 |
167 |
168 | materials.xml
169 |
170 | square
171 | 20
172 |
173 |
174 |
175 | then running ``microstructpy input.xml`` would be equivalent to running this
176 | file:
177 |
178 | .. code-block:: xml
179 |
180 |
181 |
182 | Fine 1
183 | circle
184 | 0.1
185 |
186 |
187 |
188 | Fine 2
189 | circle
190 | 0.1
191 |
192 |
193 |
194 | Coarse
195 | circle
196 | 0.3
197 |
198 |
199 |
200 | square
201 | 20
202 |
203 |
204 |
205 |
206 | The ```` tag can reduce file sizes and the amount of copy/paste for
207 | microstructures with multiple materials of the same size distribution,
208 | or multiple runs with the same material.
209 |
--------------------------------------------------------------------------------
/docs/source/contents.rst:
--------------------------------------------------------------------------------
1 | :orphan:
2 |
3 | MicroStructPy Contents
4 | ======================
5 |
6 | .. toctree::
7 | :maxdepth: 3
8 |
9 | welcome
10 | getting_started
11 | examples/index
12 | cli/index
13 | package_guide
14 | file_formats
15 | api/index
16 | troubleshooting
17 |
--------------------------------------------------------------------------------
/docs/source/docutils.conf:
--------------------------------------------------------------------------------
1 | [restructuredtext parser]
2 | tab_width: 4
--------------------------------------------------------------------------------
/docs/source/examples/cli/basalt.rst:
--------------------------------------------------------------------------------
1 | .. _ex_basalt:
2 |
3 | ===============
4 | Picritic Basalt
5 | ===============
6 |
7 | XML Input File
8 | ==============
9 |
10 | The basename for this file is ``basalt_circle.xml``.
11 | The file can be run using this command::
12 |
13 | microstructpy --demo=basalt_circle.xml
14 |
15 | The full text of the file is:
16 |
17 | .. literalinclude:: ../../../../src/microstructpy/examples/basalt_circle.xml
18 | :language: xml
19 |
20 |
21 | Material 1 - Plagioclase
22 | ========================
23 |
24 | Plagioclase composes approximately 45% of this picritic basalt sample.
25 | It is an *aphanitic* component, meaning fine-grained, and follows a custom
26 | size distribution.
27 |
28 | Material 2 - Olivine
29 | ====================
30 |
31 | Olivine composes approximately 19% of this picritic basalt sample.
32 | There are large *phenocrysts* of olivine in picritic basalt, so the crystals
33 | are generally larger than the other components and have a non-circular shape.
34 | The orientation of the phenocrysts is uniform random, with the aspect ratio
35 | varying from 1 to 3 uniformly.
36 |
37 | Materials 3-8
38 | =============
39 |
40 | Diopside, hypersthene, magnetite, chromite, ilmenite, and apatie compose
41 | approximately 36% of this picritic basalt sample.
42 | They are *aphanitic* components, meaning fine-grained, and follow a custom
43 | size distribution.
44 |
45 | Domain Geometry
46 | ===============
47 |
48 | These materials fill a circular domain with a diameter of 30 mm.
49 |
50 |
51 | Settings
52 | ========
53 |
54 | The function will output plots of the microstructure process and those plots
55 | are saved as PNGs.
56 | They are saved in a folder named ``basalt_circle``, in the current directory
57 | (i.e ``./basalt_circle``).
58 |
59 | The axes are turned off in these plots, creating PNG files with
60 | minimal whitespace.
61 |
62 | Mesh controls are introducted to increase grid resolution, particularly at the
63 | grain boundaries.
64 |
65 |
66 | Output Files
67 | ============
68 |
69 | The three plots that this file generates are the seeding, the polygon mesh,
70 | and the triangular mesh.
71 | These three plots are shown in
72 | :numref:`f_ex_basalt_seeds` - :numref:`f_ex_basalt_tri`.
73 |
74 | .. _f_ex_basalt_seeds:
75 | .. figure:: ../../../../src/microstructpy/examples/basalt_circle/seeds.png
76 | :alt: Seed geometries.
77 |
78 | Picritic basalt example - seed geometries
79 |
80 | .. _f_ex_basalt_poly:
81 | .. figure:: ../../../../src/microstructpy/examples/basalt_circle/polymesh.png
82 | :alt: Polygonal mesh.
83 |
84 | Picritic basalt example - polygonal mesh
85 |
86 | .. _f_ex_basalt_tri:
87 | .. figure:: ../../../../src/microstructpy/examples/basalt_circle/trimesh.png
88 | :alt: Triangular mesh.
89 |
90 | Picritic basalt example - triangular mesh
91 |
92 | With the ```` flag set to ``True``, verification plots are
93 | generated by MicroStructPy.
94 | The grain size distribution comparison is given in :numref:`f_ex_basalt_verif`.
95 |
96 | .. _f_ex_basalt_verif:
97 | .. figure:: ../../../../src/microstructpy/examples/basalt_circle/verification/size_cdf.png
98 | :alt: Comparing input and output CSDs.
99 |
100 | Picritic basalt example - input and output crystal size
101 | distributions (CSDs).
102 |
103 | Comparing the input and output distributions for olivine, it is clear that this
104 | microstructure is not statistically representative.
105 | A larger diameter for the domain would contain more grains of olivine, which
106 | would add more fidelity to the size CDF curve.
107 |
108 |
--------------------------------------------------------------------------------
/docs/source/examples/cli/colormap.rst:
--------------------------------------------------------------------------------
1 | .. _ex_colormap:
2 |
3 | ========
4 | Colormap
5 | ========
6 |
7 | In this example, a 3D microstructure is generated with grains colored by their
8 | seed number, rather than the material.
9 |
10 | XML Input File
11 | ==============
12 |
13 | The basename for this input file is ``colormap.xml``.
14 | The file can be run using this command::
15 |
16 | microstructpy --demo=colormap.xml
17 |
18 | The full text of the script is:
19 |
20 | .. literalinclude:: ../../../../src/microstructpy/examples/colormap.xml
21 | :language: xml
22 |
23 |
24 | Materials
25 | =========
26 |
27 | There is a single material with grain sizes ranging from 1 to 3 on a
28 | uniform distribution.
29 |
30 | Domain
31 | ======
32 |
33 | The domain of the microstructure is a :class:`.Cube`.
34 | The cube's center is at the origin and its side length is 15.
35 |
36 | Settings
37 | ========
38 |
39 | The output directory is ``./colormap``, which contains the text files
40 | and PNG plots of the microstructure.
41 | The minimum dihedral angle for the mesh elements is set to 15 degrees to
42 | ensure mesh quality.
43 |
44 | The ```` option indicates how to color seeds in the output plots.
45 | There are three values available for this option: "material", "seed number",
46 | and "material number".
47 | The "material" value will use colors specified in each ```` field.
48 | The "seed number" value will use the seed numbers as values for a colormap.
49 | Similarly, "material number" will use the material number in a colormap.
50 |
51 | The ```` option indicates which colormap should be used in the output
52 | plot.
53 | The default colormap is "viridis", which is also the default for matplotlib.
54 | A complete listing of available colormaps is available on the matplotlib
55 | `Choosing Colormaps in Matplotlib`_ webpage.
56 |
57 | Output Files
58 | ============
59 |
60 | The three plots that this file generates are the seeding, the polygon mesh,
61 | and the triangular mesh.
62 | These three plots are shown in :numref:`f_ex_colormap_seeds` -
63 | :numref:`f_ex_colormap_tri`.
64 |
65 | .. _f_ex_colormap_seeds:
66 | .. figure:: ../../../../src/microstructpy/examples/colormap/seeds.png
67 | :alt: Seed geometries.
68 |
69 | Colormap example - seed geometries.
70 |
71 | .. _f_ex_colormap_poly:
72 | .. figure:: ../../../../src/microstructpy/examples/colormap/polymesh.png
73 | :alt: Polygonal mesh.
74 |
75 | Colormap example - polygonal mesh.
76 |
77 | .. _f_ex_colormap_tri:
78 | .. figure:: ../../../../src/microstructpy/examples/colormap/trimesh.png
79 | :alt: Triangular mesh.
80 |
81 | Colormap example - triangular mesh.
82 |
83 |
84 | .. _`Choosing Colormaps in Matplotlib`: https://matplotlib.org/3.1.0/tutorials/colors/colormaps.html
85 |
--------------------------------------------------------------------------------
/docs/source/examples/cli/elliptical_grains.rst:
--------------------------------------------------------------------------------
1 | .. _ex_elliptical_grains:
2 |
3 | =================
4 | Elliptical Grains
5 | =================
6 |
7 | XML Input File
8 | ==============
9 |
10 | The basename for this file is ``elliptical_grains.xml``.
11 | The file can be run using this command::
12 |
13 | microstructpy --demo=elliptical_grains.xml
14 |
15 | The full text of the file is:
16 |
17 | .. literalinclude:: ../../../../src/microstructpy/examples/elliptical_grains.xml
18 | :language: xml
19 |
20 |
21 | Materials
22 | =========
23 |
24 | There are five materials, represented in equal proportions.
25 | The first material consists of ellipses and the semi-major axes are
26 | uniformly distributed, :math:`A \sim U(0.20, 0.75)`.
27 | The semi-minor axes are fixed at 0.05, meaning the aspect ratio of these
28 | seeds are 4-15.
29 | The orientation angles of the ellipses are uniform random in distribution from
30 | 0 to 20 degrees counterclockwise from the +x axis.
31 |
32 | The remaining four materials are all the same, with lognormal grain area
33 | distributions.
34 | The only difference among these materials is the color, which was done for
35 | visual effect.
36 |
37 |
38 | Domain Geometry
39 | ===============
40 |
41 | The domain of the microstructure is a rectangle with side lengths 2.4 in the
42 | x-direction and 1.2 in the y-direction.
43 | The domain is centered on the origin, though the position of the domain is
44 | not relevant considering that the plot axes are switched off.
45 |
46 |
47 | Settings
48 | ========
49 |
50 | The aspect ratio of elements in the triangular mesh is controlled
51 | by setting the minimum interior angle for the elements at 20 degrees,
52 | the maximum element volume to 0.001, and the maximum edge length at grain
53 | boundaries to 0.01.
54 |
55 | The function will output only plots of the microstructure process
56 | (no text files), and those plots are saved as PNGs.
57 | They are saved in a folder named ``elliptical_grains``, in the current directory
58 | (i.e ``./elliptical_grains``).
59 |
60 | The axes are turned off in these plots, creating PNG files with
61 | minimal whitespace.
62 |
63 | Finally, the linewiths in the seeds plot, polygonal mesh plot, and the
64 | triangular mesh plot are 0.5, 0.5, 0.1 respectively.
65 |
66 |
67 | Output Files
68 | ============
69 |
70 | The three plots that this file generates are the seeding, the polygon mesh,
71 | and the triangular mesh.
72 | These three plots are shown in :numref:`f_ex_ell_seeds` -
73 | :numref:`f_ex_ell_tri`.
74 |
75 | .. _f_ex_ell_seeds:
76 | .. figure:: ../../../../src/microstructpy/examples/elliptical_grains/seeds.png
77 | :alt: Seed geometries.
78 |
79 | Elliptical grain example - seed geometries.
80 |
81 | .. _f_ex_ell_poly:
82 | .. figure:: ../../../../src/microstructpy/examples/elliptical_grains/polymesh.png
83 | :alt: Polygonal mesh.
84 |
85 | Elliptical grain example - polygonal mesh.
86 |
87 | .. _f_ex_ell_tri:
88 | .. figure:: ../../../../src/microstructpy/examples/elliptical_grains/trimesh.png
89 | :alt: Triangular mesh.
90 |
91 | Elliptical grain example - triangular mesh.
92 |
93 |
--------------------------------------------------------------------------------
/docs/source/examples/cli/minimal.rst:
--------------------------------------------------------------------------------
1 | .. _ex_minimal:
2 |
3 | ===============
4 | Minimal Example
5 | ===============
6 |
7 | XML Input File
8 | ==============
9 |
10 | The basename for this file is ``minimal_paired.xml``.
11 | The file can be run using this command::
12 |
13 | microstructpy --demo=minimal_paired.xml
14 |
15 | The full text of the file is:
16 |
17 | .. literalinclude:: ../../../../src/microstructpy/examples/minimal_paired.xml
18 | :language: xml
19 |
20 |
21 | Material
22 | ========
23 |
24 | There is only one material, with a constant size of 0.09.
25 |
26 | Domain Geometry
27 | ===============
28 |
29 | The material fills a square domain.
30 | The default side length is 1, meaning the domain is greater than 10x larger
31 | than the grains.
32 |
33 |
34 | Settings
35 | ========
36 |
37 | The function will output plots of the microstructure process and those plots
38 | are saved as PNGs.
39 | They are saved in a folder named ``minimal``, in the current directory
40 | (i.e ``./minimal``).
41 |
42 | The axes are turned off in these plots, creating PNG files with
43 | minimal whitespace.
44 |
45 | This example also demonstrates how to use gmsh to generate a mesh, using the
46 | ```` and ```` tags in the input file.
47 |
48 | Finally, the seeds and grains are colored by their seed number, not by
49 | material.
50 |
51 |
52 | Output Files
53 | ============
54 |
55 | The three plots that this file generates are the seeding, the polygon mesh,
56 | and the triangular mesh.
57 | These three plots are shown in :numref:`f_ex_min_seeds` -
58 | :numref:`f_ex_min_tri`.
59 |
60 | .. _f_ex_min_seeds:
61 | .. figure:: ../../../../src/microstructpy/examples/minimal/seeds.png
62 | :alt: Seed geometries.
63 |
64 | Minimal example - seed geometries.
65 |
66 | .. _f_ex_min_poly:
67 | .. figure:: ../../../../src/microstructpy/examples/minimal/polymesh.png
68 | :alt: Polygonal mesh.
69 |
70 | Minimal example - polygonal mesh.
71 |
72 | .. _f_ex_min_tri:
73 | .. figure:: ../../../../src/microstructpy/examples/minimal/trimesh.png
74 | :alt: Triangular mesh.
75 |
76 | Minimal example - triangular mesh.
--------------------------------------------------------------------------------
/docs/source/examples/cli/two_phase_3d.rst:
--------------------------------------------------------------------------------
1 | .. _ex_2phase_3d:
2 |
3 | ====================
4 | Two Phase 3D Example
5 | ====================
6 |
7 | XML Input File
8 | ==============
9 |
10 | The basename for this file is ``two_phase_3D.xml``.
11 | The file can be run using this command::
12 |
13 | microstructpy --demo=two_phase_3D.xml
14 |
15 | The full text of the file is:
16 |
17 | .. literalinclude:: ../../../../src/microstructpy/examples/two_phase_3D.xml
18 | :language: xml
19 |
20 |
21 | Materials
22 | =========
23 |
24 | The first material makes up 25% of the volume, with a lognormal grain volume
25 | distribution.
26 |
27 | The second material makes up 75% of the volume, with an independent grain
28 | volume distribution.
29 |
30 | Domain Geometry
31 | ===============
32 |
33 | These two materials fill a cube domain of side length 7.
34 |
35 |
36 | Settings
37 | ========
38 |
39 | The function will output plots of the microstructure process and those plots
40 | are saved as PNGs.
41 | They are saved in a folder named ``two_phase_3D``, in the current directory
42 | (i.e ``./two_phase_3D``).
43 |
44 | The line width of the output plots is reduced to 0.2, to make them more
45 | visible.
46 |
47 |
48 | Output Files
49 | ============
50 |
51 | The three plots that this file generates are the seeding, the polygon mesh,
52 | and the triangular mesh.
53 | These three plots are shown in :numref:`f_ex_2p3d_seeds` -
54 | :numref:`f_ex_2p3d_tri`.
55 |
56 | .. _f_ex_2p3d_seeds:
57 | .. figure:: ../../../../src/microstructpy/examples/two_phase_3D/seeds.png
58 | :alt: Seed geometries.
59 |
60 | Two phase 3D example - seed geometries.
61 |
62 | .. _f_ex_2p3d_poly:
63 | .. figure:: ../../../../src/microstructpy/examples/two_phase_3D/polymesh.png
64 | :alt: Polygonal mesh.
65 |
66 | Two phase 3D example - polygonal mesh.
67 |
68 | .. _f_ex_2p3d_tri:
69 | .. figure:: ../../../../src/microstructpy/examples/two_phase_3D/trimesh.png
70 | :alt: Triangular mesh.
71 |
72 | Two phase 3D example - triangular mesh.
73 |
--------------------------------------------------------------------------------
/docs/source/examples/index.rst:
--------------------------------------------------------------------------------
1 | .. _examples_page:
2 |
3 | Examples
4 | =========
5 |
6 | The following contains examples of MicroStructPy.
7 | These examples include an introduction to the XML input files,
8 | some more advanced input files used on the CLI,
9 | and scripts that use the Python package.
10 |
11 | .. _intro_examples:
12 |
13 | Input File Introduction
14 | -----------------------
15 |
16 | .. toctree::
17 | :maxdepth: 1
18 | :numbered:
19 |
20 | intro/intro_1
21 | intro/intro_2
22 | intro/intro_3
23 | intro/intro_4
24 | intro/intro_5
25 | intro/intro_6
26 |
27 | .. only:: html
28 |
29 | .. image:: ../../../src/microstructpy/examples/intro_1_basic/trimesh.png
30 | :alt: Triangular mesh from first intro example.
31 | :width: 32%
32 | :target: intro/intro_1.html
33 |
34 |
35 | .. image:: ../../../src/microstructpy/examples/intro_2_quality/trimesh.png
36 | :alt: Triangular mesh from second intro example.
37 | :width: 32%
38 | :target: intro/intro_2.html
39 |
40 |
41 | .. image:: ../../../src/microstructpy/examples/intro_3_size_shape/trimesh.png
42 | :alt: Triangular mesh from third intro example.
43 | :width: 32%
44 | :target: intro/intro_3.html
45 |
46 |
47 | .. image:: ../../../src/microstructpy/examples/intro_4_oriented/trimesh.png
48 | :alt: Triangular mesh from fourth intro example.
49 | :width: 32%
50 | :target: intro/intro_4.html
51 |
52 |
53 | .. image:: ../../../src/microstructpy/examples/intro_5_plotting/trimesh.png
54 | :alt: Triangular mesh from fifth intro example.
55 | :width: 32%
56 | :target: intro/intro_5.html
57 |
58 |
59 | .. image:: ../../../src/microstructpy/examples/intro_6_culmination/trimesh.png
60 | :alt: Triangular mesh from sixth intro example.
61 | :width: 32%
62 | :target: intro/intro_6.html
63 |
64 |
65 | .. _cli_examples:
66 |
67 | CLI Examples
68 | ------------
69 |
70 | .. toctree::
71 | :maxdepth: 1
72 |
73 | cli/elliptical_grains
74 | cli/minimal
75 | cli/basalt
76 | cli/two_phase_3d
77 | cli/colormap
78 |
79 | .. only:: html
80 |
81 | .. image:: ../../../src/microstructpy/examples/elliptical_grains/trimesh.png
82 | :alt: Triangular mesh with elliptical grains.
83 | :width: 64%
84 | :target: cli/elliptical_grains.html
85 |
86 | .. image:: ../../../src/microstructpy/examples/minimal/polymesh.png
87 | :alt: Polygonal mesh from minimal example.
88 | :width: 32%
89 | :target: cli/minimal.html
90 |
91 | .. image:: ../../../src/microstructpy/examples/basalt_circle/trimesh.png
92 | :alt: Triangular mesh from basalt example.
93 | :width: 32%
94 | :target: cli/basalt.html
95 |
96 | .. image:: ../../../src/microstructpy/examples/two_phase_3D/polymesh.png
97 | :alt: Polygonal mesh from 3D two phase example.
98 | :width: 32%
99 | :target: cli/two_phase_3d.html
100 |
101 | .. image:: ../../../src/microstructpy/examples/colormap/trimesh.png
102 | :alt: Triangular mesh from 3D colormap example.
103 | :width: 32%
104 | :target: cli/colormap.html
105 |
106 |
107 |
108 | .. _package_examples:
109 |
110 | Python Package Examples
111 | -----------------------
112 |
113 | .. toctree::
114 | :maxdepth: 1
115 |
116 | package/standard_voronoi
117 | package/uniform_seeding
118 | package/foam
119 | package/logo
120 | package/grain_neighborhoods
121 | package/from_image
122 | package/mesh_process
123 |
124 | .. only:: html
125 |
126 | .. image:: ../../../src/microstructpy/examples/standard_voronoi/voronoi_diagram.png
127 | :alt: Standard Voronoi diagram.
128 | :height: 210px
129 | :target: package/standard_voronoi.html
130 |
131 | .. image:: ../../../src/microstructpy/examples/uniform_seeding/voronoi_diagram.png
132 | :alt: Voronoi diagram with uniformly-spaced seeds, colored by area.
133 | :height: 210px
134 | :target: package/uniform_seeding.html
135 |
136 | .. image:: ../../../src/microstructpy/examples/foam/trimesh.png
137 | :alt: Mesh of foam microstructure.
138 | :height: 210px
139 | :target: package/foam.html
140 |
141 | .. image:: ../../../src/microstructpy/examples/logo/logo.png
142 | :alt: MicroStructPy logo.
143 | :height: 210px
144 | :target: package/logo.html
145 |
146 | .. image:: ../../../src/microstructpy/examples/grain_neighborhoods/trimesh.png
147 | :alt: Triangular mesh of microstructure with seed neighborhoods.
148 | :height: 210px
149 | :target: package/grain_neighborhoods.html
150 |
151 | .. image:: ../../../src/microstructpy/examples/from_image/trimesh.png
152 | :alt: Triangular mesh of aluminum microstructure.
153 | :height: 210px
154 | :target: package/from_image.html
155 |
156 | .. image:: ../../../src/microstructpy/examples/docs_banner/banner.png
157 | :alt: Microstructure meshing process..
158 | :target: package/mesh_process.html
159 |
--------------------------------------------------------------------------------
/docs/source/examples/intro/intro_1.rst:
--------------------------------------------------------------------------------
1 | .. _ex_1_basic:
2 |
3 | =============
4 | Basic Example
5 | =============
6 |
7 | XML Input File
8 | ==============
9 |
10 | The basename for this file is ``intro_1_basic.xml``.
11 | The file can be run using this command::
12 |
13 | microstructpy --demo=intro_1_basic.xml
14 |
15 | The full text of the file is:
16 |
17 | .. literalinclude:: ../../../../src/microstructpy/examples/intro_1_basic.xml
18 | :language: xml
19 |
20 |
21 | Materials
22 | =========
23 |
24 | There are two materials, in a 2:1 ratio based on volume.
25 | The first is a matrix, which is represented with small circles.
26 | The size and shape of matrix grain particles are not critical, since
27 | the boundaries between them will be removed before triangular meshing.
28 | The second material consists of circular inclusions with diameter 2.
29 |
30 | Domain Geometry
31 | ===============
32 |
33 | The domain of the microstructure is a square with its bottom-left
34 | corner fixed to the origin.
35 | The side length is 20, which is 10x the size of the inclusions to ensure that
36 | the microstructure is statistically representative.
37 |
38 |
39 | Settings
40 | ========
41 |
42 | Many settings have been left to their defaults, with the exceptions being the
43 | verbose mode and output directory.
44 |
45 | By default, MicroStructPy does not print status updates to the command line.
46 | Switching the verbose mode on will regularly print the status of the code.
47 |
48 | The output directory is a filepath for writing text and image files.
49 | By default, MicroStructPy outputs texts files containing data on the seeds,
50 | polygon mesh, and triangular mesh as well as the corresponding image files,
51 | saved in PNG format.
52 |
53 | .. note::
54 |
55 | The ```` field can be an absolute or relative filepath. If it is
56 | relative, outputs are written relative to the **input file**, not the
57 | current working directory.
58 |
59 |
60 | Output Files
61 | ============
62 |
63 | The three plots that this file generates are the seeding, the polygon mesh,
64 | and the triangular mesh.
65 | These three plots are shown in :numref:`f_ex_1_basic_seeds` -
66 | :numref:`f_ex_1_basic_tri`.
67 |
68 | .. _f_ex_1_basic_seeds:
69 | .. figure:: ../../../../src/microstructpy/examples/intro_1_basic/seeds.png
70 | :alt: Seed geometries.
71 |
72 | Introduction 1 - seed geometries.
73 |
74 | .. _f_ex_1_basic_poly:
75 | .. figure:: ../../../../src/microstructpy/examples/intro_1_basic/polymesh.png
76 | :alt: Polygonal mesh.
77 |
78 | Introduction 1 - polygonal mesh.
79 |
80 | .. _f_ex_1_basic_tri:
81 | .. figure:: ../../../../src/microstructpy/examples/intro_1_basic/trimesh.png
82 | :alt: Triangular mesh.
83 |
84 | Introduction 1 - triangular mesh.
--------------------------------------------------------------------------------
/docs/source/examples/intro/intro_2.rst:
--------------------------------------------------------------------------------
1 | .. _ex_2_quality:
2 |
3 | ================
4 | Quality Controls
5 | ================
6 |
7 | XML Input File
8 | ==============
9 |
10 | The basename for this file is ``intro_2_quality.xml``.
11 | The file can be run using this command::
12 |
13 | microstructpy --demo=intro_2_quality.xml
14 |
15 | The full text of the file is:
16 |
17 | .. literalinclude:: ../../../../src/microstructpy/examples/intro_2_quality.xml
18 | :language: xml
19 |
20 |
21 | Materials
22 | =========
23 |
24 | There are two materials, in a 2:1 ratio based on volume.
25 | The first is a matrix, which is represented with small circles.
26 | The second material consists of circular inclusions with diameter 2.
27 |
28 | Domain Geometry
29 | ===============
30 |
31 | These two materials fill a square domain.
32 | The bottom-left corner of the rectangle is the origin, which puts the
33 | rectangle in the first quadrant.
34 | The side length is 20, which is 10x the size of the inclusions to ensure that
35 | microstructure is statistically representative.
36 |
37 |
38 | Settings
39 | ========
40 |
41 | The first two settings determine the output directory and whether to run the
42 | program in verbose mode.
43 | The following settings determine the quality of the triangular mesh.
44 |
45 | The minimum interior angle of the elements is 25 degrees, ensuring lower
46 | aspect ratios compared to the first example.
47 | The maximum area of the elements is also limited to 1, which populates the
48 | matrix with smaller elements.
49 | Finally, The maximum edge length of elements at interfaces is set to 0.1,
50 | which increasing the mesh density surrounding the inclusions and at the
51 | boundary of the domain.
52 |
53 | Note that the edge length control is currently unavailable in 3D.
54 |
55 |
56 | Output Files
57 | ============
58 |
59 | The three plots that this file generates are the seeding, the polygon mesh,
60 | and the triangular mesh.
61 | These three plots are shown in :numref:`f_ex_2_quality_seeds` -
62 | :numref:`f_ex_2_quality_tri`.
63 |
64 | .. _f_ex_2_quality_seeds:
65 | .. figure:: ../../../../src/microstructpy/examples/intro_2_quality/seeds.png
66 | :alt: Seed geometries.
67 |
68 | Introduction 2 - seed geometries.
69 |
70 | .. _f_ex_2_quality_poly:
71 | .. figure:: ../../../../src/microstructpy/examples/intro_2_quality/polymesh.png
72 | :alt: Polygonal mesh.
73 |
74 | Introduction 2 - polygonal mesh.
75 |
76 | .. _f_ex_2_quality_tri:
77 | .. figure:: ../../../../src/microstructpy/examples/intro_2_quality/trimesh.png
78 | :alt: Triangular mesh.
79 |
80 | Introduction 2 - triangular mesh.
--------------------------------------------------------------------------------
/docs/source/examples/intro/intro_3.rst:
--------------------------------------------------------------------------------
1 | .. _ex_3_shape:
2 |
3 | ============
4 | Size & Shape
5 | ============
6 |
7 | XML Input File
8 | ==============
9 |
10 | The basename for this file is ``intro_3_size_shape.xml``.
11 | The file can be run using this command::
12 |
13 | microstructpy --demo=intro_3_size_shape.xml
14 |
15 | The full text of the file is:
16 |
17 | .. literalinclude:: ../../../../src/microstructpy/examples/intro_3_size_shape.xml
18 | :language: xml
19 |
20 |
21 | Materials
22 | =========
23 |
24 | There are two materials, in a 2:1 ratio based on volume.
25 | The first is a matrix, which is represented with small circles.
26 |
27 | The second material consists of elliptical inclusions with size ranging from
28 | 0 to 2 and aspect ratio ranging from 1 to 3.
29 | Note that the size is defined as the diameter of a circle with equivalent area.
30 | The orientation angle of the inclusions are random, specifically they are
31 | uniformly distributed from 0 to 360 degrees.
32 |
33 | Domain Geometry
34 | ===============
35 |
36 | These two materials fill a square domain.
37 | The bottom-left corner of the rectangle is the origin, which puts the
38 | rectangle in the first quadrant.
39 | The side length is 20, which is 10x the size of the inclusions
40 | to ensure that the microstructure is statistically representative.
41 |
42 |
43 | Settings
44 | ========
45 |
46 | Many settings have been left to their defaults, with the exceptions being the
47 | verbose mode and output directory.
48 |
49 | By default, MicroStructPy does not print status updates to the command line.
50 | Switching the verbose mode on will regularly print the status of the code.
51 |
52 | The output directory is a filepath for writing text and image files.
53 | By default, MicroStructPy outputs texts files containing data on the seeds,
54 | polygon mesh, and triangular mesh as well as the corresponding image files,
55 | saved in PNG format.
56 |
57 | .. note::
58 |
59 | The ```` field can be an absolute or relative filepath. If it is
60 | relative, outputs are written relative to the **input file**, not the
61 | current working directory.
62 |
63 |
64 | Output Files
65 | ============
66 |
67 | The three plots that this file generates are the seeding, the polygon mesh,
68 | and the triangular mesh.
69 | These three plots are shown in :numref:`f_ex_3_size_shape_seeds` -
70 | :numref:`f_ex_3_size_shape_tri`.
71 |
72 | .. _f_ex_3_size_shape_seeds:
73 | .. figure:: ../../../../src/microstructpy/examples/intro_3_size_shape/seeds.png
74 | :alt: Seed geometries.
75 |
76 | Introduction 3 - seed geometries.
77 |
78 | .. _f_ex_3_size_shape_poly:
79 | .. figure:: ../../../../src/microstructpy/examples/intro_3_size_shape/polymesh.png
80 | :alt: Polygonal mesh.
81 |
82 | Introduction 3 - polygonal mesh.
83 |
84 | .. _f_ex_3_size_shape_tri:
85 | .. figure:: ../../../../src/microstructpy/examples/intro_3_size_shape/trimesh.png
86 | :alt: Triangular mesh.
87 |
88 | Introduction 3 - triangular mesh.
--------------------------------------------------------------------------------
/docs/source/examples/intro/intro_4.rst:
--------------------------------------------------------------------------------
1 | .. _ex_4_oriented:
2 |
3 | ===============
4 | Oriented Grains
5 | ===============
6 |
7 | XML Input File
8 | ==============
9 |
10 | The basename for this file is ``intro_4_oriented.xml``.
11 | The file can be run using this command::
12 |
13 | microstructpy --demo=intro_4_oriented.xml
14 |
15 | The full text of the file is:
16 |
17 | .. literalinclude:: ../../../../src/microstructpy/examples/intro_4_oriented.xml
18 | :language: xml
19 |
20 |
21 | Materials
22 | =========
23 |
24 | There are two materials, in a 2:1 ratio based on volume.
25 | The first is a matrix, which is represented with small circles.
26 |
27 | The second material consists of elliptical inclusions with size ranging from
28 | 0 to 2 and aspect ratio ranging from 1 to 3.
29 | Note that the size is defined as the diameter of a circle with equivalent area.
30 | The orientation angle of the inclusions are uniformly distributed between -10
31 | and +10 degrees, relative to the +x axis.
32 |
33 | Domain Geometry
34 | ===============
35 |
36 | These two materials fill a square domain.
37 | The bottom-left corner of the rectangle is the origin, which puts the
38 | rectangle in the first quadrant.
39 | The side length is 20, which is 10x the size of the inclusions
40 | to ensure that the microstructure is statistically representative.
41 |
42 |
43 | Settings
44 | ========
45 |
46 | Many settings have been left to their defaults, with the exceptions being the
47 | verbose mode and output directory.
48 |
49 | By default, MicroStructPy does not print status updates to the command line.
50 | Switching the verbose mode on will regularly print the status of the code.
51 |
52 | The output directory is a filepath for writing text and image files.
53 | By default, MicroStructPy outputs texts files containing data on the seeds,
54 | polygon mesh, and triangular mesh as well as the corresponding image files,
55 | saved in PNG format.
56 |
57 | .. note::
58 |
59 | The ```` field can be an absolute or relative filepath. If it is
60 | relative, outputs are written relative to the **input file**, not the
61 | current working directory.
62 |
63 |
64 | Output Files
65 | ============
66 |
67 | The three plots that this file generates are the seeding, the polygon mesh,
68 | and the triangular mesh.
69 | These three plots are shown in :numref:`f_ex_4_oriented_seeds` -
70 | :numref:`f_ex_4_oriented_tri`.
71 |
72 | .. _f_ex_4_oriented_seeds:
73 | .. figure:: ../../../../src/microstructpy/examples/intro_4_oriented/seeds.png
74 | :alt: Seed geometries.
75 |
76 | Introduction 4 - seed geometries.
77 |
78 | .. _f_ex_4_oriented_poly:
79 | .. figure:: ../../../../src/microstructpy/examples/intro_4_oriented/polymesh.png
80 | :alt: Polygonal mesh.
81 |
82 | Introduction 4 - polygonal mesh.
83 |
84 | .. _f_ex_4_oriented_tri:
85 | .. figure:: ../../../../src/microstructpy/examples/intro_4_oriented/trimesh.png
86 | :alt: Triangular mesh.
87 |
88 | Introduction 4 - triangular mesh.
89 |
--------------------------------------------------------------------------------
/docs/source/examples/intro/intro_5.rst:
--------------------------------------------------------------------------------
1 | .. _ex_5_plotting:
2 |
3 | =============
4 | Plot Controls
5 | =============
6 |
7 | XML Input File
8 | ==============
9 |
10 | The basename for this file is ``intro_5_plotting.xml``.
11 | The file can be run using this command::
12 |
13 | microstructpy --demo=intro_5_plotting.xml
14 |
15 | The full text of the file is given below.
16 |
17 | .. literalinclude:: ../../../../src/microstructpy/examples/intro_5_plotting.xml
18 | :language: xml
19 |
20 |
21 | Materials
22 | =========
23 |
24 | There are two materials, in a 2:1 ratio based on volume.
25 | The first is a pink matrix, which is represented with small circles.
26 |
27 | The second material consists of lime green circular inclusions with diameter 2.
28 |
29 | Domain Geometry
30 | ===============
31 |
32 | These two materials fill a square domain.
33 | The bottom-left corner of the rectangle is the origin, which puts the
34 | rectangle in the first quadrant.
35 | The side length is 20, which is 10x the size of the inclusions.
36 |
37 |
38 | Settings
39 | ========
40 |
41 | PNG files of each step in the process will be output, as well as the
42 | intermediate text files.
43 | They are saved in a folder named ``intro_5_plotting``, in the current directory
44 | (i.e ``./intro_5_plotting``).
45 | PDF files of the poly and tri mesh are also generated, plus an EPS file for the
46 | tri mesh.
47 |
48 | The seeds are plotted with transparency to show the overlap between them.
49 | The poly mesh is plotted with thick purple edges and the tri mesh is plotted
50 | with thin navy edges.
51 |
52 | In all of the plots, the axes are toggles off, creating image files with
53 | minimal borders.
54 |
55 |
56 | Output Files
57 | ============
58 |
59 | The three plots that this file generates are the seeding, the polygon mesh,
60 | and the triangular mesh.
61 | These three plots are shown in :numref:`f_ex_5_plotting_seeds` -
62 | :numref:`f_ex_5_plotting_tri`.
63 |
64 | .. _f_ex_5_plotting_seeds:
65 | .. figure:: ../../../../src/microstructpy/examples/intro_5_plotting/seeds.png
66 | :alt: Seed geometries.
67 |
68 | Introduction 5 - seed geometries.
69 |
70 | .. _f_ex_5_plotting_poly:
71 | .. figure:: ../../../../src/microstructpy/examples/intro_5_plotting/polymesh.png
72 | :alt: Polygonal mesh.
73 |
74 | Introduction 5 - polygonal mesh.
75 |
76 | .. _f_ex_5_plotting_tri:
77 | .. figure:: ../../../../src/microstructpy/examples/intro_5_plotting/trimesh.png
78 | :alt: Triangular mesh.
79 |
80 | Introduction 5 - triangular mesh.
--------------------------------------------------------------------------------
/docs/source/examples/intro/intro_6.rst:
--------------------------------------------------------------------------------
1 | .. _ex_6_culmin:
2 |
3 | ===========
4 | Culmination
5 | ===========
6 |
7 | XML Input File
8 | ==============
9 |
10 | The basename for this file is ``intro_6_culmination.xml``.
11 | The file can be run using this command::
12 |
13 | microstructpy --demo=intro_6_culmination.xml
14 |
15 | The full text of the file is:
16 |
17 | .. literalinclude:: ../../../../src/microstructpy/examples/intro_6_culmination.xml
18 | :language: xml
19 |
20 |
21 | Materials
22 | =========
23 |
24 | There are two materials, in a 2:1 ratio based on volume.
25 | The first is a pink matrix, which is represented with small circles.
26 |
27 | The second material consists of lime green elliptical inclusions with size
28 | ranging from 0 to 2 and aspect ratio ranging from 1 to 3.
29 | Note that the size is defined as the diameter of a circle with equivalent area.
30 | The orientation angle of the inclusions are uniformly distributed between -10
31 | and +10 degrees, relative to the +x axis.
32 |
33 | Domain Geometry
34 | ===============
35 |
36 | These two materials fill a square domain.
37 | The bottom-left corner of the rectangle is the origin, which puts the
38 | rectangle in the first quadrant.
39 | The side length is 20, which is 10x the size of the inclusions.
40 |
41 |
42 | Settings
43 | ========
44 |
45 | PNG files of each step in the process will be output, as well as the
46 | intermediate text files.
47 | They are saved in a folder named ``intro_5_plotting``, in the current directory
48 | (i.e ``./intro_5_plotting``).
49 | PDF files of the poly and tri mesh are also generated, plus an EPS file for the
50 | tri mesh.
51 |
52 | The seeds are plotted with transparency to show the overlap between them.
53 | The poly mesh is plotted with thick purple edges and the tri mesh is plotted
54 | with thin navy edges.
55 |
56 | In all of the plots, the axes are toggles off, creating image files with
57 | minimal borders.
58 |
59 | The minimum interior angle of the elements is 25 degrees, ensuring lower
60 | aspect ratios compared to the first example.
61 | The maximum area of the elements is also limited to 1, which populates the
62 | matrix with smaller elements.
63 | Finally, The maximum edge length of elements at interfaces is set to 0.1,
64 | which increasing the mesh density surrounding the inclusions and at the
65 | boundary of the domain.
66 |
67 | Note that the edge length control is currently unavailable in 3D.
68 |
69 |
70 | Output Files
71 | ============
72 |
73 | The three plots that this file generates are the seeding, the polygon mesh,
74 | and the triangular mesh.
75 | These three plots are shown in :numref:`f_ex_6_culmination_seeds` -
76 | :numref:`f_ex_6_culmination_tri`.
77 |
78 | .. _f_ex_6_culmination_seeds:
79 | .. figure:: ../../../../src/microstructpy/examples/intro_6_culmination/seeds.png
80 | :alt: Seed geometries.
81 |
82 | Introduction 6 - seed geometries.
83 |
84 | .. _f_ex_6_culmination_poly:
85 | .. figure:: ../../../../src/microstructpy/examples/intro_6_culmination/polymesh.png
86 | :alt: Polygonal mesh.
87 |
88 | Introduction 6 - polygonal mesh.
89 |
90 | .. _f_ex_6_culmination_tri:
91 | .. figure:: ../../../../src/microstructpy/examples/intro_6_culmination/trimesh.png
92 | :alt: Triangular mesh.
93 |
94 | Introduction 6 - triangular mesh.
--------------------------------------------------------------------------------
/docs/source/examples/package/foam.rst:
--------------------------------------------------------------------------------
1 | .. _ex_foam:
2 |
3 | ====
4 | Foam
5 | ====
6 |
7 | In this example, a foam microstructure is generated by first tesselating the
8 | voids, then adding foam material to the edges between the voids.
9 |
10 | Python Script
11 | =============
12 |
13 | The basename for this file is ``foam.py``.
14 | The file can be run using this command::
15 |
16 | microstructpy --demo=foam.py
17 |
18 | The full text of the script is:
19 |
20 | .. literalinclude:: ../../../../src/microstructpy/examples/foam.py
21 | :language: python
22 |
23 | Domain
24 | ======
25 |
26 | The domain of the microstructure is a :class:`.Square`.
27 | Without arguments, the square's center is (0, 0) and side length is 15.
28 |
29 | Seeds
30 | =====
31 |
32 | Initially, the seed list is entirely voids following a lognormal size
33 | distribution.
34 | These are then tessellated to determine the boundaries between the voids.
35 | These voids are generated to fill 70% of the domain and are positioned with
36 | a custom ``rtol`` value of 3%.
37 | This ensures that most of the voids do not connect with each other and that
38 | the foam seeds positioned along the edges do not become consumed by the void
39 | cells.
40 |
41 | Next, foam seeds are added to the edges between voids.
42 | These seeds are given a size distribution, however there are no foam grains
43 | since the material is amorphous.
44 | Once the foam seeds are positioned in the domain, the lists of void and foam
45 | seeds are combined into a single seed list.
46 |
47 | Polygon Mesh
48 | ============
49 |
50 | A polygon mesh is created from the list of seed points using the
51 | :func:`~microstructpy.meshing.PolyMesh.from_seeds` class method.
52 |
53 | Triangular Mesh
54 | ===============
55 |
56 | A triangular mesh is created from the polygonal mesh using the
57 | :func:`~microstructpy.meshing.TriMesh.from_polymesh` class method.
58 | The optional ``phases`` parameter is used in this case since the mesh contains
59 | non-crystalline materials.
60 | Additionally, the minimum interior angle of the mesh elements is set to 20 to
61 | ensure good mesh quality and the maximum edge length is set to increase mesh
62 | resolution near the voids.
63 |
64 | Plotting
65 | ========
66 |
67 | The triangular mesh in this example is plotted in aquamarine, one of
68 | several named colors in matplotlib.
69 | Next, the axes are turned off and the limits are set to equal the bounds of
70 | the domain.
71 | Finally, the triangular mesh is saved as a PNG and as a PDF, with the
72 | resulting plot shown in :numref:`f_ex_foam_tri`.
73 |
74 | .. _f_ex_foam_tri:
75 | .. figure:: ../../../../src/microstructpy/examples/foam/trimesh.png
76 |
77 | Foam example - triangular mesh.
78 |
--------------------------------------------------------------------------------
/docs/source/examples/package/from_image.rst:
--------------------------------------------------------------------------------
1 | .. _ex_from_image:
2 |
3 | =========================
4 | Microstructure from Image
5 | =========================
6 |
7 | .. note::
8 |
9 | The open source and freely available software package OOF is better equiped
10 | to create unstructured meshes from images.
11 |
12 | https://www.ctcms.nist.gov/oof/
13 |
14 |
15 | Python Script
16 | =============
17 |
18 | The basename for this file is ``from_image.py``.
19 | The file can be run using this command::
20 |
21 | microstructpy --demo=from_image.py
22 |
23 | The full text of the script is:
24 |
25 | .. literalinclude:: ../../../../src/microstructpy/examples/from_image.py
26 | :language: python
27 |
28 | Read Image
29 | ==========
30 |
31 | The first section of the script reads the image using matplotlib.
32 | The brightness of the image is taken as the red channel, since the RGB values
33 | are equal. That image is shown in :numref:`f_ex_image_in`.
34 |
35 | .. _f_ex_image_in:
36 | .. figure:: ../../../../src/microstructpy/examples/aluminum_micro.png
37 | :alt: Micrograph of aluminum.
38 |
39 | Micrograph of aluminum.
40 |
41 | Bin Pixels
42 | ==========
43 |
44 | The pixel values are binned based on whether the brightness is above or
45 | below 0.5.
46 |
47 | Phases
48 | ======
49 |
50 | The two phases are considered amorphous, to prevent pixilation in the
51 | triangle mesh.
52 |
53 | Create the Polygon Mesh
54 | =======================
55 |
56 | The polygon mesh is a reproduction of the pixel grid in the image.
57 | The facets are edges between pixels, and the polygons are all squares.
58 |
59 | Create the Triangle Mesh
60 | ========================
61 |
62 | The triangle mesh is created from the polygon mesh and uses the amorphous
63 | specifications for the phases. The minimum interior angle of the triangles
64 | is set to 20 degrees to control the aspect ratio of triangles.
65 |
66 | Plot Triangle Mesh
67 | ==================
68 |
69 | The axes of the plot are switched off, then the triangle mesh is plotted.
70 | The color of each triangle is set by the phase.
71 |
72 | Save Plot and Copy Input File
73 | =============================
74 |
75 | The final plot is saved to a file, then the input image is copied to the
76 | same directory for comparison.
77 | The output PNG file of this script is shown in :numref:`f_ex_image_out`.
78 |
79 | .. _f_ex_image_out:
80 | .. figure:: ../../../../src/microstructpy/examples/from_image/trimesh.png
81 | :alt: Triangular mesh of aluminum microstructure.
82 |
83 | Triangular mesh of aluminum microstructure.
84 |
85 |
86 |
--------------------------------------------------------------------------------
/docs/source/examples/package/grain_neighborhoods.rst:
--------------------------------------------------------------------------------
1 | .. _ex_grain_nbr:
2 |
3 | ===================
4 | Grain Neighborhoods
5 | ===================
6 |
7 | Python Script
8 | =============
9 |
10 | The basename for this file is ``grain_neighborhoods.py``.
11 | The file can be run using this command::
12 |
13 | microstructpy --demo=grain_neighborhoods.py
14 |
15 | The full text of the script is:
16 |
17 | .. literalinclude:: ../../../../src/microstructpy/examples/grain_neighborhoods.py
18 | :language: python
19 |
20 | Domain
21 | ======
22 |
23 | The domain of the microstructure is a
24 | :class:`microstructpy.geometry.Rectangle`, with the bottom left corner at the
25 | origin and side lengths of 8 and 12.
26 |
27 | Phases
28 | ======
29 |
30 | There are initially two phases: a matrix phase and a neighborhood phase.
31 | The neighborhood phase will be broken down into materials later. The matrix
32 | phase occupies two thirds of the domain, while the neighborhoods occupy one
33 | third.
34 |
35 | Seeds
36 | =====
37 |
38 | The seeds are generated to fill 1.1x the area of the domain, to account for
39 | overlap with the boundaries. They are positioned according to random uniform
40 | distributions.
41 |
42 | Neighborhood Replacement
43 | ========================
44 |
45 | The neighborhood seeds are replaced by a set of three different materials.
46 | One material occupies the center of the neighborhood, while the other two
47 | alternate in a ring around the center.
48 |
49 | Polygon and Triangle Meshing
50 | ============================
51 |
52 | The seeds are converted into a triangular mesh by first constructing a
53 | polygon mesh. Each material is solid, except for the first which is designated
54 | as a matrix phase. Mesh quality controls are specified to prevent high aspect
55 | ratio triangles.
56 |
57 | Plotting
58 | ========
59 |
60 | The triangular mesh is plotted and saved to a file.
61 | Each triangle is colored based on its material phase, using the standard
62 | matplotlib colors: C0, C1, C2, etc.
63 | The output PNG file is shown in :numref:`f_ex_neighs_tri`.
64 |
65 | .. _f_ex_neighs_tri:
66 | .. figure:: ../../../../src/microstructpy/examples/grain_neighborhoods/trimesh.png
67 | :alt: Triangular mesh of microstructure with seed neighborhoods.
68 |
69 | Triangular mesh of microstructure with seed neighborhoods.
--------------------------------------------------------------------------------
/docs/source/examples/package/logo.rst:
--------------------------------------------------------------------------------
1 | .. _ex_logo:
2 |
3 | ==================
4 | MicroStructPy Logo
5 | ==================
6 |
7 | Python Script
8 | =============
9 |
10 | The basename for this file is ``logo.py``.
11 | The file can be run using this command::
12 |
13 | microstructpy --demo=logo.py
14 |
15 | The full text of the script is:
16 |
17 | .. literalinclude:: ../../../../src/microstructpy/examples/logo.py
18 | :language: python
19 |
20 | Domain
21 | ======
22 |
23 | The domain of the microstructure is a :class:`.Circle`.
24 | Without arguments, the circle's center is (0, 0) and side length is 1.
25 |
26 | Seeds
27 | =====
28 |
29 | The seeds are 14 circles with radii uniformly distributed from 0 to 0.3.
30 | Calling the :func:`~microstructpy.seeding.SeedList.position` method
31 | positions the points according to random uniform distributions in the domain.
32 |
33 | Polygon Mesh
34 | ============
35 |
36 | A polygon mesh is created from the list of seed points using the
37 | :func:`~microstructpy.meshing.PolyMesh.from_seeds` class method.
38 | The mesh is plotted and saved into a PNG file in the remaining lines of the
39 | script.
40 |
41 | Plot Logo
42 | =========
43 |
44 | The edges in the polygonal mesh are plotted white on a black background.
45 | This image is converted into a mask and the white pixels are converted into
46 | transparent pixels.
47 | The remaining pixels are colored with a linear gradient between two colors.
48 | This image is saved in padded and tight versions, as well as a favicon for the
49 | HTML documentation.
50 | The logo that results is shown in :numref:`f_ex_logo`.
51 |
52 | .. _f_ex_logo:
53 | .. figure:: ../../../../src/microstructpy/examples/logo/logo.png
54 | :alt: MicroStructPy logo.
55 |
56 | MicroStructPy logo.
57 |
58 |
--------------------------------------------------------------------------------
/docs/source/examples/package/mesh_process.rst:
--------------------------------------------------------------------------------
1 | .. _ex_docs_banner:
2 |
3 | ===========================
4 | Microstructure Mesh Process
5 | ===========================
6 |
7 | Python Script
8 | =============
9 |
10 | The basename for this file is ``docs_banner.py``.
11 | The file can be run using this command::
12 |
13 | microstructpy --demo=docs_banner.py
14 |
15 | The full text of the file is:
16 |
17 | .. literalinclude:: ../../../../src/microstructpy/examples/docs_banner.py
18 | :language: python
19 |
20 | Domain Geometry
21 | ===============
22 |
23 | The materials fill a rectangular domain with side lengths 20 and 10.
24 | The center of the rectangle defaults to the origin.
25 |
26 | Seeds
27 | =====
28 |
29 | The first material is phase 2, which contains a single elliptical seed with
30 | semi-axes 8 and 3.
31 | Next, phases 0 and 1 are created with identical size distributions and
32 | different colors.
33 | The size distributions are uniform random from 0.5 to 1.5.
34 | Seeds of phase 0 and phase 1 are generated to fill the area between the
35 | rectangular domain and the elliptical seed from phase 2.
36 |
37 | Next, the phase 2 seed is appended to the list of phase 0 and 1 seeds.
38 | A hold list is then created to indicate to
39 | :func:`~microstructpy.seeding.SeedList.position`
40 | which seeds should have their positions (centers) held.
41 | The default position of a seed is the origin, so by setting the hold flag to
42 | ``True`` for the elliptical seed, it will be fixed to the center of the domain
43 | while the remaining seeds will be randomly positioned around it.
44 |
45 | Polygonal and Triangular Meshing
46 | ================================
47 |
48 | Once the seeds are positioned in the domain, a polygonal mesh is created using
49 | :func:`~microstructpy.meshing.PolyMesh.from_seeds`.
50 | The triangular mesh is created using
51 | :func:`~microstructpy.meshing.TriMesh.from_polymesh`,
52 | with the quality control settings ``min_angle``, ``max_edge_length``, and
53 | ``max_volume``.
54 |
55 | Plot Figure
56 | ===========
57 |
58 | The figure contains three plots: the seeds, the polygonal mesh, and the
59 | triangular/unstructured mesh.
60 | First, the seeds plot is generated using SeedList
61 | :func:`~microstructpy.seeding.SeedList.plot`
62 | and Rectangle
63 | :func:`~microstructpy.geometry.Rectangle.plot`
64 | to show the boundary of the domain.
65 | The seeds are plotted with some transparency to show overlap.
66 |
67 | Next, the polygonal mesh is translated to the right and plotted in such a way
68 | that avoids the internal geometry of the elliptical seed.
69 | This internal geometry is created by the multi-circle approximation used in
70 | polygonal meshing, then removed during the triangular meshing process.
71 | In the interest of clarity, these two steps are combined and the elliptical
72 | grain is plotted without internal geomtry.
73 |
74 | Finally, the triangular mesh is translated to the right of the polygonal mesh
75 | and plotted using TriMesh
76 | :func:`~microstructpy.meshing.TriMesh.plot`.
77 |
78 | Once all three plots have been added to the figure, the axes and
79 | aspect ratio are adjusted.
80 | This figure is shown in :numref:`f_ex_process`.
81 | The PNG and PDF versions of this plot are saved in a folder named
82 | ``docs_banner``, in the current directory (i.e ``./docs_banner``).
83 |
84 | .. _f_ex_process:
85 | .. figure:: ../../../../src/microstructpy/examples/docs_banner/banner.png
86 | :alt: Microstructure meshing process.
87 |
88 | Microstructure meshing process.
89 |
90 | The three major steps are:
91 | 1) seed the domain with particles,
92 | 2) create a Voronoi power diagram, and
93 | 3) convert the diagram into an unstructured mesh.
--------------------------------------------------------------------------------
/docs/source/examples/package/standard_voronoi.rst:
--------------------------------------------------------------------------------
1 | .. _ex_std_voro:
2 |
3 | ========================
4 | Standard Voronoi Diagram
5 | ========================
6 |
7 | Python Script
8 | =============
9 |
10 | The basename for this file is ``standard_voronoi.py``.
11 | The file can be run using this command::
12 |
13 | microstructpy --demo=standard_voronoi.py
14 |
15 | The full text of the script is:
16 |
17 | .. literalinclude:: ../../../../src/microstructpy/examples/standard_voronoi.py
18 | :language: python
19 |
20 | Domain
21 | ======
22 |
23 | The domain of the microstructure is a :class:`.Square`.
24 | Without arguments, the square's center is (0, 0) and side length is 1.
25 |
26 | Seeds
27 | =====
28 |
29 | A set of 50 seed circles with small radius is initially created.
30 | Calling the :func:`~microstructpy.seeding.SeedList.position` method
31 | positions the points according to random uniform distributions in the domain.
32 |
33 | Polygon Mesh
34 | ============
35 |
36 | A polygon mesh is created from the list of seed points using the
37 | :func:`~microstructpy.meshing.PolyMesh.from_seeds` class method.
38 | The mesh is plotted and saved into a PNG file in the remaining lines of the
39 | script.
40 |
41 | Plotting
42 | ========
43 |
44 | The output Voronoi diagram is plotted in :numref:`f_ex_voro`.
45 |
46 | .. _f_ex_voro:
47 | .. figure:: ../../../../src/microstructpy/examples/standard_voronoi/voronoi_diagram.png
48 |
49 | Standard Voronoi diagram.
50 |
--------------------------------------------------------------------------------
/docs/source/examples/package/uniform_seeding.rst:
--------------------------------------------------------------------------------
1 | .. _ex_uni_seed:
2 |
3 | ===============================
4 | Uniform Seeding Voronoi Diagram
5 | ===============================
6 |
7 | Python Script
8 | =============
9 |
10 | The basename for this file is ``uniform_seeding.py``.
11 | The file can be run using this command::
12 |
13 | microstructpy --demo=uniform_seeding.py
14 |
15 | The full text of the script is:
16 |
17 | .. literalinclude:: ../../../../src/microstructpy/examples/uniform_seeding.py
18 | :language: python
19 |
20 | Domain
21 | ======
22 |
23 | The domain of the microstructure is a :class:`.Square`.
24 | Without arguments, the square's center is (0, 0) and side length is 1.
25 |
26 | Seeds
27 | =====
28 |
29 | A set of 200 seed circles with small radius is initially created.
30 | The positions of the seeds are set with Mitchell's Best Candidate Algorithm
31 | [#f1]_. This algorithm positions seed *i* by sampling *i + 1*
32 | random points and picking the one that is furthest from its nearest neighbor.
33 |
34 | Polygon Mesh
35 | ============
36 |
37 | A polygon mesh is created from the list of seed points using the
38 | :func:`~microstructpy.meshing.PolyMesh.from_seeds` class method.
39 |
40 | Plotting
41 | ========
42 |
43 | The facecolor of each polygon is determined by its area. If it is below the
44 | standard area (domain area / number of cells), then it is shaded blue. If
45 | it is above the standard area, it is shaded red. A custom colorbar is added
46 | to the figure and it is saved as a PNG, shown in :numref:`f_ex_uni_voro`.
47 |
48 | .. _f_ex_uni_voro:
49 | .. figure:: ../../../../src/microstructpy/examples/uniform_seeding/voronoi_diagram.png
50 | :alt: Voronoi diagram with uniformly-spaced seeds, colored by area.
51 |
52 | Uniformly seeded Voronoi diagram with cells colored by area.
53 |
54 |
55 | .. [#f1] Mitchell, T.J., "An Algorithm for the Construction of "D-Optimal"
56 | Experimental Designs," Technometrics, Vol. 16, No. 2, May 1974, pp. 203-210.
57 | (https://www.jstor.org/stable/1267940)
58 |
--------------------------------------------------------------------------------
/docs/source/getting_started.rst:
--------------------------------------------------------------------------------
1 | .. _getting_started:
2 |
3 | Getting Started
4 | ===============
5 |
6 | Download & Installation
7 | -----------------------
8 |
9 | To install MicroStructPy, download it from PyPI using::
10 |
11 | pip install microstructpy
12 |
13 | This installs both the ``microstructpy`` Python package and the
14 | ``microstructpy`` command line interface (CLI).
15 | If there is an error with the install, try to install ``pybind11`` first.
16 | You may need to add the ``--user`` flag, depending on your permissions.
17 |
18 | To verify installation of the package, run the following commands::
19 |
20 | python -c 'import microstructpy'
21 | microstructpy --help
22 |
23 | This verifies that 1) the python package has installed correctly and 2) the
24 | command line interface (CLI) has been found by the shell.
25 | If there is an issue with the CLI, the install location may not be in the
26 | PATH variable.
27 | The most likely install location is ``~/.local/bin`` for Mac or Linux machines.
28 | For Windows, it may be in a path similar to
29 | ``~\AppData\Roaming\Python\Python36\Scripts\``.
30 |
31 | .. note::
32 | If the install fails and the last several error messages reference
33 | ``pybind11``, run ``pip install pybind11`` first then install MicroStructPy.
34 |
35 | Running Demonstrations
36 | ----------------------
37 |
38 | MicroStructPy comes with several demonstrations to familiarize users with its
39 | capabilities and options.
40 | A demonstration can be run from the command line by::
41 |
42 | microstructpy --demo=minimal.xml
43 |
44 | When a demo is run, the XML input file is copied to the current working
45 | directory.
46 | See :ref:`examples_page` for a full list of available examples and
47 | demostrations.
48 |
49 |
50 | Development
51 | -----------
52 |
53 | Contributions to MicroStructPy are most welcome.
54 | To download and install the source code for the project::
55 |
56 | git clone https://github.com/kip-hart/MicroStructPy.git
57 | pip install -e MicroStructPy
58 |
59 | MicroStructPy uses tox_ to run tests and build the documentation.
60 | To perform these tests::
61 |
62 | pip install tox
63 | cd MicroStructPy
64 | tox
65 |
66 | Please use the issue and pull request features of the `GitHub repository`_
67 | to report bugs and modify the code.
68 |
69 |
70 |
71 |
72 | .. _`GitHub repository`: https://github.com/kip-hart/MicroStructPy
73 | .. _tox: https://tox.readthedocs.io
74 |
--------------------------------------------------------------------------------
/docs/source/index.rst:
--------------------------------------------------------------------------------
1 | .. MicroStructPy documentation master file.
2 |
3 | .. include:: ../../README.rst
4 | :end-before: end-badges
5 |
6 | .. include:: welcome.rst
7 | :start-after: index-start
8 |
9 | .. toctree::
10 | :hidden:
11 | :maxdepth: 2
12 |
13 | getting_started
14 | examples/index
15 | cli/index
16 | package_guide
17 | file_formats
18 | api/index
19 | troubleshooting
20 | changelog
21 |
22 |
23 | .. external images and shields
24 |
25 | .. include:: ../../README.rst
26 | :start-after: external-images
27 |
--------------------------------------------------------------------------------
/docs/source/sphinx_gallery/README.rst:
--------------------------------------------------------------------------------
1 | :orphan:
2 |
3 | Sphinx Gallery
4 | ==============
5 |
--------------------------------------------------------------------------------
/docs/source/sphinx_gallery/geometry/README.rst:
--------------------------------------------------------------------------------
1 | :orphan:
2 |
3 | Sphinx Gallery
4 | ==============
5 |
--------------------------------------------------------------------------------
/docs/source/sphinx_gallery/geometry/plot_ellipse.py:
--------------------------------------------------------------------------------
1 | """
2 | Plot figures relevant to :class:`microstructpy.geometry.Ellipse`
3 |
4 | """
5 |
6 | import matplotlib.pyplot as plt
7 | import numpy as np
8 | from matplotlib import collections
9 | from matplotlib.ticker import FormatStrFormatter
10 |
11 | import microstructpy as msp
12 |
13 |
14 | def main():
15 | breakdown() # ellipse_001.png - ellipse breakdown
16 |
17 |
18 | def breakdown():
19 | a = 3
20 | b = 1
21 | x1 = 0.7
22 |
23 | fig = plt.figure(figsize=(14, 6))
24 | ellipse = msp.geometry.Ellipse(a=a, b=b)
25 | approx = ellipse.approximate(x1)
26 | ellipse.plot(edgecolor='k', facecolor='none', lw=3)
27 | t = np.linspace(0, 2 * np.pi)
28 | for x, y, r in approx:
29 | plt.plot(x + r * np.cos(t), y + r * np.sin(t), 'b')
30 |
31 | xticks = np.unique(np.concatenate((approx[:, 0], (-a, a))))
32 | plt.xticks(xticks)
33 | plt.yticks(np.unique(np.concatenate((approx[:, 1], (-b, b)))))
34 | plt.gca().set_xticklabels([str(round(float(label), 1)) for label in xticks])
35 | plt.axis('scaled')
36 | plt.grid(True, linestyle=':')
37 | plt.tight_layout()
38 |
39 |
40 | if __name__ == '__main__':
41 | plt.rc('savefig', dpi=300, pad_inches=0)
42 | main()
--------------------------------------------------------------------------------
/docs/source/sphinx_gallery/geometry/plot_rectangle.py:
--------------------------------------------------------------------------------
1 | """
2 | Plot figures relevant to :class:`microstructpy.geometry.Rectangle`
3 |
4 | """
5 |
6 | import matplotlib.pyplot as plt
7 | import numpy as np
8 | from matplotlib import collections
9 |
10 | import microstructpy as msp
11 |
12 | def main():
13 | # Plot breakdown
14 | breakdown(2.5, 1, 0.3, (9, 4)) # rectangle_001.png - rect breakdown
15 | breakdown(1, 1, 0.2, (4, 4)) # rectangle_001.png - square breakdown
16 |
17 |
18 | def breakdown(length, width, x1, figsize):
19 | r = msp.geometry.Rectangle(length=length, width=width)
20 | approx = r.approximate(x1=x1)
21 |
22 | # Plot rectangle
23 | fig = plt.figure(figsize=figsize)
24 | r.plot(edgecolor='k', facecolor='none', lw=3)
25 |
26 | # Plot breakdown
27 | t = np.linspace(0, 2 * np.pi)
28 | xp = np.cos(t)
29 | yp = np.sin(t)
30 | for x, y, radius in approx:
31 | plt.plot(x + radius * xp, y + radius * yp, 'b')
32 |
33 | # Format Axes
34 | xtick = np.unique([circ[0] for circ in approx])
35 | ytick = np.unique([circ[1] for circ in approx])
36 | plt.xticks(xtick)
37 | plt.yticks(ytick)
38 |
39 | plt.axis('scaled')
40 | plt.grid(True, linestyle=':')
41 | plt.tight_layout()
42 |
43 |
44 | if __name__ == '__main__':
45 | plt.rc('savefig', dpi=300, pad_inches=0)
46 | main()
--------------------------------------------------------------------------------
/docs/source/sphinx_gallery/plot_demos.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | r"""
3 | Plot all demos
4 |
5 | """
6 |
7 | import glob
8 | import locale
9 | import os
10 | import shutil
11 | import subprocess
12 |
13 | import matplotlib.pyplot as plt
14 | import microstructpy as msp
15 |
16 | locale.setlocale(locale.LC_NUMERIC, "C")
17 |
18 | example_dir = '../../../src/microstructpy/examples'
19 |
20 | welcome_fnames = ['intro_2_quality/trimesh.png',
21 | 'minimal/polymesh.png',
22 | 'basalt_circle/trimesh.png',
23 | 'foam/trimesh.png',
24 | 'two_phase_3D/trimesh.png',
25 | 'colormap/trimesh.png']
26 |
27 | def main():
28 | # Copy Supporting Files
29 | supporting_files = ['aphanitic_cdf.csv', 'olivine_cdf.csv']
30 | for fname in supporting_files:
31 | filename = os.path.join(example_dir, fname)
32 | shutil.copy(filename, '.')
33 |
34 | # Run XML files
35 | xml_pattern = os.path.join(example_dir, '*.xml')
36 | for filename in glob.glob(xml_pattern):
37 | msp.cli.run_file(filename)
38 |
39 | # Run Python Scripts
40 | py_pattern = os.path.join(example_dir, '*.py')
41 | for filename in glob.glob(py_pattern):
42 | subprocess.call(['python', filename])
43 |
44 | # Remove Supporting Files
45 | for fname in supporting_files:
46 | os.remove(fname)
47 |
48 | # Create welcome figure
49 | create_welcome()
50 |
51 | # Create example subfigures
52 | seed_poly_tri('.')
53 |
54 |
55 | def create_welcome():
56 | fig, axes = plt.subplots(2, 3, figsize=(21, 15))
57 | plt.subplots_adjust(wspace=0.05, hspace=0)
58 | for i, fname in enumerate(welcome_fnames):
59 | filename = os.path.join(example_dir, fname)
60 | im = plt.imread(filename)
61 |
62 | row_num = int(i / 3)
63 | col_num = i % 3
64 | ax = axes[row_num, col_num]
65 | ax.imshow(im)
66 |
67 | ax.set_axis_off()
68 | ax.get_xaxis().set_visible(False)
69 | ax.get_yaxis().set_visible(False)
70 |
71 | sub_fname = 'welcome_examples.png'
72 | sub_filename = os.path.join(example_dir, sub_fname)
73 | plt.tight_layout()
74 | plt.savefig(sub_filename, pad_inches=0, dpi=200)
75 | plt.close('all')
76 |
77 |
78 | def seed_poly_tri(filepath):
79 | basenames = ['seeds.png', 'polymesh.png', 'trimesh.png']
80 | ex_path = os.path.join(example_dir, filepath)
81 | fig, axes = plt.subplots(1, 3, figsize=(20, 10))
82 | plt.subplots_adjust(wspace=0.05, hspace=0)
83 | for i, fname in enumerate(basenames):
84 | filename = os.path.join(ex_path, fname)
85 | im = plt.imread(filename)
86 |
87 | ax = axes[i]
88 | ax.imshow(im)
89 |
90 | ax.set_axis_off()
91 | ax.get_xaxis().set_visible(False)
92 | ax.get_yaxis().set_visible(False)
93 |
94 | sub_fname = 'joined.png'
95 | sub_filename = os.path.join(ex_path, sub_fname)
96 | plt.tight_layout()
97 | plt.savefig(sub_filename, pad_inches=0, dpi=300)
98 | plt.close('all')
99 |
100 |
101 | if __name__ == '__main__':
102 | main()
103 |
104 |
105 |
106 |
--------------------------------------------------------------------------------
/docs/source/troubleshooting.rst:
--------------------------------------------------------------------------------
1 | .. _troubleshooting:
2 |
3 | Troubleshooting
4 | ==============================================================================
5 |
6 | This page addresses some problems that may be encountered with MicroStructPy.
7 | If this page does not address your problem, please submit an issue through the
8 | package GitHub_ page.
9 |
10 | .. _GitHub: https://github.com/kip-hart/MicroStructPy
11 |
12 | Installation
13 | ------------------------------------------------------------------------------
14 |
15 | These are problems encountered when installing MicroStructPy.
16 |
17 | Missing library for pygmsh on Linux
18 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
19 | **Problem Description**
20 |
21 | When running MicroStructPy for the first time on a Linux operating system,
22 | there is an error message like::
23 |
24 | ...
25 | src/microstructpy/meshing/trimesh.py:19: in
26 | import pygmsh as pg
27 | /opt/hostedtoolcache/Python/3.7.9/x64/lib/python3.7/site-packages/pygmsh/__init__.py:1: in
28 | from . import geo, occ
29 | /opt/hostedtoolcache/Python/3.7.9/x64/lib/python3.7/site-packages/pygmsh/geo/__init__.py:1: in
30 | from .geometry import Geometry
31 | /opt/hostedtoolcache/Python/3.7.9/x64/lib/python3.7/site-packages/pygmsh/geo/geometry.py:1: in
32 | import gmsh
33 | /opt/hostedtoolcache/Python/3.7.9/x64/lib/python3.7/site-packages/gmsh-4.6.0-Linux64-sdk/lib/gmsh.py:39: in
34 | lib = CDLL(libpath)
35 | /opt/hostedtoolcache/Python/3.7.9/x64/lib/python3.7/ctypes/__init__.py:364: in __init__
36 | self._handle = _dlopen(self._name, mode)
37 | E OSError: libGLU.so.1: cannot open shared object file: No such file or directory
38 |
39 |
40 | **Problem Solution**
41 |
42 | The libGLU library is misssing from the computer. To add it, run::
43 |
44 | sudo apt-get install libglu1
45 |
46 |
47 | MeshPy fails to install
48 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
49 | **Problem Description**
50 |
51 | When installing the package, either through PyPI as
52 | ``pip install microstructpy`` or from the source as ``pip install -e .`` in
53 | the top-level directory, an error message appears during the meshpy install.
54 | The error message indicates that Visual Studio cannot find the pybind11
55 | headers.
56 |
57 | **Problem Solution**
58 |
59 | Install pybind11 first by running ``pip install pybind11``, then try to
60 | install MicroStructPy.
61 |
62 | Command Line Interface
63 | ------------------------------------------------------------------------------
64 |
65 | These are problems encountered when running ``microstructpy input_file.xml``.
66 |
67 | Command not found on Linux
68 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
69 |
70 | **Problem Description**
71 |
72 | The MicroStructPy package installs without a problem, however on running
73 | ``microstructpy example_file.xml`` the following message appears::
74 |
75 | microstructpy: command not found
76 |
77 | **Problem Solution**
78 |
79 | The command line interface (CLI) is install to a directory that is not in
80 | the PATH variable. Check for the CLI in ``~/.local/bin`` and if it is there,
81 | add the following to your ``~/.bash_profile`` file::
82 |
83 | export PATH=$PATH:~/.local/bin
84 |
85 | then source the .bash_profile file by running ``source ~/.bash_profile``.
86 |
87 | 'tkinter' not found on Linux
88 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
89 |
90 | **Problem Description**
91 |
92 | The MicroStructPy package installs without a problem, however on running
93 | ``microstructpy example_file.xml`` the following error is raised::
94 |
95 | ModuleNotFoundError: No module named 'tkinter'
96 |
97 | **Problem Solution**
98 |
99 | To install ``tkinter`` for Python 3 on Linux, run the following command::
100 |
101 | sudo apt-get install python3-tk
102 |
103 | For Python 2, run the following instead::
104 |
105 | sudo apt-get install python-tk
106 |
107 | Program quits/segfaults while calculating Voronoi diagram
108 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
109 |
110 | **Problem Description**
111 |
112 | During the calculating Voronoi diagram step, the program either quits or
113 | segfaults.
114 |
115 | **Problem Solution**
116 |
117 | This issue was experienced while running 32-bit Python with a large number of
118 | seeds. Python ran out of memory addresses and segfaulted. Switching from 32-bit
119 | to 64-bit Python solved the problem.
120 |
--------------------------------------------------------------------------------
/docs/source/welcome.rst:
--------------------------------------------------------------------------------
1 | :orphan:
2 |
3 | Welcome
4 | =======
5 |
6 | Summary
7 | -------
8 |
9 | .. index-start
10 |
11 | MicroStructPy is a microstructure mesh generator written in Python.
12 | Features of MicroStructPy include:
13 |
14 | * 2D and 3D microstructures
15 | * Grain size, shape, orientation, and position control
16 | * Polycrystals, amorphous phases, and voids
17 | * Mesh verification
18 | * Visualizations
19 | * Output to common file formats
20 | * Customizable workflow
21 |
22 | .. figure:: ../../src/microstructpy/examples/docs_banner/banner.png
23 | :alt: Banner image showing the three steps for creating microstructure.
24 |
25 | The primary steps to create a microstructure.
26 | 1) seed the domain with particles,
27 | 2) create a Voronoi power diagram, and
28 | 3) convert the diagram into an unstructured mesh.
29 |
30 |
31 | Examples
32 | --------
33 |
34 | These images were created using MicroStructPy.
35 | For more examples, see the :ref:`examples_page` section.
36 |
37 | .. figure:: ../../src/microstructpy/examples/welcome_examples.png
38 | :alt: Several examples created using MicroStructPy.
39 |
40 | Examples created using MicroStructPy.
41 |
42 |
43 | Quick Start
44 | -----------
45 |
46 | To install MicroStructPy, download it from PyPI using::
47 |
48 | pip install microstructpy
49 |
50 | If there is an error with the install, try ``pip install pybind11`` first,
51 | then install MicroStructPy.
52 | This will create a command line executable and python package both
53 | named ``microstructpy``.
54 | To use the command line interface, create a file called ``input.xml`` and copy
55 | this into it:
56 |
57 | .. literalinclude:: ../../src/microstructpy/examples/minimal.xml
58 | :language: xml
59 |
60 | Next, run the file from the command line::
61 |
62 | microstructpy input.xml
63 |
64 | This will produce three text files and three image files: ``seeds.txt``,
65 | ``polymesh.txt``, ``trimesh.txt``, ``seeds.png``, ``polymesh.png``, and
66 | ``trimesh.png``.
67 | The text files contain all of the data related to the seed geometries and
68 | meshes.
69 | The image files contain:
70 |
71 | .. figure:: ../../src/microstructpy/examples/joined.png
72 | :alt: Seed geometries, polygonal mesh, and unstructured mesh for min. expl.
73 |
74 | The output plots are:
75 | 1) seed geometries, 2) polygonal mesh, and 3) triangular mesh.
76 |
77 |
78 | The same results can be produced using this script:
79 |
80 | .. code-block:: python
81 |
82 | import matplotlib.pyplot as plt
83 | import microstructpy as msp
84 |
85 |
86 | phase = {'shape': 'circle', 'size': 0.15}
87 | domain = msp.geometry.Square()
88 |
89 | # Unpositioned list of seeds
90 | seeds = msp.seeding.SeedList.from_info(phase, domain.area)
91 |
92 | # Position seeds in domain
93 | seeds.position(domain)
94 |
95 | # Create polygonal mesh
96 | polygon_mesh = msp.meshing.PolyMesh.from_seeds(seeds, domain)
97 |
98 | # Create triangular mesh
99 | triangle_mesh = msp.meshing.TriMesh.from_polymesh(polygon_mesh)
100 |
101 | # Plot outputs
102 | for output in [seeds, polygon_mesh, triangle_mesh]:
103 | plt.figure()
104 | output.plot(edgecolor='k')
105 | plt.axis('image')
106 | plt.axis([-0.5, 0.5, -0.5, 0.5])
107 | plt.show()
108 |
109 |
110 | .. include:: ../../README.rst
111 | :start-after: begin-publications
112 | :end-before: end-publications
113 |
114 |
115 | License and Attribution
116 | -----------------------
117 |
118 | MicroStructPy is open source and freely available.
119 | Copyright for MicroStructPy is held by Georgia Tech Research Corporation.
120 | MicroStructPy is a major part of Kenneth (Kip) Hart's doctoral thesis,
121 | advised by Prof. Julian Rimoli.
122 |
123 | .. only:: latex
124 |
125 | .. topic:: License
126 |
127 | .. include:: ../../LICENSE.rst
128 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | aabbtree==2.5.0
2 | matplotlib>=3.7.3
3 | pybind11==2.4.3
4 | pygmsh==7.1.17
5 | MeshPy==2022.1.3
6 | numpy>=1.24.4,<2.0
7 | pyquaternion==0.9.5
8 | pyvoro-mmalahe==1.3.4
9 | scipy>=1.10.1
10 | setuptools>=70.0.0
11 | xmltodict==0.12.0
12 | tox==3.14.0
13 | lsq-ellipse==2.0.1
14 | zipp>=3.19.1 # not directly required, pinned by Snyk to avoid a vulnerability
15 |
--------------------------------------------------------------------------------
/setup.cfg:
--------------------------------------------------------------------------------
1 | [bdist_wheel]
2 | universal = 1
3 |
4 | [tool:pytest]
5 | testpaths = tests
6 |
7 | python_files =
8 | test_*.py
9 | *_test.py
10 | tests.py
11 |
12 | addopts =
13 | -ra
14 | --strict
15 | --doctest-modules
16 | --doctest-glob=\*.rst
17 | --tb=short
18 |
19 | [isort]
20 | force_single_line = True
21 | line_length = 120
22 | known_first_party = microstructpy
23 | default_section = THIRDPARTY
24 | forced_separate = test_cli
25 |
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- encoding: utf-8 -*-
3 | from __future__ import absolute_import
4 | from __future__ import print_function
5 |
6 | from glob import glob
7 | from os.path import basename
8 | from os.path import dirname
9 | from os.path import join
10 | from os.path import splitext
11 |
12 | from setuptools import find_packages
13 | from setuptools import setup
14 |
15 | desc = 'Microstructure modeling, mesh generation, analysis, and visualization.'
16 |
17 |
18 | def read(*fname):
19 | return open(join(dirname(__file__), *fname)).read()
20 |
21 |
22 | def find_version(*fname):
23 | ver_str = ''
24 | for line in read(*fname).split('\n'):
25 | if line.startswith('__version__') and '=' in line:
26 | ver_str = line.split('=')[-1].strip().strip('\"').strip('\'')
27 | break
28 | return ver_str
29 |
30 |
31 | setup(
32 | name='microstructpy',
33 | version=find_version('src', 'microstructpy', '__init__.py'),
34 | license='MIT License',
35 | description=desc,
36 | long_description=read('README.rst'),
37 | long_description_content_type=' text/x-rst',
38 | author='Kenneth (Kip) Hart',
39 | author_email='kiphart91@gmail.com',
40 | url='https://github.com/kip-hart/MicroStructPy',
41 | project_urls={
42 | 'Documentation': 'https://docs.microstructpy.org',
43 | },
44 | packages=find_packages('src'),
45 | package_dir={'': 'src'},
46 | py_modules=[splitext(basename(path))[0] for path in glob('src/*.py')],
47 | package_data={'': ['src/microstructpy/examples/*.{csv,py,xml}',
48 | 'src/microstructpy/examples/aluminum_micro.png']},
49 | include_package_data=True,
50 | zip_safe=False,
51 | classifiers=[
52 | # complete classifier list:
53 | # http://pypi.python.org/pypi?%3Aaction=list_classifiers
54 | 'Development Status :: 5 - Production/Stable',
55 | 'Intended Audience :: Science/Research',
56 | 'License :: OSI Approved :: MIT License',
57 | 'Operating System :: MacOS :: MacOS X',
58 | 'Operating System :: Microsoft :: Windows',
59 | 'Operating System :: POSIX :: Linux',
60 | 'Programming Language :: Python :: 3.9',
61 | 'Programming Language :: Python :: 3.10',
62 | 'Programming Language :: Python :: 3.11',
63 | 'Programming Language :: Python :: 3.12',
64 | 'Topic :: Scientific/Engineering',
65 | 'Topic :: Scientific/Engineering :: Mathematics',
66 | 'Topic :: Scientific/Engineering :: Physics'
67 | ],
68 | keywords=[
69 | 'microstructure',
70 | 'micromechanics',
71 | 'finite element',
72 | 'FEM', 'FEA',
73 | 'mesh',
74 | 'polycrystal',
75 | 'tessellation',
76 | 'Laguerre tessellation',
77 | 'multi-sphere'
78 | ],
79 | install_requires=[
80 | 'aabbtree>=2.5.0',
81 | 'pybind11', # must come before meshpy for successful install
82 | 'lsq-ellipse',
83 | 'matplotlib>=3.4.0',
84 | 'meshpy>=2018.2.1',
85 | 'numpy>=1.22.2',
86 | 'pygmsh>=7.0.2',
87 | 'pyquaternion',
88 | 'pyvoro-mmalahe>=1.3.4', # install issue with pyvoro
89 | 'scipy',
90 | 'xmltodict'
91 | ],
92 | entry_points={
93 | 'console_scripts': [
94 | 'microstructpy = microstructpy.cli:main',
95 | ]
96 | },
97 | )
98 |
--------------------------------------------------------------------------------
/src/microstructpy/__init__.py:
--------------------------------------------------------------------------------
1 | import microstructpy.cli
2 | import microstructpy.geometry
3 | import microstructpy.meshing
4 | import microstructpy.seeding
5 | import microstructpy.verification
6 |
7 | __version__ = '1.5.9'
8 |
--------------------------------------------------------------------------------
/src/microstructpy/_misc.py:
--------------------------------------------------------------------------------
1 | """Miscellaneous functions
2 |
3 | This private module contains miscellaneous functions.
4 | """
5 |
6 | import ast
7 |
8 | import numpy as np
9 |
10 | __author__ = 'Kenneth (Kip) Hart'
11 |
12 | kw_solid = {'crystalline', 'granular', 'solid'}
13 | kw_amorph = {'amorphous', 'glass', 'matrix'}
14 | kw_void = {'void', 'crack', 'hole'}
15 |
16 | ori_kws = {'orientation', 'matrix', 'angle', 'angle_deg', 'angle_rad',
17 | 'rot_seq', 'rot_seq_rad', 'rot_seq_deg'}
18 | gen_kws = {'material_type', 'fraction', 'shape', 'name', 'color', 'position'}
19 |
20 | demo_needs = {'basalt_circle.xml': ['aphanitic_cdf.csv', 'olivine_cdf.csv'],
21 | 'from_image.py': ['aluminum_micro.png']}
22 |
23 | mpl_plural_kwargs = {'edgecolors', 'facecolors', 'linewidths', 'antialiaseds',
24 | 'offsets'}
25 | plt_3d_adj = {
26 | 'left': 0.4,
27 | 'right': 1,
28 | 'bottom': 0,
29 | 'top': 0.8,
30 | }
31 |
32 |
33 | # --------------------------------------------------------------------------- #
34 | # #
35 | # Convert String to Value (Infer Type) #
36 | # #
37 | # --------------------------------------------------------------------------- #
38 | def from_str(string):
39 | """ Convert string to number
40 |
41 | This function takes a string and converts it into a number or a list.
42 |
43 | Args:
44 | string (str): The string.
45 |
46 | Returns:
47 | The value in the string.
48 |
49 | """
50 | s = string.strip()
51 | try:
52 | val = ast.literal_eval(s)
53 | except (ValueError, SyntaxError):
54 | if 'true' in s.lower():
55 | tmp_s = s.lower().replace('true', 'True')
56 | tmp_val = from_str(tmp_s)
57 | if tmp_val != tmp_s:
58 | val = tmp_val
59 | else:
60 | val = s
61 | elif 'false' in s.lower():
62 | tmp_s = s.lower().replace('false', 'False')
63 | tmp_val = from_str(tmp_s)
64 | if tmp_val != tmp_s:
65 | val = tmp_val
66 | else:
67 | val = s
68 | else:
69 | val = s
70 | return val
71 |
72 |
73 | # --------------------------------------------------------------------------- #
74 | # #
75 | # Tangent Spheres #
76 | # #
77 | # --------------------------------------------------------------------------- #
78 | def tangent_sphere(points, radii=None, simplices=None):
79 | """Calculate center and radius of tangent sphere(s)
80 |
81 | This function computes the center and radius of an n-dimensional sphere
82 | that is tangent to (n+1) spheres. For example, in 2D this function
83 | computes the center and radius of a circle tangent to three other circles.
84 |
85 | The operation of this function can be vectorized using the ``simplices``
86 | input. The simplices should be an Mx(n+1) list of indices of the points.
87 | The result is an Mx(n+1) numpy array, where the first n columns are the
88 | coordinates of the sphere center. The final column is the radius of the
89 | sphere.
90 |
91 | If no radii are specified, the results are circumspheres of the simplices
92 | (circumcircles in 2D).
93 |
94 | Radii at each point can be speficied. If no radii are given, then the
95 | results are circumspheres of the simplices (circumcircles in 2D).
96 |
97 | Args:
98 | points (list, tuple, numpy.ndarray): List of points.
99 | radii (list, tuple, numpy.ndarray): List of radii. *(optional)*
100 | simplices (list, tuple, numpy.ndarray): List of simplices. *(optional)*
101 |
102 | Returns:
103 | numpy.ndarray: The centers and radii of tangent spheres.
104 |
105 | """
106 | # set radii
107 | if radii is None:
108 | radii = np.full(len(points), 0)
109 |
110 | # extract points
111 | if simplices is None:
112 | simplices = np.arange(len(points)).reshape(1, -1)
113 |
114 | pts = np.array(points)[simplices]
115 | rs = np.array(radii)[simplices]
116 |
117 | # define circle distances
118 | cs = np.sum(pts * pts, axis=-1) - rs * rs
119 |
120 | # matrix and vector quantities
121 | pos1 = pts[:, 0]
122 | r1 = rs[:, 0]
123 | A = pts[:, 1:] - pos1[:, np.newaxis, :]
124 | b = -1 * (rs[:, 1:] - r1[:, np.newaxis])
125 | c = 0.5 * (cs[:, 1:] - cs[:, 0, np.newaxis])
126 |
127 | # linear system coefficients
128 | alpha = np.linalg.solve(A, b)
129 | beta = np.linalg.solve(A, c)
130 |
131 | # quadratic equation in rc
132 | r_beta = beta - pos1
133 | C1 = np.sum(alpha * alpha, axis=-1) - 1
134 | C2 = np.sum(r_beta * alpha, axis=-1) - r1
135 | C3 = np.sum(r_beta * r_beta, axis=-1) - r1 * r1
136 |
137 | # solve for rc
138 | discr = C2 * C2 - C1 * C3
139 | rt_discr = np.sqrt(discr)
140 | rt_discr[discr < 0] = 0
141 |
142 | rc1 = (-C2 + rt_discr) / C1
143 | rc2 = (-C2 - rt_discr) / C1
144 |
145 | mask = np.abs(rc1) < np.abs(rc2)
146 | rc = rc2
147 | rc[mask] = rc1[mask]
148 | rc[discr < 0] = 0
149 |
150 | # solve for center position
151 | posc = alpha * rc[:, np.newaxis] + beta
152 |
153 | # return results
154 | spheres = np.hstack((posc, rc.reshape(-1, 1)))
155 | return np.squeeze(spheres)
156 |
157 |
158 | def axisEqual3D(ax):
159 | ax.set_aspect('equal')
160 |
161 |
162 | def ax_objects(ax):
163 | n = 0
164 | for att in ['collections', 'images', 'lines', 'patches', 'texts']:
165 | n += len(getattr(ax, att))
166 | return n
167 |
--------------------------------------------------------------------------------
/src/microstructpy/examples/.gitignore:
--------------------------------------------------------------------------------
1 | */*
2 | *.txt
3 | *.png
4 | !aluminum_micro.png
5 | from_image/aluminum_micro.png
6 |
--------------------------------------------------------------------------------
/src/microstructpy/examples/aluminum_micro.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kip-hart/MicroStructPy/59f6bb14de2364f943943ec327b5014c1f5bb81d/src/microstructpy/examples/aluminum_micro.png
--------------------------------------------------------------------------------
/src/microstructpy/examples/aphanitic_cdf.csv:
--------------------------------------------------------------------------------
1 | 0.0131329,0.01533213559176235
2 | 0.0244043,0.052366065866209975
3 | 0.0378734,0.10664028994219119
4 | 0.0524219,0.16912000096172966
5 | 0.0658667,0.22292200530737463
6 | 0.078159,0.270757219379418
7 | 0.0882121,0.31252632948214387
8 | 0.102668,0.35461605029964904
9 | 0.114868,0.40079860122375904
10 | 0.130442,0.44146381748575336
11 | 0.143858,0.4682199164619496
12 | 0.156045,0.4963700404401114
13 | 0.168257,0.5226454904629255
14 | 0.17936,0.5468300134050428
15 | 0.193731,0.5746462325954049
16 | 0.207044,0.600186102906063
17 | 0.220469,0.6147083337501832
18 | 0.232676,0.6276799922488674
19 | 0.247096,0.6392477153562951
20 | 0.2712,0.671419103088213
21 | 0.282213,0.7115650573599237
22 | 0.295636,0.7335215361206971
23 | 0.308959,0.7516200656859109
24 | 0.31891,0.7701590164868207
25 | 0.333254,0.7917551921790197
26 | 0.346618,0.8065154544827832
27 | 0.358667,0.8305986992703492
28 | 0.372182,0.8392944450621487
29 | 0.384077,0.8660193175326374
30 | 0.397254,0.9053530877053354
31 | 0.408645,0.9151403067362659
32 | 0.423006,0.9254603215782193
33 | 0.460577,0.9365599254365803
34 | 0.472521,0.9639040536949486
35 | 0.511517,0.9714442205219028
36 | 0.560104,0.9804858511663381
37 | 0.596389,0.9999999999999998
--------------------------------------------------------------------------------
/src/microstructpy/examples/basalt_circle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Plagioclase
5 |
6 | norm
7 | 45.2
8 | 0.2
9 |
10 |
11 | cdf
12 | aphanitic_cdf.csv
13 |
14 | #BDBDBD
15 |
16 |
17 |
18 | Olivine
19 | ellipse
20 |
21 | norm
22 | 19.1
23 | 0.2
24 |
25 |
26 | cdf
27 | olivine_cdf.csv
28 |
29 |
30 | uniform
31 | 1.0
32 | 2.0
33 |
34 |
35 | uniform
36 | -90
37 | 180
38 |
39 | #99BA73
40 |
41 |
42 |
43 | Diopside
44 |
45 | norm
46 | 13.2
47 | 0.2
48 |
49 |
50 | cdf
51 | aphanitic_cdf.csv
52 |
53 | #709642
54 |
55 |
56 |
57 | Hypersthene
58 |
59 | norm
60 | 16.6
61 | 0.2
62 |
63 |
64 | cdf
65 | aphanitic_cdf.csv
66 |
67 | #876E59
68 |
69 |
70 |
71 | Magnetite
72 |
73 | norm
74 | 3.35
75 | 0.2
76 |
77 |
78 | cdf
79 | aphanitic_cdf.csv
80 |
81 | #6E6E6E
82 |
83 |
84 |
85 | Chromite
86 |
87 | norm
88 | 0.65
89 | 0.2
90 |
91 |
92 | cdf
93 | aphanitic_cdf.csv \
94 |
95 | #545454
96 |
97 |
98 |
99 | Ilmenite
100 |
101 | norm
102 | 0.65
103 | 0.2
104 |
105 |
106 | cdf
107 | aphanitic_cdf.csv
108 |
109 | #6B6B6B
110 |
111 |
112 |
113 | Apatite
114 |
115 | norm
116 | 3.35
117 | 0.2
118 |
119 |
120 |
121 | cdf
122 | aphanitic_cdf.csv
123 |
124 | #ABA687
125 |
126 |
127 |
128 | circle
129 | 10
130 |
131 |
132 |
133 | basalt_circle
134 |
135 | png
136 | png
137 | png
138 | png
139 |
140 |
141 | False
142 | True
143 | True
144 |
145 | 0.01
146 | 20
147 | 0.05
148 |
149 |
150 | 0.2
151 |
152 |
153 | 0.2
154 |
155 |
156 | 0.1
157 |
158 |
159 |
160 |
--------------------------------------------------------------------------------
/src/microstructpy/examples/colormap.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | sphere
5 |
6 | uniform
7 | 1
8 | 2
9 |
10 |
11 |
12 |
13 | cube
14 | 15
15 |
16 |
17 |
18 | colormap
19 | 15
20 | seed number
21 | RdYlBu
22 |
23 |
--------------------------------------------------------------------------------
/src/microstructpy/examples/docs_banner.py:
--------------------------------------------------------------------------------
1 | from __future__ import division
2 |
3 | import os
4 |
5 | import numpy as np
6 | import scipy.stats
7 | from matplotlib import pyplot as plt
8 |
9 | import microstructpy as msp
10 |
11 |
12 | def main():
13 | # Colors
14 | c1 = '#12C2E9'
15 | c2 = '#C471ED'
16 | c3 = '#F64F59'
17 |
18 | # Offset
19 | off = 1
20 |
21 | # Create Directory
22 | dirname = os.path.join(os.path.dirname(__file__), 'docs_banner')
23 | if not os.path.exists(dirname):
24 | os.makedirs(dirname)
25 |
26 | # Create Domain
27 | domain = msp.geometry.Rectangle(width=10, length=20)
28 |
29 | # Create Unpositioned Seeds
30 | phase2 = {'color': c1}
31 | ell_geom = msp.geometry.Ellipse(a=8, b=3)
32 | ell_seed = msp.seeding.Seed(ell_geom, phase=2)
33 |
34 | mu = 1
35 | bnd = 0.5
36 | d_dist = scipy.stats.uniform(loc=mu-bnd, scale=2*bnd)
37 | phase0 = {'color': c2, 'shape': 'circle', 'd': d_dist}
38 | phase1 = {'color': c3, 'shape': 'circle', 'd': d_dist}
39 | circle_area = domain.area - ell_geom.area
40 | seeds = msp.seeding.SeedList.from_info([phase0, phase1], circle_area)
41 |
42 | seeds.append(ell_seed)
43 | hold = [False for seed in seeds]
44 | hold[-1] = True
45 | phases = [phase0, phase1, phase2]
46 |
47 | # Create Positioned Seeds
48 | seeds.position(domain, hold=hold, verbose=True)
49 |
50 | # Create Polygonal Mesh
51 | pmesh = msp.meshing.PolyMesh.from_seeds(seeds, domain)
52 |
53 | # Create Triangular Mesh
54 | tmesh = msp.meshing.TriMesh.from_polymesh(pmesh,
55 | min_angle=12,
56 | max_edge_length=0.2,
57 | max_volume=0.4)
58 |
59 | # Create Figure
60 | k = 0.12
61 | len_x = 3 * domain.length + 4 * off
62 | len_y = domain.width + 2 * off
63 | fig = plt.figure(figsize=(k * len_x, k * len_y))
64 |
65 | # Plot Seeds
66 | seed_colors = [phases[s.phase]['color'] for s in seeds]
67 | seeds.plot(color=seed_colors, alpha=0.8, edgecolor='k', linewidth=0.3)
68 | domain.plot(facecolor='none', edgecolor='k', linewidth=0.3)
69 |
70 | # Plot Polygonal Mesh
71 | pmesh.points = np.array(pmesh.points)
72 | pmesh.points[:, 0] += domain.length + off
73 | for region, phase_num in zip(pmesh.regions, pmesh.phase_numbers):
74 | if phase_num == 2:
75 | continue
76 | color = phases[phase_num]['color']
77 |
78 | facets = [pmesh.facets[f] for f in region]
79 | kps = ordered_kps(facets)
80 | x, y = zip(*[pmesh.points[kp] for kp in kps])
81 | plt.fill(x, y, color=color, alpha=0.8, edgecolor='none')
82 |
83 | ellipse_regions = set()
84 | for region_num, phase_num in enumerate(pmesh.phase_numbers):
85 | if phase_num == 2:
86 | ellipse_regions.add(region_num)
87 |
88 | ellipse_facets = []
89 | for facet, neighbors in zip(pmesh.facets, pmesh.facet_neighbors):
90 | common_regions = ellipse_regions & set(neighbors)
91 | if len(common_regions) == 1:
92 | ellipse_facets.append(facet)
93 | ellipse_kps = ordered_kps(ellipse_facets)
94 | x, y = zip(*[pmesh.points[kp] for kp in ellipse_kps])
95 | plt.fill(x, y, color=phases[-1]['color'], alpha=0.8, edgecolor='none')
96 |
97 | for facet, neighbors in zip(pmesh.facets, pmesh.facet_neighbors):
98 | common_regions = ellipse_regions & set(neighbors)
99 | if len(common_regions) < 2:
100 | x, y = zip(*[pmesh.points[kp] for kp in facet])
101 | plt.plot(x, y, color='k', linewidth=0.3)
102 |
103 | # Plot Triangular Mesh
104 | tmesh.points = np.array(tmesh.points)
105 | tmesh.points[:, 0] += 2 * off + 2 * domain.length
106 | tri_colors = [seed_colors[n] for n in tmesh.element_attributes]
107 | tmesh.plot(color=tri_colors, alpha=0.8, edgecolor='k', linewidth=0.2)
108 |
109 | # Set Up Axes
110 | plt.gca().set_position([0, 0, 1, 1])
111 | plt.axis('image')
112 | plt.gca().set_axis_off()
113 | plt.gca().get_xaxis().set_visible(False)
114 | plt.gca().get_yaxis().set_visible(False)
115 |
116 | xlim, ylim = domain.limits
117 | xlim[0] -= off
118 | xlim[1] += 3 * off + 2 * domain.length
119 |
120 | ylim[0] -= off
121 | ylim[1] += off
122 |
123 | plt.axis(list(xlim) + list(ylim))
124 |
125 | fname = os.path.join(dirname, 'banner.png')
126 | plt.savefig(fname, bbox_inches='tight', pad_inches=0)
127 | plt.savefig(fname.replace('.png', '.pdf'), bbox_inches='tight', pad_inches=0)
128 |
129 |
130 | def ordered_kps(pairs):
131 | t_pairs = [tuple(p) for p in pairs]
132 | kps = list(t_pairs.pop())
133 | while t_pairs:
134 | for i, pair in enumerate(t_pairs):
135 | if kps[-1] in pair:
136 | break
137 | assert kps[-1] in pair, pairs
138 | kps += [kp for kp in t_pairs.pop(i) if kp != kps[-1]]
139 | return kps[:-1]
140 |
141 |
142 | if __name__ == '__main__':
143 | main()
144 |
--------------------------------------------------------------------------------
/src/microstructpy/examples/elliptical_grains.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 2
5 | ellipse
6 |
7 | uniform
8 | 0.2
9 | 0.35
10 |
11 | 0.05
12 |
13 | uniform
14 | 0
15 | 20
16 |
17 | orange
18 |
19 |
20 |
21 | 1
22 | circle
23 |
24 | lognorm
25 | 0.004
26 | 1.0
27 |
28 | plum
29 |
30 |
31 |
32 | 1
33 | circle
34 |
35 | lognorm
36 | 0.004
37 | 1.0
38 |
39 | lightblue
40 |
41 |
42 |
43 | 1
44 | circle
45 |
46 | lognorm
47 | 0.004
48 | 1.0
49 |
50 | lightgreen
51 |
52 |
53 |
54 | 1
55 | circle
56 |
57 | lognorm
58 | 0.004
59 | 1.0
60 |
61 | khaki
62 |
63 |
64 |
65 | rectangle
66 | (2.4, 1.2)
67 |
68 |
69 |
70 | True
71 | 20
72 | 0.01
73 | 0.004
74 |
75 | elliptical_grains
76 | False
77 |
78 |
79 | 1.0
80 |
81 |
82 |
83 | 1.0
84 |
85 |
86 |
87 | 0.1
88 |
89 |
90 |
91 |
--------------------------------------------------------------------------------
/src/microstructpy/examples/foam.py:
--------------------------------------------------------------------------------
1 | import os
2 |
3 | import numpy as np
4 | import scipy.stats
5 | from matplotlib import pyplot as plt
6 |
7 | import microstructpy as msp
8 |
9 |
10 | def main():
11 | # Create Directory
12 | dirname = os.path.join(os.path.dirname(__file__), 'foam')
13 | if not os.path.exists(dirname):
14 | os.makedirs(dirname)
15 |
16 | # Define Domain
17 | domain = msp.geometry.Square(side_length=8)
18 |
19 | # Create Void Tessellation
20 | void_mat = {'material_type': 'void',
21 | 'shape': 'circle',
22 | 'size': scipy.stats.lognorm(scale=1, s=0.2)
23 | }
24 |
25 | void_a = 0.7 * domain.area
26 | void_seeds = msp.seeding.SeedList.from_info(void_mat, void_a)
27 | void_seeds.position(domain, rtol=0.03, verbose=True)
28 | void_tess = msp.meshing.PolyMesh.from_seeds(void_seeds, domain)
29 |
30 | # Add Foam
31 | foam_mat = {'material_type': 'amorphous',
32 | 'shape': 'circle',
33 | 'size': scipy.stats.lognorm(scale=0.15, s=0.1)
34 | }
35 |
36 | foam_a = 0.15 * domain.area
37 | foam_seeds = msp.seeding.SeedList.from_info(foam_mat, foam_a)
38 | inds = np.flip(np.argsort([s.volume for s in foam_seeds]))
39 | foam_seeds = foam_seeds[inds]
40 |
41 | bkdwns = np.array([s.breakdown[0] for s in foam_seeds])
42 | np.random.seed(0)
43 | for i, seed in enumerate(foam_seeds):
44 | if i == 0:
45 | trial_pt = trial_position(void_tess)
46 | else:
47 | r = seed.geometry.r
48 | check_bkdwns = bkdwns[:i]
49 | good_pt = False
50 | while not good_pt:
51 | trial_pt = trial_position(void_tess)
52 | good_pt = check_pt(trial_pt, r, check_bkdwns)
53 |
54 | seed.position = trial_pt
55 | bkdwns[i] = seed.breakdown
56 | seed.phase = 1
57 |
58 | # Combine Results
59 | materials = [void_mat, foam_mat]
60 | seeds = void_seeds + foam_seeds
61 | pmesh = msp.meshing.PolyMesh.from_seeds(seeds, domain)
62 |
63 | # Triangular Mesh
64 | tmesh = msp.meshing.TriMesh.from_polymesh(pmesh,
65 | materials,
66 | min_angle=20,
67 | max_edge_length=0.1)
68 |
69 | # Plot
70 | tmesh.plot(facecolor='aquamarine',
71 | edgecolor='k',
72 | linewidth=0.2)
73 |
74 | plt.gca().set_position([0, 0, 1, 1])
75 | plt.axis('image')
76 | plt.gca().set_axis_off()
77 | plt.gca().get_xaxis().set_visible(False)
78 | plt.gca().get_yaxis().set_visible(False)
79 |
80 | xlim, ylim = domain.limits
81 | plt.axis([xlim[0], xlim[1], ylim[0], ylim[1]])
82 |
83 | for ext in ['png', 'pdf']:
84 | fname = os.path.join(dirname, 'trimesh.' + ext)
85 | plt.savefig(fname, bbox_inches='tight', pad_inches=0)
86 |
87 |
88 | def pick_edge(void_tess):
89 | f_neighs = void_tess.facet_neighbors
90 | i = -1
91 | neighs = [-1, -1]
92 | while any([n < 0 for n in neighs]):
93 | i = np.random.randint(len(f_neighs))
94 | neighs = f_neighs[i]
95 | facet = void_tess.facets[i]
96 | j = np.random.randint(len(facet))
97 | kp1 = facet[j]
98 | kp2 = facet[j - 1]
99 | return kp1, kp2
100 |
101 |
102 | def trial_position(void_tess):
103 | kp1, kp2 = pick_edge(void_tess)
104 | pt1 = void_tess.points[kp1]
105 | pt2 = void_tess.points[kp2]
106 |
107 | f = np.random.rand()
108 | return [f * x1 + (1 - f) * x2 for x1, x2 in zip(pt1, pt2)]
109 |
110 |
111 | def check_pt(point, r, breakdowns):
112 | pts = breakdowns[:, :-1]
113 | rads = breakdowns[:, -1]
114 |
115 | rel_pos = pts - point
116 | dist = np.sqrt(np.sum(rel_pos * rel_pos, axis=1))
117 | min_dist = rads + r - 0.3 * np.minimum(rads, r)
118 | return np.all(dist > min_dist)
119 |
120 |
121 | if __name__ == '__main__':
122 | main()
123 |
--------------------------------------------------------------------------------
/src/microstructpy/examples/from_image.py:
--------------------------------------------------------------------------------
1 | import os
2 | import shutil
3 |
4 | import numpy as np
5 | from matplotlib import image as mpim
6 | from matplotlib import pyplot as plt
7 |
8 | import microstructpy as msp
9 |
10 | # Read in image
11 | image_basename = 'aluminum_micro.png'
12 | image_path = os.path.dirname(__file__)
13 | image_filename = os.path.join(image_path, image_basename)
14 | image = mpim.imread(image_filename)
15 | im_brightness = image[:, :, 0]
16 |
17 | # Bin the pixels
18 | br_bins = [0.00, 0.50, 1.00]
19 |
20 | bin_nums = np.zeros_like(im_brightness, dtype='int')
21 | for i in range(len(br_bins) - 1):
22 | lb = br_bins[i]
23 | ub = br_bins[i + 1]
24 | mask = np.logical_and(im_brightness >= lb, im_brightness <= ub)
25 | bin_nums[mask] = i
26 |
27 | # Define the phases
28 | phases = [{'color': c, 'material_type': 'amorphous'} for c in ('C0', 'C1')]
29 |
30 | # Create the polygon mesh
31 | m, n = bin_nums.shape
32 | x = np.arange(n + 1).astype('float')
33 | y = m + 1 - np.arange(m + 1).astype('float')
34 | xx, yy = np.meshgrid(x, y)
35 | pts = np.array([xx.flatten(), yy.flatten()]).T
36 | kps = np.arange(len(pts)).reshape(xx.shape)
37 |
38 | n_facets = 2 * (m + m * n + n)
39 | n_regions = m * n
40 | facets = np.full((n_facets, 2), -1)
41 | regions = np.full((n_regions, 4), 0)
42 | region_phases = np.full(n_regions, 0)
43 |
44 | facet_top = np.full((m, n), -1, dtype='int')
45 | facet_bottom = np.full((m, n), -1, dtype='int')
46 | facet_left = np.full((m, n), -1, dtype='int')
47 | facet_right = np.full((m, n), -1, dtype='int')
48 |
49 | k_facets = 0
50 | k_regions = 0
51 | for i in range(m):
52 | for j in range(n):
53 | kp_top_left = kps[i, j]
54 | kp_bottom_left = kps[i + 1, j]
55 | kp_top_right = kps[i, j + 1]
56 | kp_bottom_right = kps[i + 1, j + 1]
57 |
58 | # left facet
59 | if facet_left[i, j] < 0:
60 | fnum_left = k_facets
61 | facets[fnum_left] = (kp_top_left, kp_bottom_left)
62 | k_facets += 1
63 |
64 | if j > 0:
65 | facet_right[i, j - 1] = fnum_left
66 | else:
67 | fnum_left = facet_left[i, j]
68 |
69 | # right facet
70 | if facet_right[i, j] < 0:
71 | fnum_right = k_facets
72 | facets[fnum_right] = (kp_top_right, kp_bottom_right)
73 | k_facets += 1
74 |
75 | if j + 1 < n:
76 | facet_left[i, j + 1] = fnum_right
77 | else:
78 | fnum_right = facet_right[i, j]
79 |
80 | # top facet
81 | if facet_top[i, j] < 0:
82 | fnum_top = k_facets
83 | facets[fnum_top] = (kp_top_left, kp_top_right)
84 | k_facets += 1
85 |
86 | if i > 0:
87 | facet_bottom[i - 1, j] = fnum_top
88 | else:
89 | fnum_top = facet_top[i, j]
90 |
91 | # bottom facet
92 | if facet_bottom[i, j] < 0:
93 | fnum_bottom = k_facets
94 | facets[fnum_bottom] = (kp_bottom_left, kp_bottom_right)
95 | k_facets += 1
96 |
97 | if i + 1 < m:
98 | facet_top[i + 1, j] = fnum_bottom
99 | else:
100 | fnum_bottom = facet_bottom[i, j]
101 |
102 | # update region
103 | region = (fnum_top, fnum_left, fnum_bottom, fnum_right)
104 | regions[k_regions] = region
105 | region_phases[k_regions] = bin_nums[i, j]
106 | k_regions += 1
107 |
108 |
109 | pmesh = msp.meshing.PolyMesh(pts, facets, regions,
110 | seed_numbers=range(n_regions),
111 | phase_numbers=region_phases)
112 |
113 | # Create the triangle mesh
114 | tmesh = msp.meshing.TriMesh.from_polymesh(pmesh, phases=phases, min_angle=20)
115 |
116 | # Plot triangle mesh
117 | fig = plt.figure()
118 | ax = plt.Axes(fig, [0., 0., 1., 1.])
119 | ax.set_axis_off()
120 | ax.get_xaxis().set_visible(False)
121 | ax.get_yaxis().set_visible(False)
122 | fig.add_axes(ax)
123 |
124 | fcs = [phases[region_phases[r]]['color'] for r in tmesh.element_attributes]
125 | tmesh.plot(facecolors=fcs, edgecolors='k', lw=0.2)
126 |
127 |
128 | plt.axis('square')
129 | plt.xlim(x.min(), x.max())
130 | plt.ylim(y.min(), y.max())
131 | plt.axis('off')
132 |
133 | # Save plot and copy input file
134 | plot_basename = 'from_image/trimesh.png'
135 | file_dir = os.path.dirname(os.path.realpath(__file__))
136 | filename = os.path.join(file_dir, plot_basename)
137 | dirs = os.path.dirname(filename)
138 | if not os.path.exists(dirs):
139 | os.makedirs(dirs)
140 | plt.savefig(filename, bbox_inches='tight', pad_inches=0)
141 |
142 | shutil.copy(image_filename, dirs)
143 |
--------------------------------------------------------------------------------
/src/microstructpy/examples/grain_neighborhoods.py:
--------------------------------------------------------------------------------
1 | from __future__ import division
2 |
3 | import os
4 |
5 | import numpy as np
6 | import scipy.integrate
7 | import scipy.stats
8 | from matplotlib import pyplot as plt
9 |
10 | import microstructpy as msp
11 |
12 | # Define the domain
13 | domain = msp.geometry.Square(corner=(0, 0), side_length=10)
14 |
15 | # Define the material phases
16 | a_dist = scipy.stats.lognorm(s=1, scale=0.1)
17 | matrix_phase = {'fraction': 1,
18 | 'material_type': 'matrix',
19 | 'shape': 'circle',
20 | 'area': a_dist}
21 |
22 | neighborhood_phase = {'fraction': 1,
23 | 'material_type': 'solid',
24 | 'shape': 'ellipse',
25 | 'a': 1.5,
26 | 'b': 0.6,
27 | 'angle_deg': scipy.stats.uniform(0, 360)}
28 |
29 | phases = [matrix_phase, neighborhood_phase]
30 |
31 | # Create the seed list
32 | seeds = msp.seeding.SeedList.from_info(phases, domain.area)
33 | seeds.position(domain)
34 |
35 | # Replace the neighborhood phase with materials
36 | a = neighborhood_phase['a']
37 | b = neighborhood_phase['b']
38 | r = b / 3
39 | n = 16
40 |
41 | t_perim = np.linspace(0, 2 * np.pi, 201)
42 | x_perim = (a - r) * np.cos(t_perim)
43 | y_perim = (b - r) * np.sin(t_perim)
44 | dx = np.insert(np.diff(x_perim), 0, 0)
45 | dy = np.insert(np.diff(y_perim), 0, 0)
46 | ds = np.sqrt(dx * dx + dy * dy)
47 | arc_len = scipy.integrate.cumulative_trapezoid(ds, x=t_perim, initial=0)
48 | eq_spaced = arc_len[-1] * np.arange(n) / n
49 | x_pts = np.interp(eq_spaced, arc_len, x_perim)
50 | y_pts = np.interp(eq_spaced, arc_len, y_perim)
51 |
52 | repl_seeds = msp.seeding.SeedList()
53 | geom = {'a': a - 2 * r, 'b': b - 2 * r}
54 | for sn, seed in enumerate(seeds):
55 | if seed.phase == 0:
56 | repl_seeds.append(seed)
57 | else:
58 | center = seed.position
59 | theta = seed.geometry.angle_rad
60 |
61 | geom['angle_rad'] = theta
62 | geom['center'] = center
63 | core_seed = msp.seeding.Seed.factory('ellipse', phase=3,
64 | position=seed.position, **geom)
65 | repl_seeds.append(core_seed)
66 |
67 | x_ring = center[0] + x_pts * np.cos(theta) - y_pts * np.sin(theta)
68 | y_ring = center[1] + x_pts * np.sin(theta) + y_pts * np.cos(theta)
69 | for i in range(n):
70 | phase = 1 + (i % 2)
71 | center = (x_ring[i], y_ring[i])
72 | ring_geom = {'center': center, 'r': r}
73 | ring_seed = msp.seeding.Seed.factory('circle', position=center,
74 | phase=phase, **ring_geom)
75 | if domain.within(center):
76 | repl_seeds.append(ring_seed)
77 |
78 | # Create polygon and triangle meshes
79 | pmesh = msp.meshing.PolyMesh.from_seeds(repl_seeds, domain)
80 | phases = [{'material_type': 'solid'} for i in range(4)]
81 | phases[0]['material_type'] = 'matrix'
82 | tmesh = msp.meshing.TriMesh.from_polymesh(pmesh, phases, min_angle=20,
83 | max_volume=0.1)
84 |
85 | # Plot triangle mesh
86 | colors = ['C' + str(repl_seeds[att].phase) for att in tmesh.element_attributes]
87 | tmesh.plot(facecolors=colors, edgecolors='k', linewidth=0.2)
88 |
89 | plt.axis('square')
90 | plt.xlim(domain.limits[0])
91 | plt.ylim(domain.limits[1])
92 |
93 | file_dir = os.path.dirname(os.path.realpath(__file__))
94 | filename = os.path.join(file_dir, 'grain_neighborhoods/trimesh.png')
95 | dirs = os.path.dirname(filename)
96 | if not os.path.exists(dirs):
97 | os.makedirs(dirs)
98 | plt.savefig(filename, bbox_inches='tight', pad_inches=0)
99 |
--------------------------------------------------------------------------------
/src/microstructpy/examples/intro_1_basic.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Matrix
5 | matrix
6 | 2
7 | circle
8 |
9 | uniform
10 | 0
11 | 1.5
12 |
13 |
14 |
15 |
16 | Inclusions
17 | 1
18 | circle
19 | 2
20 |
21 |
22 |
23 | square
24 | 20
25 | (0, 0)
26 |
27 |
28 |
29 | True
30 | intro_1_basic
31 |
32 |
33 |
--------------------------------------------------------------------------------
/src/microstructpy/examples/intro_2_quality.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Matrix
5 | matrix
6 | 2
7 |
8 | circle
9 |
10 | uniform
11 | 0
12 | 1.5
13 |
14 |
15 |
16 |
17 | Inclusions
18 | 1
19 | circle
20 | 2
21 |
22 |
23 |
24 | square
25 | 20
26 | (0, 0)
27 |
28 |
29 |
30 | intro_2_quality
31 | True
32 |
33 |
34 | 25
35 | 1
36 | 0.1
37 |
38 |
39 |
--------------------------------------------------------------------------------
/src/microstructpy/examples/intro_3_size_shape.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Matrix
5 | matrix
6 | 2
7 |
8 | circle
9 |
10 | uniform
11 | 0
12 | 1.5
13 |
14 |
15 |
16 |
17 | Inclusions
18 | 1
19 | ellipse
20 |
21 | triang
22 | 0
23 | 2
24 | 1
25 |
26 |
27 | uniform
28 | 1
29 | 2
30 |
31 | random
32 |
33 |
34 |
35 | square
36 | 20
37 | (0, 0)
38 |
39 |
40 |
41 | intro_3_size_shape
42 | True
43 |
44 |
45 |
--------------------------------------------------------------------------------
/src/microstructpy/examples/intro_4_oriented.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Matrix
5 | matrix
6 | 2
7 |
8 | circle
9 |
10 | uniform
11 | 0
12 | 1.5
13 |
14 |
15 |
16 |
17 | Inclusions
18 | 1
19 | ellipse
20 |
21 | triang
22 | 0
23 | 2
24 | 1
25 |
26 |
27 | uniform
28 | 1
29 | 2
30 |
31 |
32 | uniform
33 | -10
34 | 20
35 |
36 |
37 |
38 |
39 | square
40 | 20
41 | (0, 0)
42 |
43 |
44 |
45 | intro_4_oriented
46 | True
47 |
48 |
49 |
--------------------------------------------------------------------------------
/src/microstructpy/examples/intro_5_plotting.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | matrix
5 | 2
6 |
7 | circle
8 |
9 | uniform
10 | 0
11 | 1.5
12 |
13 | pink
14 |
15 |
16 |
17 | 1
18 | circle
19 | 2
20 | lime
21 |
22 |
23 |
24 | square
25 | 20
26 | (0, 0)
27 |
28 |
29 |
30 |
31 | png
32 | png, pdf
33 | png
34 | eps
35 | pdf
36 |
37 |
38 | intro_5_plotting
39 | True
40 |
41 |
42 | 0.5
43 | none
44 |
45 |
46 |
47 | 3
48 | #A4058F
49 |
50 |
51 |
52 | 0.2
53 | navy
54 |
55 |
56 | False
57 |
58 |
59 |
--------------------------------------------------------------------------------
/src/microstructpy/examples/intro_6_culmination.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | matrix
5 | 2
6 |
7 | circle
8 |
9 | uniform
10 | 0
11 | 1.5
12 |
13 | pink
14 |
15 |
16 |
17 | 1
18 | ellipse
19 |
20 | triang
21 | 0
22 | 2
23 | 1
24 |
25 |
26 | uniform
27 | 1
28 | 2
29 |
30 |
31 | uniform
32 | -10
33 | 20
34 |
35 | lime
36 |
37 |
38 |
39 | square
40 | 20
41 | (0, 0)
42 |
43 |
44 |
45 |
46 | png
47 | png, pdf
48 | png
49 | eps
50 | pdf
51 |
52 |
53 | intro_6_culmination
54 | True
55 |
56 | 25
57 | 1
58 | 0.1
59 |
60 |
61 | 0.5
62 | none
63 |
64 |
65 |
66 | 3
67 | #A4058F
68 |
69 |
70 |
71 | 0.2
72 | navy
73 |
74 |
75 | False
76 |
77 |
78 |
--------------------------------------------------------------------------------
/src/microstructpy/examples/logo.py:
--------------------------------------------------------------------------------
1 | from __future__ import division
2 |
3 | import os
4 |
5 | import numpy as np
6 | from matplotlib import collections
7 | from matplotlib import pyplot as plt
8 | from matplotlib.backends.backend_agg import FigureCanvasAgg
9 | from matplotlib.offsetbox import AnnotationBbox
10 | from matplotlib.offsetbox import OffsetImage
11 |
12 | import microstructpy as msp
13 |
14 |
15 | def main(n_seeds, size_rng, pos_rng, k_lw):
16 | bkgrnd_color = 'black'
17 | line_color = (1, 1, 1, 1) # white
18 |
19 | dpi = 300
20 | init_size = 2000
21 | logo_size = 1500
22 | favicon_size = 48
23 |
24 | logo_basename = 'logo.svg'
25 | favicon_basename = 'favicon.ico'
26 | social_basename = 'social.png'
27 | file_dir = os.path.dirname(os.path.realpath(__file__))
28 | path = os.path.join(file_dir, 'logo')
29 | if not os.path.exists(path):
30 | os.makedirs(path)
31 | logo_filename = os.path.join(path, logo_basename)
32 | pad_filename = os.path.join(path, 'pad_' + logo_basename)
33 | favicon_filename = os.path.join(path, favicon_basename)
34 | social_filename = os.path.join(path, social_basename)
35 |
36 | # Set Domain
37 | domain = msp.geometry.Circle()
38 |
39 | # Set Seed List
40 | np.random.seed(size_rng)
41 | rs = 0.3 * np.random.rand(n_seeds)
42 |
43 | factory = msp.seeding.Seed.factory
44 | seeds = msp.seeding.SeedList([factory('circle', r=r) for r in rs])
45 | seeds.position(domain, rng_seed=pos_rng)
46 |
47 | # Create the Poly Mesh
48 | pmesh = msp.meshing.PolyMesh.from_seeds(seeds, domain)
49 |
50 | # Create and Format the Figure
51 | plt.clf()
52 | plt.close('all')
53 | fig = plt.figure(figsize=(init_size / dpi, init_size / dpi), dpi=dpi)
54 | ax = plt.Axes(fig, [0., 0., 1., 1.])
55 | ax.set_axis_off()
56 | ax.get_xaxis().set_visible(False)
57 | ax.get_yaxis().set_visible(False)
58 | fig.add_axes(ax)
59 |
60 | # Plot the Domain
61 | domain.plot(ec='none', fc=bkgrnd_color)
62 |
63 | # Plot the Facets
64 | facet_colors = []
65 | for neigh_pair in pmesh.facet_neighbors:
66 | if min(neigh_pair) < 0:
67 | facet_colors.append((0, 0, 0, 0))
68 | else:
69 | facet_colors.append(line_color)
70 |
71 | lw = k_lw * init_size / 100
72 | pmesh.plot_facets(index_by='facet', colors=facet_colors,
73 | linewidth=lw, capstyle='round')
74 |
75 | pts = np.array(pmesh.points)
76 | rs = np.sqrt(np.sum(pts * pts, axis=1))
77 | mask = np.isclose(rs, 1)
78 |
79 | edges = []
80 | for facet in pmesh.facets:
81 | if np.sum(mask[facet]) != 1:
82 | continue
83 |
84 | edge = np.copy(pts[facet])
85 | if mask[facet[0]]:
86 | u = edge[0] - edge[1]
87 | u *= 1.1
88 | edge[0] = edge[1] + u
89 | else:
90 | u = edge[1] - edge[0]
91 | u *= 1.1
92 | edge[1] = edge[0] + u
93 | edges.append(edge)
94 |
95 | pc = collections.LineCollection(edges, color=line_color, linewidth=lw,
96 | capstyle='round')
97 | ax.add_collection(pc)
98 |
99 | # Format the Plot and Convert to Image Array
100 | plt.axis('square')
101 | plt.axis(1.01 * np.array([-1, 1, -1, 1]))
102 | canvas = FigureCanvasAgg(fig)
103 | canvas.draw()
104 |
105 | plt_im = np.array(canvas.buffer_rgba())
106 | mask = plt_im[:, :, 0] > 0.5 * 255
107 |
108 | # Create the Logo
109 | logo_im = np.copy(plt_im)
110 |
111 | xx, yy = np.meshgrid(*[np.arange(n) for n in logo_im.shape[:2]])
112 | zz = - 0.2 * xx + 0.9 * yy
113 | ss = (zz - zz.min()) / (zz.max() - zz.min())
114 |
115 | c1 = [67, 206, 162]
116 | c2 = [24, 90, 157]
117 |
118 | logo_im[mask, -1] = 0 # transparent background
119 |
120 | # gradient
121 | for i in range(logo_im.shape[-1] - 1):
122 | logo_im[~mask, i] = (1 - ss[~mask]) * c1[i] + ss[~mask] * c2[i]
123 |
124 | inds = np.linspace(0, logo_im.shape[0] - 1, logo_size).astype('int')
125 | logo_im = logo_im[inds]
126 | logo_im = logo_im[:, inds]
127 |
128 | pad_w = logo_im.shape[0]
129 | pad_h = 0.5 * logo_im.shape[1]
130 | pad_shape = np.array([pad_w, pad_h, logo_im.shape[2]]).astype('int')
131 | logo_pad = np.zeros(pad_shape, dtype=logo_im.dtype)
132 | pad_im = np.concatenate((logo_pad, logo_im, logo_pad), axis=1)
133 | doc_im = np.concatenate((logo_pad, pad_im, logo_pad), axis=1)
134 |
135 | plt.imsave(logo_filename, logo_im, dpi=dpi)
136 | plt.imsave(logo_filename.replace('.svg', '.png'), np.ascontiguousarray(logo_im), dpi=dpi)
137 | plt.imsave(pad_filename, pad_im, dpi=dpi)
138 | plt.imsave(pad_filename.replace('.svg', '.png'), np.ascontiguousarray(doc_im), dpi=dpi)
139 |
140 | # Create the Favicon
141 | fav_im = np.copy(logo_im)
142 | inds = np.linspace(0, fav_im.shape[0] - 1, favicon_size).astype('int')
143 | fav_im = fav_im[inds]
144 | fav_im = fav_im[:, inds]
145 |
146 | plt.imsave(favicon_filename, np.ascontiguousarray(fav_im), dpi=dpi, format='png')
147 |
148 | # Create the Social Banner
149 | fig_social, ax_social = plt.subplots()
150 |
151 | ax_social.set_xlim(0, 2)
152 | ax_social.set_ylim(0, 1)
153 | ax_social.set_aspect('equal')
154 |
155 | ax_social.set_axis_off()
156 | ax_social.get_xaxis().set_visible(False)
157 | ax_social.get_yaxis().set_visible(False)
158 |
159 | imagebox = OffsetImage(logo_im, zoom=0.05)
160 | ab = AnnotationBbox(imagebox, (1, 0.7), frameon=False)
161 | ax_social.add_artist(ab)
162 | ax_social.text(1, 0.35, 'MicroStructPy',
163 | fontsize=20,
164 | weight='bold',
165 | horizontalalignment='center',
166 | verticalalignment='center')
167 | ax_social.text(1, 0.23, 'Microstructure Mesh Generation in Python',
168 | fontsize=10,
169 | horizontalalignment='center',
170 | verticalalignment='center')
171 | plt.draw()
172 | plt.savefig(social_filename, bbox_inches='tight', pad_inches=0)
173 | plt.close('all')
174 |
175 |
176 | if __name__ == '__main__':
177 | n_seeds = 14
178 | size_rng = 4
179 | pos_rng = 7
180 | k_lw = 1.1
181 |
182 | main(n_seeds, size_rng, pos_rng, k_lw)
183 |
--------------------------------------------------------------------------------
/src/microstructpy/examples/minimal.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | circle
5 | 0.15
6 |
7 |
8 |
9 | square
10 |
11 |
12 |
--------------------------------------------------------------------------------
/src/microstructpy/examples/minimal_paired.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | circle
5 | 0.09
6 |
7 |
8 |
9 | square
10 |
11 |
12 |
13 | minimal
14 | False
15 | seed number
16 | Paired
17 | gmsh
18 | 0.03
19 |
20 |
21 |
--------------------------------------------------------------------------------
/src/microstructpy/examples/olivine_cdf.csv:
--------------------------------------------------------------------------------
1 | 0.0578778,1.5701240548769328e-6
2 | 0.154341,0.00033025723859269246
3 | 0.250804,0.0036920787776204785
4 | 0.361736,0.009699296325930005
5 | 0.458199,0.022361588309627884
6 | 0.559486,0.03540695717145988
7 | 0.660772,0.05480969583418152
8 | 0.757235,0.06994861116131441
9 | 0.858521,0.09885177611031959
10 | 0.959807,0.12608273026813632
11 | 1.05145,0.17472554028359996
12 | 1.1672,0.19938391704059527
13 | 1.25402,0.2623745913809862
14 | 1.36013,0.329340547069217
15 | 1.46624,0.36327522429202896
16 | 1.5627,0.42510214002218444
17 | 1.65434,0.5226136019375014
18 | 1.76045,0.5524047674579283
19 | 1.86174,0.5876397044607361
20 | 1.96302,0.6289435590528172
21 | 2.35852,0.7005801812903562
22 | 2.96141,0.8423918690211719
23 | 3.06752,1.0
24 |
--------------------------------------------------------------------------------
/src/microstructpy/examples/standard_voronoi.py:
--------------------------------------------------------------------------------
1 | import os
2 |
3 | from matplotlib import pyplot as plt
4 |
5 | import microstructpy as msp
6 |
7 | # Create domain
8 | domain = msp.geometry.Square()
9 |
10 | # Create list of seed points
11 | factory = msp.seeding.Seed.factory
12 | n = 50
13 | seeds = msp.seeding.SeedList([factory('circle', r=0.01) for i in range(n)])
14 | seeds.position(domain)
15 |
16 | # Create Voronoi diagram
17 | pmesh = msp.meshing.PolyMesh.from_seeds(seeds, domain)
18 |
19 | # Plot Voronoi diagram and seed points
20 | pmesh.plot(edgecolors='k', facecolors='gray')
21 | seeds.plot(edgecolors='k', facecolors='none')
22 |
23 | plt.axis('square')
24 | plt.xlim(domain.limits[0])
25 | plt.ylim(domain.limits[1])
26 |
27 | file_dir = os.path.dirname(os.path.realpath(__file__))
28 | filename = os.path.join(file_dir, 'standard_voronoi/voronoi_diagram.png')
29 | dirs = os.path.dirname(filename)
30 | if not os.path.exists(dirs):
31 | os.makedirs(dirs)
32 | plt.savefig(filename, bbox_inches='tight', pad_inches=0)
33 |
--------------------------------------------------------------------------------
/src/microstructpy/examples/two_phase_3D.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 1
5 |
6 | lognorm
7 | 1
8 | 0.95
9 |
10 | sphere
11 | Phase 1
12 |
13 |
14 |
15 | 3
16 |
17 | lognorm
18 | 0.5
19 | 1.01
20 |
21 | Phase 2
22 |
23 |
24 |
25 | cube
26 | 7
27 | (0, 0, 0)
28 |
29 |
30 |
31 | two_phase_3D
32 | True
33 |
34 |
35 | 0.2
36 |
37 |
38 | 0.2
39 |
40 |
41 | 0.2
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/src/microstructpy/examples/uniform_seeding.py:
--------------------------------------------------------------------------------
1 | from __future__ import division
2 |
3 | import os
4 |
5 | import matplotlib as mpl
6 | import numpy as np
7 | from matplotlib import pyplot as plt
8 | from scipy.spatial import distance
9 |
10 | import microstructpy as msp
11 |
12 | # Create domain
13 | domain = msp.geometry.Square(corner=(0, 0))
14 |
15 | # Create list of seed points
16 | factory = msp.seeding.Seed.factory
17 | n = 200
18 | seeds = msp.seeding.SeedList([factory('circle', r=0.007) for i in range(n)])
19 |
20 | # Position seeds according to Mitchell's Best Candidate Algorithm
21 | np.random.seed(0)
22 |
23 | lims = np.array(domain.limits) * (1 - 1e-5)
24 | centers = np.zeros((n, 2))
25 |
26 | for i in range(n):
27 | f = np.random.rand(i + 1, 2)
28 | pts = f * lims[:, 0] + (1 - f) * lims[:, 1]
29 | try:
30 | min_dists = distance.cdist(pts, centers[:i]).min(axis=1)
31 | i_max = np.argmax(min_dists)
32 | except ValueError: # this is the case when i=0
33 | i_max = 0
34 | centers[i] = pts[i_max]
35 | seeds[i].position = centers[i]
36 |
37 | # Create Voronoi diagram
38 | pmesh = msp.meshing.PolyMesh.from_seeds(seeds, domain)
39 |
40 | # Set colors based on area
41 | areas = pmesh.volumes
42 | std_area = domain.area / n
43 | min_area = min(areas)
44 | max_area = max(areas)
45 | cell_colors = np.zeros((n, 3))
46 | for i in range(n):
47 | if areas[i] < std_area:
48 | f_red = (areas[i] - min_area) / (std_area - min_area)
49 | f_green = (areas[i] - min_area) / (std_area - min_area)
50 | f_blue = 1
51 | else:
52 | f_red = 1
53 | f_green = (max_area - areas[i]) / (max_area - std_area)
54 | f_blue = (max_area - areas[i]) / (max_area - std_area)
55 | cell_colors[i] = (f_red, f_green, f_blue)
56 |
57 | # Create colorbar
58 | vs = (std_area - min_area) / (max_area - min_area)
59 | colors = [(0, (0, 0, 1)), (vs, (1, 1, 1)), (1, (1, 0, 0))]
60 | cmap = mpl.colors.LinearSegmentedColormap.from_list('area_cmap', colors)
61 | norm = mpl.colors.Normalize(vmin=min_area, vmax=max_area)
62 | sm = plt.cm.ScalarMappable(cmap=cmap, norm=norm)
63 | sm.set_array([])
64 | cb = plt.colorbar(sm, ticks=[min_area, std_area, max_area], ax=plt.gca(),
65 | orientation='horizontal', fraction=0.046, pad=0.08)
66 | cb.set_label('Cell Area')
67 |
68 | # Plot Voronoi diagram and seed points
69 | pmesh.plot(edgecolors='k', facecolors=cell_colors)
70 | seeds.plot(edgecolors='k', facecolors='none')
71 |
72 | plt.axis('square')
73 | plt.xlim(domain.limits[0])
74 | plt.ylim(domain.limits[1])
75 |
76 | # Save diagram
77 | file_dir = os.path.dirname(os.path.realpath(__file__))
78 | filename = os.path.join(file_dir, 'uniform_seeding/voronoi_diagram.png')
79 | dirs = os.path.dirname(filename)
80 | if not os.path.exists(dirs):
81 | os.makedirs(dirs)
82 | plt.savefig(filename, bbox_inches='tight', pad_inches=0)
83 |
--------------------------------------------------------------------------------
/src/microstructpy/geometry/__init__.py:
--------------------------------------------------------------------------------
1 | from microstructpy.geometry.box import Box
2 | from microstructpy.geometry.box import Cube
3 | from microstructpy.geometry.circle import Circle
4 | from microstructpy.geometry.ellipse import Ellipse
5 | from microstructpy.geometry.ellipsoid import Ellipsoid
6 | from microstructpy.geometry.rectangle import Rectangle
7 | from microstructpy.geometry.rectangle import Square
8 | from microstructpy.geometry.sphere import Sphere
9 |
10 | __all__ = ['Box', 'Cube', 'Circle', 'Ellipse', 'Ellipsoid',
11 | 'Rectangle', 'Square', 'Sphere']
12 |
13 |
14 | def factory(name, **kwargs):
15 | """Factory method for geometries.
16 |
17 | This function returns a geometry based on a string containing the
18 | name of the geometry and keyword arguments defining the geometry.
19 |
20 | .. note::
21 |
22 | The function call is ``factory(name, **kwargs)``. Sphinx autodocs
23 | has dropped the first parameter.
24 |
25 | Args:
26 | name (str): {'box' | 'cube' | 'ellipse' | 'ellipsoid' | 'circle' |
27 | 'rectangle' | 'square' | 'sphere'} Name of geometry.
28 | **kwargs (dict): Arguments defining the geometry.
29 |
30 | """
31 | geom = name.strip().lower()
32 | if geom in ('box', 'rectangular prism', 'cuboid'):
33 | return Box(**kwargs)
34 | elif geom == 'cube':
35 | return Cube(**kwargs)
36 | elif geom == 'ellipse':
37 | return Ellipse(**kwargs)
38 | elif geom == 'ellipsoid':
39 | return Ellipsoid(**kwargs)
40 | elif geom == 'circle':
41 | return Circle(**kwargs)
42 | elif geom == 'rectangle':
43 | return Rectangle(**kwargs)
44 | elif geom == 'square':
45 | return Square(**kwargs)
46 | elif geom == 'sphere':
47 | return Sphere(**kwargs)
48 | else:
49 | e_str = 'Cannot recognize geometry name: ' + geom
50 | raise ValueError(e_str)
51 |
--------------------------------------------------------------------------------
/src/microstructpy/geometry/box.py:
--------------------------------------------------------------------------------
1 | """Box
2 |
3 | This module contains the Box class.
4 |
5 | """
6 | # --------------------------------------------------------------------------- #
7 | # #
8 | # Import Modules #
9 | # #
10 | # --------------------------------------------------------------------------- #
11 |
12 | from __future__ import division
13 |
14 | import numpy as np
15 | from matplotlib import pyplot as plt
16 | from mpl_toolkits.mplot3d import Axes3D
17 | from mpl_toolkits.mplot3d.art3d import Poly3DCollection
18 |
19 | from microstructpy.geometry.n_box import NBox
20 |
21 | __author__ = 'Kenneth (Kip) Hart'
22 |
23 |
24 | # --------------------------------------------------------------------------- #
25 | # #
26 | # Box Class #
27 | # #
28 | # --------------------------------------------------------------------------- #
29 | class Box(NBox):
30 | """Box
31 |
32 | This class contains a generic, 3D box. The position and dimensions of the
33 | box can be specified using any of the parameters below.
34 |
35 | Without any parameters, this is a unit cube centered on the origin.
36 |
37 | Args:
38 | side_lengths (list): *(optional)* Side lengths.
39 | center (list): *(optional)* Center of box.
40 | corner (list): *(optional)* Bottom-left corner.
41 | limits (list): *(optional)* Bounds of box.
42 | bounds (list): *(optional)* Alias for ``limits``.
43 |
44 | """
45 | def __init__(self, **kwargs):
46 | NBox.__init__(self, **kwargs)
47 |
48 | try:
49 | self.center
50 | except AttributeError:
51 | self.center = [0, 0, 0]
52 |
53 | try:
54 | self.side_lengths
55 | except AttributeError:
56 | self.side_lengths = [1, 1, 1]
57 |
58 | # ----------------------------------------------------------------------- #
59 | # Representation Function #
60 | # ----------------------------------------------------------------------- #
61 | def __repr__(self):
62 | repr_str = 'Box('
63 | repr_str += 'center=' + repr(tuple(self.center)) + ', '
64 | repr_str += 'side_lengths=' + repr(tuple(self.side_lengths)) + ')'
65 | return repr_str
66 |
67 | # ----------------------------------------------------------------------- #
68 | # Number of Dimensions #
69 | # ----------------------------------------------------------------------- #
70 | @property
71 | def n_dim(self):
72 | """int: number of dimensions, 3"""
73 | return 3
74 |
75 | # ----------------------------------------------------------------------- #
76 | # Volume #
77 | # ----------------------------------------------------------------------- #
78 | @property
79 | def volume(self):
80 | """float: volume of box, :math:`V=l_1 l_2 l_3`"""
81 | return self.n_vol
82 |
83 | # ----------------------------------------------------------------------- #
84 | # Plot Function #
85 | # ----------------------------------------------------------------------- #
86 | def plot(self, **kwargs):
87 | """Plot the box.
88 |
89 | This function adds an
90 | :class:`mpl_toolkits.mplot3d.art3d.Poly3DCollection` to the current
91 | axes. The keyword arguments are passed through to the Poly3DCollection.
92 |
93 | Args:
94 | **kwargs (dict): Keyword arguments for Poly3DCollection.
95 |
96 | """ # NOQA: E501
97 | if plt.gcf().axes:
98 | ax = plt.gca()
99 | else:
100 | ax = plt.gcf().add_subplot(projection=Axes3D.name)
101 |
102 | xlim, ylim, zlim = self.limits
103 |
104 | inds = [(0, 0), (0, 1), (1, 1), (1, 0)]
105 |
106 | # x faces
107 | f1 = np.array([(xlim[0], ylim[i], zlim[j]) for i, j in inds])
108 | f2 = np.array([(xlim[1], ylim[i], zlim[j]) for i, j in inds])
109 |
110 | # y faces
111 | f3 = np.array([(xlim[i], ylim[0], zlim[j]) for i, j in inds])
112 | f4 = np.array([(xlim[i], ylim[1], zlim[j]) for i, j in inds])
113 |
114 | # z faces
115 | f5 = np.array([(xlim[i], ylim[j], zlim[0]) for i, j in inds])
116 | f6 = np.array([(xlim[i], ylim[j], zlim[1]) for i, j in inds])
117 |
118 | # plot
119 | xy = [f1, f2, f3, f4, f5, f6]
120 | pc = Poly3DCollection(xy, **kwargs)
121 | ax.add_collection(pc)
122 |
123 |
124 | # --------------------------------------------------------------------------- #
125 | # #
126 | # Cube Class #
127 | # #
128 | # --------------------------------------------------------------------------- #
129 | class Cube(Box):
130 | """A cube.
131 |
132 | This class contains a generic, 3D cube. It is derived from the
133 | :class:`.Box` and contains the ``side_length`` property, rather than
134 | multiple side lengths.
135 |
136 | Without any parameters, this is a unit cube centered on the origin.
137 |
138 | Args:
139 | side_length (float): *(optional)* Side length.
140 | center (list, tuple, numpy.ndarray): *(optional)* Center of box.
141 | corner (list, tuple, numpy.ndarray): *(optional)* Bottom-left corner.
142 | """
143 | def __init__(self, **kwargs):
144 | if 'side_length' in kwargs:
145 | kwargs['side_lengths'] = 3 * [kwargs['side_length']]
146 |
147 | Box.__init__(self, **kwargs)
148 |
149 | # ----------------------------------------------------------------------- #
150 | # Side Length Property #
151 | # ----------------------------------------------------------------------- #
152 | @property
153 | def side_length(self):
154 | """float: length of the side of the cube."""
155 | return self.side_lengths[0]
156 |
--------------------------------------------------------------------------------
/src/microstructpy/meshing/__init__.py:
--------------------------------------------------------------------------------
1 | from microstructpy.meshing.polymesh import PolyMesh
2 | from microstructpy.meshing.trimesh import RasterMesh
3 | from microstructpy.meshing.trimesh import TriMesh
4 |
5 | __all__ = ['PolyMesh', 'RasterMesh', 'TriMesh']
6 |
--------------------------------------------------------------------------------
/src/microstructpy/seeding/__init__.py:
--------------------------------------------------------------------------------
1 | from microstructpy.seeding.seed import Seed
2 | from microstructpy.seeding.seedlist import SeedList
3 |
4 | __all__ = ['Seed', 'SeedList']
5 |
--------------------------------------------------------------------------------
/tests/cli/test_includes.py:
--------------------------------------------------------------------------------
1 | import os
2 |
3 | import xmltodict
4 |
5 | from microstructpy import cli
6 |
7 |
8 | def test_equivalence():
9 | print(os.getcwd())
10 | files_dir = os.path.join(os.path.dirname(__file__), 'test_includes_files')
11 | with open(os.path.join(files_dir, 'expected_input.xml'), 'r') as file:
12 | expected = xmltodict.parse(file.read())
13 |
14 | for fname in ['input.xml', 'different_dir/input.xml']:
15 | actual = cli.input2dict(os.path.join(files_dir, fname))
16 | assert expected == actual
17 |
--------------------------------------------------------------------------------
/tests/cli/test_includes_files/different_dir/input.xml:
--------------------------------------------------------------------------------
1 |
2 | ../materials.xml
3 |
4 | square
5 | 20
6 |
7 |
8 | True
9 |
10 |
11 |
--------------------------------------------------------------------------------
/tests/cli/test_includes_files/expected_input.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Fine 1
4 | circle
5 | 0.1
6 |
7 |
8 |
9 | Fine 2
10 | circle
11 | 0.1
12 |
13 |
14 |
15 | Coarse
16 | circle
17 | 0.3
18 |
19 |
20 | square
21 | 20
22 |
23 |
24 | True
25 |
26 |
27 |
--------------------------------------------------------------------------------
/tests/cli/test_includes_files/fine_grained.xml:
--------------------------------------------------------------------------------
1 |
2 | circle
3 | 0.1
4 |
5 |
--------------------------------------------------------------------------------
/tests/cli/test_includes_files/input.xml:
--------------------------------------------------------------------------------
1 |
2 | materials.xml
3 |
4 | square
5 | 20
6 |
7 |
8 | True
9 |
10 |
11 |
--------------------------------------------------------------------------------
/tests/cli/test_includes_files/materials.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Fine 1
4 | fine_grained.xml
5 |
6 |
7 |
8 | Fine 2
9 | fine_grained.xml
10 |
11 |
12 |
13 | Coarse
14 | circle
15 | 0.3
16 |
17 |
18 |
--------------------------------------------------------------------------------
/tests/geometry/test_n_sphere.py:
--------------------------------------------------------------------------------
1 | import microstructpy as msp
2 |
3 | c1 = msp.geometry.n_sphere.NSphere(r=1, center=(0, 4, -1))
4 | c2 = msp.geometry.n_sphere.NSphere(r=2, center=(3, 1))
5 | c3 = msp.geometry.n_sphere.NSphere(d=4, center=(3, 1))
6 |
7 |
8 | def test_eq():
9 | assert c1 == c1
10 | assert not c2 == c1
11 |
12 | assert c2 == c3
13 |
--------------------------------------------------------------------------------
/tests/meshing/test_polymesh.py:
--------------------------------------------------------------------------------
1 | from __future__ import division
2 |
3 | import os
4 | import sys
5 |
6 | import numpy as np
7 |
8 | from microstructpy import geometry
9 | from microstructpy.meshing.polymesh import PolyMesh
10 | from microstructpy.meshing.polymesh import kp_loop
11 | from microstructpy.seeding import Seed
12 | from microstructpy.seeding import SeedList
13 |
14 | '''
15 | Test Mesh
16 |
17 | D ------- C
18 | | | \
19 | | | \
20 | | | \
21 | A ------- B -- E
22 |
23 | A = (0, 0)
24 | B = (1, 0)
25 | C = (1, 1)
26 | D = (0, 1)
27 | E = (1.5, 0)
28 |
29 | Facets:
30 | 0 A B
31 | 1 B C
32 | 2 C D
33 | 3 D A
34 | 4 B E
35 | 5 E C
36 |
37 | Regions:
38 | 0, 1, 2, 3
39 | 4, 5, 1
40 |
41 | Seed Numbers:
42 | 0
43 | 1
44 |
45 | Phase Numbers:
46 | 2
47 | 2
48 |
49 | '''
50 |
51 | A = (0, 0)
52 | B = (1, 0)
53 | C = (1, 1)
54 | D = (0, 1)
55 | E = (1.5, 0)
56 | pts = [A, B, C, D, E]
57 |
58 | facets = [(0, 1), (1, 2), (2, 3), (3, 0), (1, 4), (4, 2)]
59 |
60 | regions = [(0, 1, 2, 3), (4, 5, 1)]
61 |
62 | seed_nums = [0, 1]
63 | phase_nums = [2, 2]
64 |
65 | pmesh = PolyMesh(pts, facets, regions, seed_nums, phase_nums)
66 |
67 |
68 | def test_eq():
69 | assert pmesh == pmesh
70 |
71 | r2 = [(0, 3, 2, 1), (4, 1, 5)]
72 | pmesh2 = PolyMesh(pts, facets, r2, seed_nums, phase_nums)
73 | assert pmesh == pmesh2
74 | assert pmesh2 == pmesh
75 |
76 | assert pmesh != pts
77 | assert pmesh != PolyMesh(pts, facets, regions, seed_nums, phase_nums[:-1])
78 |
79 | r3 = [(0, 3, 2), (4, 1, 5)]
80 | assert pmesh != PolyMesh(pts, facets, r3, seed_nums, phase_nums)
81 |
82 | pt2 = [(-1, 0), B, C, D, E]
83 | assert pmesh != PolyMesh(pt2, facets, regions, seed_nums, phase_nums)
84 |
85 | f2 = [(0, 1), (1, 3), (2, 3), (3, 0), (1, 4), (4, 2)]
86 | assert pmesh != PolyMesh(pts, f2, regions, seed_nums, phase_nums)
87 |
88 | pmesh3 = PolyMesh(pts, facets, regions)
89 | assert pmesh3 == pmesh3
90 | assert pmesh3 != pmesh
91 |
92 |
93 | def test_read_write():
94 | pyver_str = sys.version.split(' ')[0]
95 | pyver_str = pyver_str.replace('.', '_')
96 |
97 | fname = 'tmp_' + pyver_str + '.txt'
98 | filepath = os.path.dirname(__file__)
99 | filename = filepath + '/' + fname
100 |
101 | pmesh.write(filename)
102 | rw_pmesh = PolyMesh.from_file(filename)
103 | os.remove(filename)
104 | assert pmesh == rw_pmesh
105 |
106 | alt_str = 'comments\n' + str(pmesh)
107 | with open(filename, 'w') as file:
108 | file.write(alt_str + '\n')
109 | rw_pmesh = PolyMesh.from_file(filename)
110 | os.remove(filename)
111 | assert pmesh == rw_pmesh
112 |
113 |
114 | def test_repr():
115 | assert pmesh == eval(repr(pmesh))
116 |
117 | pmesh2 = PolyMesh(pts, facets, regions)
118 | assert pmesh2 == eval(repr(pmesh2))
119 |
120 |
121 | def test_from_seeds():
122 | # d^2 = dx^2 + dy^2 - r^2
123 | # Let d = 3
124 | # And circle 1 has radius 4,
125 | # so dx = 5
126 | # And circle 2 has radius 2,
127 | # so dx = np.sqrt(13)
128 | # and in both cases, y= 0
129 |
130 | d = 3
131 | r1 = 4
132 | r2 = 2
133 |
134 | x1 = -np.sqrt(d * d + r1 * r1)
135 | x2 = np.sqrt(d * d + r2 * r2)
136 |
137 | p1 = 2
138 | p2 = 3
139 |
140 | x_len = 2 * 1.1 * max(-x1 + r1, x2 + r2)
141 | y_len = 2 * 1.1 * max(r1, r2)
142 |
143 | # create polymesh by hand
144 | A = (-0.5 * x_len, -0.5 * y_len)
145 | B = (0, -0.5 * y_len)
146 | C = (0.5 * x_len, -0.5 * y_len)
147 | D = (0.5 * x_len, 0.5 * y_len)
148 | E = (0, 0.5 * y_len)
149 | F = (-0.5 * x_len, 0.5 * y_len)
150 |
151 | pts = [A, B, C, D, E, F]
152 | facets = [(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 0), (1, 4)]
153 | regions = [(0, 6, 4, 5), (1, 2, 3, 6)]
154 | poly_exp = PolyMesh(pts, facets, regions, [0, 1], [p1, p2])
155 |
156 | # create polymesh from seeds and domain
157 | s1 = Seed.factory('circle', r=r1, center=(x1, 0), phase=p1)
158 | s2 = Seed.factory('circle', r=r2, center=(x2, 0), phase=p2)
159 | slist = SeedList([s1, s2])
160 |
161 | lens = [x_len, y_len]
162 | dom = geometry.Rectangle(center=(0.0, 0.0), side_lengths=lens)
163 |
164 | poly_act = PolyMesh.from_seeds(slist, dom)
165 | assert poly_exp == poly_act
166 |
167 |
168 | def test_kp_loop():
169 | p1 = [0, 1]
170 | p2 = [1, 2]
171 | p3 = [2, 0]
172 | pairs = [p1, p2, p3]
173 | loop = kp_loop(pairs)
174 |
175 | possible_pairs = [(0, 1, 2),
176 | (1, 2, 0),
177 | (2, 0, 1),
178 | (2, 1, 0),
179 | (1, 0, 2),
180 | (0, 2, 1)]
181 | assert tuple(loop) in possible_pairs
182 |
--------------------------------------------------------------------------------
/tests/test_misc.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 |
3 | from microstructpy import _misc
4 |
5 |
6 | def test_from_str_int():
7 | pairs = [('0', 0),
8 | ('1', 1),
9 | ('2', 2),
10 | ('-1', -1),
11 | ('-2', -2)]
12 |
13 | for int_str, int_exp in pairs:
14 | int_act = _misc.from_str(int_str)
15 | a_str = 'Expected ' + str(int_exp) + ' and got ' + str(int_act)
16 | assert int_exp == int_act, a_str
17 |
18 |
19 | def test_from_str_float():
20 | pairs = [('1.234', 1.234),
21 | ('0.214', 0.214),
22 | ('-0.4', -0.4),
23 | ('1.2e5', 1.2e5)]
24 |
25 | for flt_str, flt_exp in pairs:
26 | flt_act = _misc.from_str(flt_str)
27 | a_str = 'Expected ' + str(flt_exp) + ' and got ' + str(flt_act)
28 | assert flt_exp == flt_act, a_str
29 |
30 |
31 | def test_from_str_bool():
32 | pairs = [('True', True),
33 | ('False', False),
34 | ('true', True),
35 | ('false', False)]
36 |
37 | for bool_str, bool_exp in pairs:
38 | bool_act = _misc.from_str(bool_str)
39 | a_str = 'Expected ' + str(bool_exp) + ' and got ' + str(bool_act)
40 | a_str += ' for string ' + repr(bool_str)
41 | assert bool_exp == bool_act, a_str
42 |
43 |
44 | def test_from_str_list():
45 | pairs = [('[0]', [0]),
46 | # ('[1, 0, a]', [1, 0, 'a']),
47 | ('[-2.3, true]', [-2.3, True])]
48 |
49 | for list_str, list_exp in pairs:
50 | list_act = _misc.from_str(list_str)
51 | assert len(list_exp) == len(list_act)
52 | for act_val, exp_val in zip(list_act, list_exp):
53 | assert act_val == exp_val
54 |
55 |
56 | '''
57 | def test_from_str_list_of_lists():
58 | lol_str = '[[1, 0, 0, True, False], [2, 4, a, -2.3]]'
59 | lol_exp = [[1, 0, 0, True, False], [2, 4, 'a', -2.3]]
60 |
61 | lol_act = _misc.from_str(lol_str)
62 |
63 | assert len(lol_exp) == len(lol_act)
64 | for list_exp, list_act in zip(lol_exp, lol_act):
65 | assert len(list_exp) == len(list_act)
66 | for val_exp, val_act in zip(list_exp, list_act):
67 | assert val_exp == val_act
68 | '''
69 |
70 |
71 | def test_tangent_sphere_2D():
72 | pts = np.array([(0, 0), (4, 0), (3, 3)])
73 | rads = np.array([1, 0.5, 0.5])
74 |
75 | simps = [None, np.array([[0, 1, 2]])]
76 | for simp in simps:
77 | x, y, rad = _misc.tangent_sphere(pts, rads, simplices=simp)
78 | cen = np.array([x, y])
79 |
80 | rel_pos = pts - cen
81 | dist = np.sqrt(np.sum(rel_pos * rel_pos, axis=-1))
82 | assert np.all(np.isclose(dist, rads + rad))
83 |
84 |
85 | def test_tangent_sphere_ND():
86 | n = 7
87 | np.random.seed(0)
88 | pts = np.random.rand(n + 1, n)
89 | nsphere = _misc.tangent_sphere(pts)
90 | cen = nsphere[:-1]
91 | rad = nsphere[-1]
92 |
93 | rel_pos = pts - cen
94 | dist = np.sqrt(np.sum(rel_pos * rel_pos, axis=-1))
95 | assert np.all(np.isclose(dist, rad))
96 |
--------------------------------------------------------------------------------
/tox.ini:
--------------------------------------------------------------------------------
1 | # tox (https://tox.readthedocs.io/) is a tool for running tests
2 | # in multiple virtualenvs. This configuration file will run the
3 | # test suite on all supported python versions. To use it, "pip install tox"
4 | # and then run "tox" from this directory.
5 |
6 | [tox]
7 | envlist = clean,
8 | check,
9 | py36,
10 | py37
11 | docs
12 |
13 | [testenv]
14 | deps = pytest
15 | -rrequirements.txt
16 | setenv = MPLBACKEND = agg
17 | commands =
18 | pytest
19 |
20 | [testenv:cov]
21 | deps = pytest
22 | pytest-cov
23 | basepython = python3.6
24 | usedevelop = True
25 | setenv = MPLBACKEND = agg
26 | commands =
27 | pytest --cov src/microstructpy --cov-report=html --cov-branch
28 |
29 | [testenv:check]
30 | deps = docutils
31 | check-manifest
32 | flake8
33 | readme-renderer
34 | pygments
35 | isort
36 | twine
37 | readme_renderer[md]
38 | skip_install = true
39 | commands = python setup.py sdist check --strict --metadata
40 | check-manifest {toxinidir}
41 | flake8 src tests setup.py --exclude=__init__.py
42 | isort --verbose --check-only --diff src tests setup.py
43 | twine check dist/*
44 |
45 | [testenv:docs]
46 | deps = -rdocs/requirements.txt
47 | basepython = python3.6
48 | commands = sphinx-build docs/source/ docs/build/
49 |
50 |
51 | [testenv:docs-dev]
52 | deps = -rdocs/requirements.txt
53 | basepython = python3.6
54 | commands = sphinx-build -Wn docs/source/ docs/build/
55 | sphinx-build -b latex docs/source/ docs/build-pdf/
56 | sphinx-build -b epub docs/source/ docs/build-epub/
57 |
58 | [testenv:clean]
59 | deps = coverage
60 | skip_install = true
61 | commands = coverage erase
62 |
--------------------------------------------------------------------------------