Skip to content

Commit

Permalink
preparing for v 0.1.1
Browse files Browse the repository at this point in the history
  • Loading branch information
ducarme committed Feb 12, 2025
1 parent 5a6bcb9 commit aecbe31
Show file tree
Hide file tree
Showing 17 changed files with 130 additions and 16 deletions.
4 changes: 3 additions & 1 deletion MANIFEST.in
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
exclude src/springable/optimization.py
exclude src/springable/optimization.py
include src/springable/examples-spring-model-CSV-files/*.csv
include src/springable/gallery-spring-model-CSV-files/*.csv
2 changes: 1 addition & 1 deletion default_graphics_settings.toml
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ line_spring_default_color = "#cecece"
distance_spring_line_linewidth = 1.0
distance_spring_line_default_color = "#cecece"
distance_spring_line_default_opacity = 0.7
node_style = "elegant" # "basic", "elegant"
node_style = "basic" # "basic", "elegant"
node_size = 3
node_color = "#101010"
show_node_numbers = false
Expand Down
6 changes: 5 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ requires = ["setuptools>=61.0"]
build-backend = "setuptools.build_meta"

[project]
name = "springable"
name = "springable-test"
version = "0.1.1"
authors = [
{name="Paul Ducarme"},
Expand All @@ -28,6 +28,10 @@ classifiers = [
]
keywords = ["nonlinear", "spring", "simulation", "animation", "instability", "snap-through"]

[too.setuptools]
include-package-data = true # is true by default for setuptools v >= 61.0.0
# the

[tool.setuptools.packages.find]
where = ["src"]
exclude = ["springable.dynamics"]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@ NODES
0, 0.0, 0.0, 1, 1
1, 1.0, 0.0, 0, 1
SPRINGS
0-1, PIECEWISE(a=[stiffness0;stiffness1;stiffness2];x=[critical_displacement_loading; critical_displacement_unloading];delta=0.1)
0-1, PIECEWISE(k_i=[stiffness0;stiffness1;stiffness2];u_i=[critical_displacement_loading; critical_displacement_unloading];us=0.1)
LOADING
1, X, 2.50
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@ NODES
0, 0.0, 0.0, 1, 1
1, 1.0, 0.0, 0, 1
SPRINGS
0-1, PIECEWISE(a=[initial_stiffness;final_stiffness];x=[transition_displacement];delta=0.2)
0-1, PIECEWISE(k_i=[initial_stiffness;final_stiffness];u_i=[transition_displacement];us=0.2)
LOADING
1, X, 2.50
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@ NODES
0, 0.0, 0.0, 1, 1
1, 1.0, 0.0, 0, 1
SPRINGS
0-1, PIECEWISE(a=[initial_stiffness;final_stiffness];x=[transition_displacement];delta=0.2)
0-1, PIECEWISE(k_i=[initial_stiffness;final_stiffness];u_i=[transition_displacement];us=0.2)
LOADING
1, X, 2.50
20 changes: 20 additions & 0 deletions src/gallery-spring-model-CSV-files/von_mises_truss.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
PARAMETERS
width, 8.0
triangle_height, 3.0
vertical_element_length, 8.0
triangle_side_stiffness, 9.0
vertical_element_stiffness, 1.4, [1;2.5;4]
hinge_stiffness, 7.5
NODES
0,0.0,0.0,1,1
1,width/2,triangle_height,1,0
2,width,0.0,1,1
3,width/2,triangle_height + vertical_element_length,1,0
SPRINGS
1-2,triangle_side_stiffness
1-0,triangle_side_stiffness
1-3,vertical_element_stiffness
ROTATION SPRINGS
0-1-2, hinge_stiffness
LOADING
3, Y, -7.5
65 changes: 65 additions & 0 deletions src/springable/discover.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
from .simulation import simulate_model
from .readwrite import fileio
import os


def show_examples(filename=None):
save_dir = fileio.mkdir('examples_results')
folder = os.path.join('src', 'examples-spring-model-CSV-files')
filenames = os.listdir(folder)

if filename is not None:
if filename in filenames:
filenames = [filename]
else:
print(f'The example "{filename}" is unknown.')
print('Please choose one among the available examples:')
print(filenames)
return

for i, model_filename in enumerate(filenames):
model_path = os.path.join(folder, model_filename)
simulate_model(model_path, os.path.join(save_dir, model_filename.split('.')[0]),print_model_file=True)

if i != len(filenames) - 1:
print()

if len(filenames) > 1:
print()
print("You have seen all the basic examples.")

print()
print("To run your own simulation, create your own CSV file and run:")
print("\timport spring.simulation as ss")
print("\tss.simulate_model('my_spring_model.csv')")


def show_gallery(filename):
save_dir = fileio.mkdir('gallery_results')
folder = os.path.join('src', 'gallery-spring-model-CSV-files')
filenames = os.listdir(folder)

if filename is not None:
if filename in filenames:
filenames = [filename]
else:
print(f'The example "{filename}" is unknown.')
print('Please choose one among the available examples:')
print(filenames)
return

for i, model_filename in enumerate(filenames):
model_path = os.path.join(folder, model_filename)
simulate_model(model_path, os.path.join(save_dir, model_filename.split('.')[0]),print_model_file=True)

if i != len(filenames) - 1:
print()

if len(filenames) > 1:
print()
print("You have seen the entire gallery.")

print()
print("Inspired? Create your own CSV file and run:")
print("\timport spring.simulation as ss")
print("\tss.simulate_model('my_spring_model.csv')")
2 changes: 1 addition & 1 deletion src/springable/graphics/default_graphics_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ class AssemblyAppearanceOptions(Updatable):
distance_spring_line_linewidth: float = 1.0
distance_spring_line_default_color: str = '#CECECE'
distance_spring_line_default_opacity: float = 0.7
node_style: str = 'elegant'
node_style: str = 'basic'
node_size: float = 3.
node_color: str = '#101010'
show_node_numbers: bool = False
Expand Down
2 changes: 1 addition & 1 deletion src/springable/gui/gui_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
DEFAULT_BEHAVIORS['LOGARITHM'] = LogarithmBehavior(DEFAULT_NATURAL_MEASURE, k=1.0)
DEFAULT_BEHAVIORS['BEZIER'] = BezierBehavior(DEFAULT_NATURAL_MEASURE, u_i=[1.0, 2.0, 3.0], f_i=[1.0, -1.0, 1.0])
DEFAULT_BEHAVIORS['BEZIER2'] = Bezier2Behavior(DEFAULT_NATURAL_MEASURE, u_i=[1.0, 2.0, 3.0], f_i=[1.0, -1.0, 1.0])
DEFAULT_BEHAVIORS['PIECEWISE'] = PiecewiseBehavior(DEFAULT_NATURAL_MEASURE, k=[1.0, -1.0, 1.0], u=[1, 2], us=0.25)
DEFAULT_BEHAVIORS['PIECEWISE'] = PiecewiseBehavior(DEFAULT_NATURAL_MEASURE, k_i=[1.0, -1.0, 1.0], u_i=[1, 2], us=0.25)
DEFAULT_BEHAVIORS['ZIGZAG'] = ZigzagBehavior(DEFAULT_NATURAL_MEASURE, [1.0, 2.0, 3.0], [1.0, -5.0, 1.0], 0.5)
DEFAULT_BEHAVIORS['ZIGZAG2'] = Zigzag2Behavior(DEFAULT_NATURAL_MEASURE, [1.0, 2.0, 3.0], [1.0, -5.0, 1.0], 0.5)
DEFAULT_BEHAVIORS['CONTACT'] = ContactBehavior(0.0, f0=10.0, uc=0.5)
Expand Down
10 changes: 5 additions & 5 deletions src/springable/mechanics/mechanical_behavior.py
Original file line number Diff line number Diff line change
Expand Up @@ -521,13 +521,13 @@ def _compute_hysteron_info(self):


class PiecewiseBehavior(UnivariateBehavior, ControllableByPoints):
def __init__(self, natural_measure, k, u, us):
super().__init__(natural_measure, k=k, u=u, us=us)
def __init__(self, natural_measure, k_i, u_i, us):
super().__init__(natural_measure, k_i=k_i, u_i=u_i, us=us)
self._check()
self._make()

def _check(self):
k, u, us = self._parameters['k'], self._parameters['u'], self._parameters['us']
k, u, us = self._parameters['k_i'], self._parameters['u_i'], self._parameters['us']
if u[0] - 0.0 < us or (len(u) > 1 and np.min(np.diff(u)) < 2 * us):
raise InvalidBehaviorParameters(
f'us ({us:.3E}) is too large for the piecewise intervals provided. '
Expand All @@ -536,7 +536,7 @@ def _check(self):
raise InvalidBehaviorParameters(f'Expected {len(k) - 1} transitions, but only {len(k)} were provided.')

def _make(self):
k, u, us = self._parameters['k'], self._parameters['u'], self._parameters['us']
k, u, us = self._parameters['k_i'], self._parameters['u_i'], self._parameters['us']
self._u_i, self._f_i = spw.compute_piecewise_control_points(k, u, extra=4 * us)
self._generalized_force_function = spw.create_smooth_piecewise_function(k, u, us)
self._generalized_stiffness_function = spw.create_smooth_piecewise_derivative_function(k, u, us)
Expand All @@ -548,7 +548,7 @@ def update_from_control_points(self, cp_x, cp_y):
if (np.diff(cp_x) < 0).any():
raise InvalidBehaviorParameters(f'Each control point must be on the right of the previous one.')
k, u = spw.compute_piecewise_slopes_and_transitions_from_control_points(cp_x, cp_y)
self.update(k=k, u=u)
self.update(k_i=k, u_i=u)

def elastic_energy(self, alpha: float) -> float:
return quad(self._generalized_force_function, 0.0, alpha - self._natural_measure)[0]
Expand Down
16 changes: 16 additions & 0 deletions src/springable/readwrite/fileio.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,22 @@
from tomli import load as load_toml_file


def print_model_file(model_path, print_title=True):
title = ''
if print_title:
title = f'MODEL: {os.path.basename(model_path)}'
print(''.join(['-']*(len(title) + 4)))
print(f'| {title} |')
print(''.join(['-']*(len(title) + 4)))
with open(model_path, 'r') as file:
reader = csv.reader(file)
for row in reader:
print(", ".join(row))
if print_title:
print(''.join(['-'] * (len(title) + 4)))



def read_model(model_path, parameters: dict[str, float | str] = None) -> Model:
_parameters, _ = read_parameters_from_model_file(model_path)
if parameters is not None:
Expand Down
13 changes: 10 additions & 3 deletions src/springable/simulation.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ def save_results(result: static_solver.Result, save_dir):
io.write_results(result, save_dir)


def simulate_model(model_path, save_dir=None, solver_settings_path=None, graphics_settings_path=None,
postprocessing=None):
def simulate_model(model_path, save_dir=None, solver_settings_path: str = None, graphics_settings_path: str = None,
print_model_file=False, postprocessing=None):
# CREATE MAIN DIRECTORY WHERE RESULT WILL BE SAVED + COPY INPUT FILES
if save_dir is None:
save_dir = io.mkdir(os.path.splitext(os.path.basename(model_path))[0])
Expand All @@ -43,6 +43,9 @@ def simulate_model(model_path, save_dir=None, solver_settings_path=None, graphic
if graphics_settings_path is not None:
io.copy_graphics_settings_file(save_dir, graphics_settings_path)

if print_model_file:
io.print_model_file(model_path)

# READ INPUT FILES
mdl = io.read_model(model_path)
general_options = GeneralOptions()
Expand Down Expand Up @@ -80,7 +83,8 @@ def simulate_model(model_path, save_dir=None, solver_settings_path=None, graphic


def scan_parameter_space(model_path, save_dir=None, scan_parameters_one_by_one=True,
solver_settings_path=None, graphics_settings_path=None, postprocessing=None):
solver_settings_path=None, graphics_settings_path=None, print_model_file=False,
postprocessing=None):
if solver_settings_path is not None:
solver_settings = io.read_solver_settings_file(solver_settings_path)
else:
Expand Down Expand Up @@ -117,6 +121,9 @@ def scan_parameter_space(model_path, save_dir=None, scan_parameters_one_by_one=T
io.copy_graphics_settings_file(save_dir, graphics_settings_path)

# READ DEFAULT AND DESIGN PARAMETERS
if print_model_file:
io.print_model_file(model_path)

default_parameters, design_parameter_data = io.read_parameters_from_model_file(model_path)
design_parameter_names = list(design_parameter_data.keys())
design_parameter_vectors = []
Expand Down

0 comments on commit aecbe31

Please sign in to comment.