Skip to content

Commit

Permalink
filename instead of folder/label in TXTExport
Browse files Browse the repository at this point in the history
  • Loading branch information
KulaginVladimir committed Jan 13, 2024
1 parent 375fb16 commit 7c6ca17
Show file tree
Hide file tree
Showing 7 changed files with 118 additions and 42 deletions.
56 changes: 35 additions & 21 deletions festim/exports/txt_export.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,33 +9,39 @@

class TXTExport(festim.Export):
"""
Args:
field (str): the exported field ("solute", "1", "retention",
"T"...)
label (str): label of the field. Will also be the filename.
folder (str): the export folder
filename (str): the filename (must end with .txt).
times (list, optional): if provided, the field will be
exported at these timesteps. Otherwise exports at all
timesteps. Defaults to None.
header_format (str, optional): the format of column headers.
Defautls to ".2e".
"""

def __init__(self, field, label, folder, times=None, header_format=".2e") -> None:
def __init__(self, field, filename, times=None, header_format=".2e") -> None:
super().__init__(field=field)
if times:
self.times = sorted(times)
else:
self.times = times
self.label = label
self.folder = folder
self.filename = filename
self.header_format = header_format
self._first_time = True

@property
def filename(self):
return f"{self.folder}/{self.label}.txt"
return self._filename

@filename.setter
def filename(self, value):
if value is not None:
if not isinstance(value, str):
raise TypeError("filename must be a string")
if not value.endswith(".txt"):
raise ValueError("filename must end with .txt")
self._filename = value

def is_it_time_to_export(self, current_time):
if self.times is None:
Expand All @@ -60,11 +66,6 @@ def write(self, current_time, steady):
solution = f.project(self.function, V_DG1)
solution_column = np.transpose(solution.vector()[:])
if self.is_it_time_to_export(current_time):
if steady:
header = "x,t=steady"
else:
header = f"x,t={format(current_time, self.header_format)}s"

# if the directory doesn't exist
# create it
dirname = os.path.dirname(self.filename)
Expand All @@ -75,6 +76,10 @@ def write(self, current_time, steady):
# write data
# else append new column to the existing file
if steady or self._first_time:
if steady:
header = "x,t=steady"
else:
header = f"x,t={format(current_time, self.header_format)}s"
x = f.interpolate(f.Expression("x[0]", degree=1), V_DG1)
x_column = np.transpose([x.vector()[:]])
data = np.column_stack([x_column, solution_column])
Expand All @@ -93,27 +98,36 @@ def write(self, current_time, steady):


class TXTExports:
"""
Args:
fields (list): list of exported fields ("solute", "1", "retention",
"T"...)
filenames (list): list of the filenames for each field (must end with .txt).
times (list, optional): if provided, fields will be
exported at these timesteps. Otherwise exports at all
timesteps. Defaults to None.
header_format (str, optional): the format of column headers.
Defautls to ".2e".
"""

def __init__(
self, fields=[], labels=[], times=None, folder=None, header_format=".2e"
self, fields=[], filenames=[], times=None, header_format=".2e"
) -> None:
msg = "TXTExports class will be depricated in future versions of FESTIM"
warnings.warn(msg, DeprecationWarning)

self.fields = fields
if len(self.fields) != len(labels):
if len(self.fields) != len(filenames):
raise ValueError(
"Number of fields to be exported "
"doesn't match number of labels in txt exports"
"doesn't match number of filenames in txt exports"
)
if times:
self.times = sorted(times)
else:
self.times = times
self.labels = labels
self.folder = folder
self.filenames = filenames
self.header_format = header_format
self.exports = []
for function, label in zip(self.fields, self.labels):
self.exports.append(
TXTExport(function, label, folder, times, header_format)
)
for function, filename in zip(self.fields, self.filenames):
self.exports.append(TXTExport(function, filename, times, header_format))
32 changes: 32 additions & 0 deletions test/simulation/test_initialise.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import festim as F
from pathlib import Path


def test_initialise_changes_nb_of_sources():
Expand Down Expand Up @@ -71,3 +72,34 @@ def test_initialise_initialise_dt():

