Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Docs #29

Merged
merged 23 commits into from
Aug 2, 2024
Merged

Docs #29

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion doc/dev_workflow.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Dev Workflow

*Work in progress.*

## Configuration

* GitHub CLI https://cli.github.com
Expand All @@ -8,13 +10,23 @@
* Install Python
* TODO Python color debugger: https://github.com/mdmintz/pdbp
* Install Rust
* Python virtual environmen
* Python virtual environment
* Code check out

## Development Cycle

* Branch
* Develop
* `cargo build`
* develop tests
* develop implementation
* test:
* `cargo test`
* `cargo run` // test without required input and output flags
* `cargo run --release -- -i tests/input/f.npy -o foo.exo`
* `cargo run -- --help`
* precommit: `pre-commit run --all-files`
* `cargo doc --open`
* Test
* `maturin develop --release --features python`
* Merge request
29 changes: 29 additions & 0 deletions doc/encrypted.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Encrypted

We create an encrypted `.npy` file for the sake of testing. We wish to test the case where the `.npy` file exists, it can be found, but it cannot be opened.

```bash
from cryptography.fernet import Fernet
import numpy as np

# Generate a key for encryption
key = Fernet.generate_key()
cipher_suite = Fernet(key)

# Create a valid .npy file
data = np.array([1, 2, 3, 4, 5])
np.save('valid.npy', data)

# Read the file content
with open('valid.npy', 'rb') as f:
file_data = f.read()

# Encrypt the file content
encrypted_data = cipher_suite.encrypt(file_data)

# Write the encrypted data to a new file
with open('encrypted.npy', 'wb') as f:
f.write(encrypted_data)

print(f"Encryption key: {key.decode()}")
```
Binary file added doc/fig/letter_f_spn_annotated.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/fig/letter_f_voxel.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
118 changes: 107 additions & 11 deletions doc/logs.md
Original file line number Diff line number Diff line change
@@ -1,19 +1,33 @@
# logs

**Goal:** A command line Rust application that takes a command line argument, the path to a `.yml` file, and represents that yaml data as an internal yaml struct.

*In order of most recent to least recent.*

## 2024-08-07

## 2024-07-31

* Candice would like a Work Planning Agreement (WPA)
* Tutorial: How to update the exo branch, which is currently 12 commits behind and 10 commits ahead of the main branch.
* Module load mechanism on HPC, via SMT > Utility > PythonModule > Deployer
* Tutorial: Outline of a complete [development workflow](dev_workflow.md)
### For next week

* CBH
* yaml input/ouput
* tilde bug
* MRB
* clap
* exodus with node numbering (and numbering gaps)
* exodus connectivity

### This week

