Skip to content

Commit

Permalink
Merge 3a8dbd6 into 50c8558
Browse files Browse the repository at this point in the history
  • Loading branch information
mcflugen committed Feb 19, 2020
2 parents 50c8558 + 3a8dbd6 commit bd21dd5
Show file tree
Hide file tree
Showing 2 changed files with 193 additions and 20 deletions.
126 changes: 114 additions & 12 deletions compaction/cli.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,23 @@
import pathlib
import sys
from functools import partial
from io import StringIO
from typing import Optional, TextIO

import click
import numpy as np # type: ignore
import pandas # type: ignore
import yaml

from ._version import get_versions
from .compaction import compact
from .compaction import compact as _compact

__version__ = get_versions()["version"]
del get_versions

out = partial(click.secho, bold=True, err=True)
err = partial(click.secho, fg="red", err=True)


def load_config(file: Optional[TextIO] = None):
"""Load compaction config file.
Expand All @@ -34,45 +41,140 @@ def load_config(file: Optional[TextIO] = None):
"rho_void": 1000.0,
}
if file is not None:
conf.update(yaml.load(file))
conf.update(yaml.safe_load(file))
return conf


def _contents_of_input_file(infile: str) -> str:
params = load_config()

def as_csv(data, header=None):
with StringIO() as fp:
np.savetxt(fp, data, header=header, delimiter=",", fmt="%.1f")
contents = fp.getvalue()
return contents

contents = {
"config": yaml.dump(params, default_flow_style=False),
"porosity": as_csv(
[[1.0, 0.4], [1.0, 0.4], [1.0, 0.2]],
header="Layer Thickness [m], Porosity [-]",
),
}

return contents[infile]


def run_compaction(
src: Optional[TextIO] = None, dest: Optional[TextIO] = None, **kwds
) -> None:
src = src or sys.stdin
dest = dest or sys.stdout

init = pandas.read_csv(src, names=("dz", "porosity"), dtype=float)
init = pandas.read_csv(src, names=("dz", "porosity"), dtype=float, comment="#")

porosity_new = compact(init.dz.values, init.porosity.values, **kwds)
porosity_new = _compact(init.dz.values, init.porosity.values, **kwds)

dz_new = init.dz * (1 - init.porosity) / (1 - porosity_new)

out = pandas.DataFrame.from_dict({"dz": dz_new, "porosity": porosity_new})
out.to_csv(dest, index=False, header=False)


@click.command()
@click.group()
@click.version_option()
def compact() -> None:
"""Compact layers of sediment.
\b
Examples:
Create a folder with example input files,
$ compact setup compact-example
Run a simulation using the examples input files,
$ compact run compact-example/porosity.csv
"""
pass


@compact.command()
@click.version_option(version=__version__)
@click.option("-v", "--verbose", is_flag=True, help="Emit status messages to stderr.")
@click.option("--dry-run", is_flag=True, help="Do not actually run the model")
# @click.option(
# "--config", default="config.yaml", type=click.File(mode="r"), help="Configuration file"
# )
@click.option(
"--config", default=None, type=click.File(mode="r"), help="Configuration file"
"--config",
type=click.Path(
exists=False, file_okay=True, dir_okay=False, readable=True, allow_dash=False
),
default="config.yaml",
is_eager=True,
help="Read configuration from PATH.",
)
@click.argument("src", type=click.File(mode="r"))
@click.argument("dest", default="-", type=click.File(mode="w"))
def main(src: TextIO, dest: TextIO, config: TextIO, dry_run: bool, verbose: bool):
# @click.argument("dest", type=click.File(mode="w"))
def run(src: TextIO, dest: TextIO, config: str, dry_run: bool, verbose: bool) -> None:
"""Run a simulation."""
config_path = pathlib.Path(config)
if src.name is "<stdin>":
rundir = pathlib.Path(".")
else:
rundir = pathlib.Path(src.name).parent.resolve()

with open(rundir / config_path, "r") as fp:
params = load_config(fp)

params = load_config(config)
if verbose:
click.secho(yaml.dump(params, default_flow_style=False), err=True)
out(yaml.dump(params, default_flow_style=False))

if dry_run:
click.secho("Nothing to do. 😴", err=True, fg="green")
out("Nothing to do. 😴")
else:
run_compaction(src, dest, **params)

click.secho("💥 Finished! 💥", err=True, fg="green")
click.secho("Output written to {0}".format(dest.name), err=True, fg="green")
out("💥 Finished! 💥")
out("Output written to {0}".format(dest.name))

sys.exit(0)


@compact.command()
@click.argument(
"infile",
type=click.Choice(["config", "porosity"]),
)
def show(infile: str) -> None:
"""Show example input files."""
print(_contents_of_input_file(infile))


@compact.command()
@click.argument(
"dest",
type=click.Path(exists=True, file_okay=False, dir_okay=True, readable=True),
)
def setup(dest: str) -> None:
"""Setup a folder of input files for a simulation."""
folder = pathlib.Path(dest)

files = [pathlib.Path(fname) for fname in ["porosity.csv", "config.yaml"]]

existing_files = [folder / name for name in files if (folder / name).exists()]
if existing_files:
for name in existing_files:
err(
f"{name}: File exists. Either remove and then rerun or choose a different destination folder",
)
else:
for fname in files:
with open(folder / fname, "w") as fp:
print(_contents_of_input_file(fname.stem), file=fp)
print(str(folder /"porosity.csv"))

sys.exit(len(existing_files))
87 changes: 79 additions & 8 deletions tests/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

import pandas # type: ignore
import pytest # type: ignore
import numpy as np # type: ignore
import yaml
from click.testing import CliRunner
from numpy.testing import assert_array_almost_equal # type: ignore
Expand All @@ -29,10 +30,10 @@ def test_content(response):
def test_command_line_interface():
"""Test the CLI."""
runner = CliRunner()
result = runner.invoke(cli.main, ["--help"])
result = runner.invoke(cli.compact, ["--help"])
assert result.exit_code == 0

result = runner.invoke(cli.main, ["--version"])
result = runner.invoke(cli.compact, ["--version"])
assert result.exit_code == 0
assert "version" in result.output

Expand All @@ -41,7 +42,7 @@ def test_dry_run(tmpdir, datadir):
with tmpdir.as_cwd():
runner = CliRunner()
result = runner.invoke(
cli.main,
cli.run,
[
"--dry-run",
"--config={0}".format(datadir / "config.yaml"),
Expand All @@ -58,7 +59,7 @@ def test_verbose(tmpdir, datadir):
with tmpdir.as_cwd():
runner = CliRunner()
result = runner.invoke(
cli.main,
cli.run,
[
"--verbose",
"--config={0}".format(datadir / "config.yaml"),
Expand All @@ -69,7 +70,7 @@ def test_verbose(tmpdir, datadir):
assert result.exit_code == 0
assert (tmpdir / "out.txt").exists()

conf = yaml.load(os.linesep.join(result.output.splitlines()[:5]))
conf = yaml.safe_load(os.linesep.join(result.output.splitlines()[:5]))
assert isinstance(conf, dict)


Expand All @@ -79,9 +80,9 @@ def test_constant_porosity(tmpdir, datadir):
)
phi_expected = compact(data["dz"], data["porosity"], porosity_max=0.6)
with tmpdir.as_cwd():
runner = CliRunner()
runner = CliRunner(mix_stderr=False)
result = runner.invoke(
cli.main,
cli.run,
[
"--config={0}".format(datadir / "config.yaml"),
str(datadir / "porosity_profile.txt"),
Expand All @@ -90,7 +91,77 @@ def test_constant_porosity(tmpdir, datadir):
)

assert result.exit_code == 0
assert "Output written to out.txt" in result.output
assert "Output written to out.txt" in result.stderr
phi_actual = pandas.read_csv("out.txt", names=("dz", "porosity"), dtype=float)

assert_array_almost_equal(phi_actual["porosity"], phi_expected)


def test_setup(tmpdir):
with tmpdir.as_cwd():
runner = CliRunner()
result = runner.invoke(cli.setup, ["."])

assert result.exit_code == 0
assert (tmpdir / "config.yaml").exists()
assert (tmpdir / "porosity.csv").exists()


@pytest.mark.parametrize(
"files", (("config.yaml",), ("porosity.csv",), ("config.yaml", "porosity.csv"))
)
def test_setup_with_existing_files(tmpdir, files):
runner = CliRunner(mix_stderr=False)
with tmpdir.as_cwd():
for name in files:
with open(name, "w") as fp:
pass

result = runner.invoke(cli.setup, ["."])

assert result.exit_code == len(files)
assert result.stdout == ""
for name in files:
assert name in result.stderr


def test_show(tmpdir):
with tmpdir.as_cwd():
result = CliRunner(mix_stderr=False).invoke(cli.show, ["config"])
with open("config.yaml", "w") as fp:
fp.write(result.stdout)

result = CliRunner(mix_stderr=False).invoke(cli.show, ["porosity"])
with open("porosity.csv", "w") as fp:
fp.write(result.stdout)

result = CliRunner(mix_stderr=False).invoke(cli.run, ["porosity.csv", "out.csv"])

assert (tmpdir / "out.csv").exists()
assert result.exit_code == 0


def test_show_config(tmpdir):
runner = CliRunner(mix_stderr=False)
result = runner.invoke(cli.show, ["config"])

assert result.exit_code == 0

params = yaml.safe_load(result.stdout)
assert isinstance(params, dict)


def test_show_porosity(tmpdir):
runner = CliRunner(mix_stderr=False)
result = runner.invoke(cli.show, ["porosity"])

assert result.exit_code == 0

with open(tmpdir / "porosity.csv", "w") as fp:
fp.write(result.stdout)

data = pandas.read_csv(
tmpdir / "porosity.csv", names=("dz", "porosity"), dtype=float, comment="#"
)
assert np.all(data.dz.values > 0.0)
assert np.all(data.porosity.values >= 0.0)

0 comments on commit bd21dd5

Please sign in to comment.