# test
assert my_model.dt.value(2) == 3


def test_TXTExport_times_added_to_milestones(tmpdir):
"""Creates a Simulation object and checks that, if no dt.milestones
are given and TXTExport.times are given, TXTExport.times are
are added to dt.milestones by .initialise()
"""
# tmpdir
d = tmpdir.mkdir("test_folder")

# build
my_model = F.Simulation()
my_model.mesh = F.MeshFromVertices([1, 2, 3])
my_model.materials = F.Material(id=1, D_0=1, E_D=0, thermal_cond=1)
my_model.T = F.Temperature(100)
my_model.dt = F.Stepsize(initial_value=3)
my_model.settings = F.Settings(
absolute_tolerance=1e-10, relative_tolerance=1e-10, final_time=4
)
txt_export = F.TXTExport(
field="solute",
filename="{}/solute_label.txt".format(str(Path(d))),
times=[1, 2, 3],
)
my_model.exports = [txt_export]

# run
my_model.initialise()

# test
assert my_model.dt.milestones == txt_export.times
2 changes: 1 addition & 1 deletion test/system/test_chemical_potential.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ def run(h):
my_exports = festim.Exports(
[
festim.TXTExport(
"solute", times=[100], label="solute", folder=str(Path(d))
"solute", times=[100], filename="{}/solute.txt".format(str(Path(d)))
),
]
)
Expand Down
18 changes: 9 additions & 9 deletions test/system/test_misc.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,17 +134,17 @@ def test_txt_export_desired_times(tmp_path):
my_model.dt = F.Stepsize(0.1)

my_export = F.TXTExport(
"solute", label="mobile_conc", times=[0.2, 0.5], folder=tmp_path
"solute", times=[0.2, 0.5], filename="{}/mobile_conc.txt".format(tmp_path)
)
my_model.exports = [my_export]

my_model.initialise()
my_model.run()

assert os.path.exists("{}/{}.txt".format(my_export.folder, my_export.label))
assert os.path.exists(my_export.filename)

data = np.genfromtxt(
"{}/{}.txt".format(my_export.folder, my_export.label),
my_export.filename,
skip_header=1,
delimiter=",",
)
Expand All @@ -163,16 +163,16 @@ def test_txt_export_all_times(tmp_path):
my_model.T = F.Temperature(500)
my_model.dt = F.Stepsize(0.1)

my_export = F.TXTExport("solute", label="mobile_conc", folder=tmp_path)
my_export = F.TXTExport("solute", filename="{}/mobile_conc.txt".format(tmp_path))
my_model.exports = [my_export]

my_model.initialise()
my_model.run()

assert os.path.exists("{}/{}.txt".format(my_export.folder, my_export.label))
assert os.path.exists(my_export.filename)

data = np.genfromtxt(
"{}/{}.txt".format(my_export.folder, my_export.label),
my_export.filename,
skip_header=1,
delimiter=",",
)
Expand All @@ -190,15 +190,15 @@ def test_txt_export_steady_state(tmp_path):
my_model.settings = F.Settings(1e-10, 1e-10, transient=False)
my_model.T = F.Temperature(500)

my_export = F.TXTExport("solute", label="mobile_conc", folder=tmp_path)
my_export = F.TXTExport("solute", filename="{}/mobile_conc.txt".format(tmp_path))
my_model.exports = [my_export]

my_model.initialise()
my_model.run()

assert os.path.exists("{}/{}.txt".format(my_export.folder, my_export.label))
assert os.path.exists(my_export.filename)

txt = open("{}/{}.txt".format(my_export.folder, my_export.label))
txt = open(my_export.filename)
header = txt.readline().rstrip()
txt.close()