- [ ] CFC would like a Work Planning Agreement (WPA)
- [x] Tutorial: How to update the exo branch, which is currently 12 commits behind and 10 commits ahead of the main branch.
- [ ] Module load mechanism on HPC, via SMT > Utility > PythonModule > Deployer
- [x] Tutorial: Outline of a complete [development workflow](dev_workflow.md)
* Configuration - especially a Python virtual environment
* Is there a virtual environment equivalent for Rust?
* Q: Is there a virtual environment equivalent for Rust? A: Nope, not necessary.
* Check in and review
* Code Review: Minimum working example: https://github.com/hovey/rustschool/tree/main/yml_io
- [x] Code Review: Minimum working example: https://github.com/hovey/rustschool/tree/main/yml_io
* can we have `main.rs` and `lib.rs` (???), so how to architect if we want both a library and a command line tool?
* yamlio or ymlio be in `lib.rs` equivalent
* `eprintln!`
Expand All @@ -36,12 +50,22 @@
* uses serde_yaml and yaml_rust
* yaml = "0.1"
* downloads 24,016
* clap: https://github.com/clap-rs/clap
- [x] clap: https://github.com/clap-rs/clap
* `cargo run - --help`, `cargo run recipe.yml`
* clap alternatives: quicli, structopt
* Code Review: continuation from last week, especially node numbering with gaps
* [done] Questions for MRB
- [x] * clap alternatives: quicli, structopt
- [ ] Code Review: continuation from last week, especially node numbering with gaps
- [x] Questions for MRB
* in `/tests/` folder, the `test_utility.py` has the `test_` prefix so that it is picked up by the `pytest` module. In that same folder, `npy.py` and `spn.py` have tests, and therein has function definitions with the leading `test_foo` format, but the filenames themselves do not have the `test_` prefix.
- [x] Deployment
* [crates.io](https://crates.io)
* [rust binary](https://crates.io/crates/automesh)
* rust library
* [PyPI](https://pypi.org)
* [Python wheel](https://pypi.org/project/automesh/)
- [x] Decisions
* not require `test_` prefix (as done with Python) for names of Rust test files
* tell python testing to look at `.py` files in the `tests/` folders, as shown below from the [`pyproject.toml`](../pyproject.toml)
* stop using `pip install -e .` and instead, use Maturin, which will build the Python wheel (`maturin develop --release --features python`) and then use code from the wheel

```bash
[tool.pytest.ini_options]
Expand Down Expand Up @@ -102,7 +126,79 @@ Failed to build automesh
ERROR: ERROR: Failed to build installable wheels for some pyproject.toml based projects (automesh)
```

**Goal:** A command line Rust application that takes a command line argument, the path to a .yml file, and represents that yaml data as an internal yaml struct.
### MRB accomplishments

* I added clap as a dependency and set up a main.rs to run automesh as a binary, i.e.,
`cargo run --release -- -i tests/input/f.npy -o foo.exo`
it automatically changes methods based on IO file extensions, and it fails for now (we don’t have anything that writes exodus files yet)
* I moved the functionality of the NPY type into the SPN type after realizing that the internal data was essentially the same. Meaning the methods in NPY that read `.npy` files just converted it into SPN equivalent data anyway. So now SPN types can be created from `.spn` or `.npy` files.
* I added the functionality that renumbers the nodes to avoid gaps, I’m pretty sure it’s working. Itertools is now a dependency so I could use `.unique()`
* Still no nodal coordinates yet, will work on next.

### Where do the different editable installs originate?

```bash
cd ~/autotwin/mesh
source .venv/bin/activate.fish

pip list
Package Version Editable project location
--------------- ----------- ---------------------------
atmesh 0.0.7 /Users/chovey/autotwin/mesh
...
numpy 1.26.4

python

import atmesh
print(atmesh)
<module 'atmesh' from '/Users/chovey/autotwin/mesh/src/atmesh/__init__.py'>

import numpy
print(numpy)
<module 'numpy' from '/Users/chovey/autotwin/mesh/.venv/lib/python3.11/site-packages/numpy/__init__.py'>

quit()

deactivate

cd ~/autotwin/automesh
source .venv/bin/activate.fish

pip list
Package Version Editable project location
------------ ------- -------------------------------
automesh 0.1.3 /Users/chovey/autotwin/automesh
...
numpy 2.0.0

python

import automesh
print(automesh)
<module 'automesh' from '/Users/chovey/autotwin/automesh/.venv/lib/python3.11/site-packages/automesh/__init__.py'>

print(numpy)
module 'numpy' from '/Users/chovey/autotwin/automesh/.venv/lib/python3.11/site-packages/numpy/__init__.py'>

quit()
```

### CBH accomplishments

* documentation
* error handling

### Continued discussion (2024-08-02)

* Decisions:
* command line arguments (via clap) is prioritized; `.yml` file recipie is paused in favor of CLI interacion
* command line runs produce a `.log` file by default (optional is to have no logging, command line flag for no logging is to be determined), the `.log` file will
* echo the command issued to the CLI (support reproducibility)
* have a name `<output_file>.log` that matches the file name of the output Exodus file `<output_file>.exo`
* the contents of the `.log` file will also be echoed to the screen (stdout) during the run and capture any errors (stderr) if they are encountered
* command line interface to be expanded to specify `nelx`, `nely`, and `nelz` (and have error checking to assure that `nelx x nely x nelz = n_voxels`)
* CLI to be expanded to consume two types of input files: `.npy` and `.spn`.

## 2024-07-24

Expand Down
85 changes: 85 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,89 @@
//! Automatic mesh generation.
//!
//! This program converts a segmentation to a finite element mesh.
//!
//! * The segmentation is composed of non-negative integers of type `uint8`
//! saved to a binary file in [NumPy](https://numpy.org) `.npy` format.
//! * The segmentation can be either a semantic segmentation or an instance
//! segmentation.
//! * A semantic segmentation classifies each pixel in an image
//! to as belonging to a specific class (or category). For example, an image
//! containing three dogs will contain two classes: `dog` and `background`.
//! * An instance segmentation goes beyond semantic segmentation,
//! classifying pixels not only by class, but also but instance. Unlike
//! semantic segmentation, image segmentation can classify individual instances
//! of object of the same class. For example, an image containing three dogs
//! will contain four classes: `dog_1`, `dog_2`, `dog_3`, and `background`.
//! * The finite element mesh is saved as an Exodus finite element mesh file
//! in `.exo` format.
//!
//! # Example:
//!
//! ## Step 1
//!
//! In Python, create a 3D "letter F" with an endcap as a 3D voxelated domain.
//! Save the domain, a simple two-material semantic segmentation, as a NumPy file.
//! The integer `0` is used to denote `void` (e.g., air). The integer `1` is
//! used to denote `solid`.
//!
//! ```Python
//! import numpy as np
//!
//! # Step 1a: Create a NumPy array
//! letter_f = np.array(
//! [[[1, 1, 1],
//! [1, 1, 1],
//! [1, 1, 1],
//! [1, 1, 1],
//! [1, 1, 1]],
//!
//! [[1, 1, 1],
//! [1, 0, 0],
//! [1, 1, 0],
//! [1, 0, 0],
//! [1, 0, 0]],
//!
//! [[1, 1, 1],
//! [1, 0, 0],
//! [1, 1, 0],
//! [1, 0, 0],
//! [1, 0, 0]],
//!
//! [[1, 1, 1],
//! [1, 0, 0],
//! [1, 1, 0],
//! [1, 0, 0],
//! [1, 0, 0]]], dtype=np.uint8)
//!
//! # Step 1b: Save the array to a .npy file
//! np.save('letter_f.npy', letter_f)
//! ```
//!
//! ![letter F voxel](../../../doc/fig/letter_f_voxel.png)
//!
//! ## Step 2
//! On the command line, convert the `.npy` file to an `.exo` file.
//!
//! ```bash
//! automesh --input letter_f.npy --output letter_f.exo
//! ```
//!
//! The program also works directly on `.spn files`, e.g.,
//!
//! ```bash
//! # TODO: work in progress
//! automesh --input letter_f.spn -nx 3 -ny 5 -nz 4 --output letter_f.exo
//! ```
//!
//! with the default `z`, `y`, `x` ordering.
//!
//! # See Also
//!
//! The automesh online help:
//!
//! ```bash
//! automesh --help
//! ```

#[cfg(feature = "python")]
mod py;
Expand Down
8 changes: 4 additions & 4 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
use automesh::Spn;
use clap::Parser;

#[derive(Parser, Debug)]
#[command(version, about, long_about = None)]
#[derive(Parser)]
#[command(about, arg_required_else_help = true, long_about = None, version)]
struct Args {
/// Name of the input file.
/// Name of the NumPy input file. Example: --input <input_file>.npy (TODO: work in progress <input_file>.spn)
#[arg(short, long)]
input: String,

/// Name of the output file.
/// Name of the Exodus output file. Example: --output <output_file>.exo
#[arg(short, long)]
output: String,
}
Expand Down
Loading
Loading