Expand Down
2 changes: 1 addition & 1 deletion test/system/test_system.py
Original file line number Diff line number Diff line change
Expand Up @@ -344,7 +344,7 @@ def run(h):
my_exports = festim.Exports(
[
festim.TXTExport(
"solute", times=[100], label="solute", folder=str(Path(d))
"solute", times=[100], filename="{}/solute.txt".format(str(Path(d)))
),
]
)
Expand Down
41 changes: 33 additions & 8 deletions test/unit/test_exports/test_txt_export.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,11 @@ def function_subspace(self):
@pytest.fixture
def my_export(self, tmpdir):
d = tmpdir.mkdir("test_folder")
my_export = TXTExport("solute", "solute_label", str(Path(d)), times=[1, 2, 3])
my_export = TXTExport(
"solute",
times=[1, 2, 3],
filename="{}/solute_label.txt".format(str(Path(d))),
)

return my_export

Expand All @@ -34,37 +38,54 @@ def test_file_exists(self, my_export, function):
my_export.function = function
my_export.write(current_time=current_time, steady=False)

assert os.path.exists("{}/{}.txt".format(my_export.folder, my_export.label))
assert os.path.exists(my_export.filename)

def test_file_doesnt_exist(self, my_export, function):
current_time = 10
my_export.function = function
my_export.write(current_time=current_time, steady=False)

assert not os.path.exists("{}/{}.txt".format(my_export.folder, my_export.label))
assert not os.path.exists(my_export.filename)

def test_create_folder(self, my_export, function):
"""Checks that write() creates the folder if it doesn't exist"""
current_time = 1
my_export.function = function
my_export.folder += "/folder2"
slash_indx = my_export.filename.rfind("/")
my_export.filename = (
my_export.filename[:slash_indx]
+ "/folder2"
+ my_export.filename[slash_indx:]
)
my_export.write(current_time=current_time, steady=False)

assert os.path.exists("{}/{}.txt".format(my_export.folder, my_export.label))
assert os.path.exists(my_export.filename)

def test_subspace(self, my_export, function_subspace):
current_time = 1
my_export.function = function_subspace
my_export.write(current_time=current_time, steady=False)

assert os.path.exists("{}/{}.txt".format(my_export.folder, my_export.label))
assert os.path.exists(my_export.filename)

def test_error_filename_endswith_txt(self, my_export):
with pytest.raises(ValueError, match="filename must end with .txt"):
my_export.filename = "coucou"

def test_error_filename_not_a_str(self, my_export):
with pytest.raises(TypeError, match="filename must be a string"):
my_export.filename = 2


class TestIsItTimeToExport:
@pytest.fixture
def my_export(self, tmpdir):
d = tmpdir.mkdir("test_folder")
my_export = TXTExport("solute", "solute_label", str(Path(d)), times=[1, 2, 3])
my_export = TXTExport(
"solute",
times=[1, 2, 3],
filename="{}/solute_label.txt".format(str(Path(d))),
)

return my_export

Expand All @@ -84,7 +105,11 @@ class TestWhenIsNextTime:
@pytest.fixture
def my_export(self, tmpdir):
d = tmpdir.mkdir("test_folder")
my_export = TXTExport("solute", "solute_label", str(Path(d)), times=[1, 2, 3])
my_export = TXTExport(
"solute",
times=[1, 2, 3],
filename="{}/solute_label.txt".format(str(Path(d))),
)

return my_export

Expand Down
9 changes: 7 additions & 2 deletions test/unit/test_exports/test_txt_exports.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,12 @@ class TestWrite:
def my_export(self, tmpdir, request):
d = tmpdir.mkdir("test_folder")
my_export = TXTExports(
["solute", "T"], ["solute_label", "T_label"], request.param, str(Path(d))
fields=["solute", "T"],
filenames=[
"{}/solute_label.txt".format(str(Path(d))),
"{}/T_label.txt".format(str(Path(d))),
],
times=request.param,
)

return my_export
Expand All @@ -22,4 +27,4 @@ def test_txt_exports_times(self, my_export):

def test_error_when_fields_and_labels_have_different_lengths():
with pytest.raises(ValueError, match="Number of fields to be exported"):
TXTExports(["solute", "T"], ["solute_label"], [1])
TXTExports(["solute", "T"], ["solute_label.txt"], [1])

0 comments on commit 7c6ca17

Please sign in to comment.