Skip to content
Merged
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
47 changes: 38 additions & 9 deletions conmech/mesh/boundaries_factory.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,21 @@
"""
Created at 16.02.2022
"""
# CONMECH @ Jagiellonian University in Kraków
#
# Copyright (C) 2022-2026 Piotr Bartman-Szwarc <piotr.bartman@uj.edu.pl>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 3
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
# USA.

from typing import Callable, Tuple, Union

Expand Down Expand Up @@ -64,17 +79,31 @@ def reorder_boundary_nodes(nodes, elements, is_contact, is_dirichlet):
D - dirichlet node
Dirichlet override other
"""
# move boundary nodes to the top
# C | N | I | D
nodes, elements, boundary_nodes_count = reorder(nodes, elements, lambda _: True, to_top=True)
# then move contact nodes to the top
nodes, elements, contact_nodes_count = reorder(
# C | N | D
# I
nodes, elements, _neumann_nodes_count = reorder(
nodes,
elements,
lambda *args: is_contact(*args) and not is_dirichlet(*args),
to_top=True,
# lambda *args: is_contact(*args) and not is_dirichlet(*args),
lambda *args: not is_contact(*args) and not is_dirichlet(*args),
to_top=False,
)
# finally move dirichlet nodes to the bottom
# C | D
# I
# N
nodes, elements, contact_nodes_count = reorder(nodes, elements, is_contact, to_top=True)
# C
# N
# I
# D
# if node is both contact and dirichlet we treat it as dirichlet
nodes, elements, dirichlet_nodes_count = reorder(nodes, elements, is_dirichlet, to_top=False)
# C
# N
# I
# D
return (
nodes,
elements,
Expand Down
3 changes: 2 additions & 1 deletion conmech/plotting/drawer.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ def __init__(self, state, config: Config):
self.state = state
self.config = config
self.mesh = state.body.mesh
self.initial_nodes = state.body.mesh.nodes
self.node_size = 2 + (300 / len(self.mesh.nodes))
self.line_width = self.node_size / 2
self.deformed_mesh_color = "k"
Expand Down Expand Up @@ -144,7 +145,7 @@ def set_axes_limits(self, axes, foundation):
def draw_meshes(self, axes):
if self.original_mesh_color is not None:
self.draw_mesh(
self.mesh.nodes,
self.initial_nodes,
axes,
label="Original",
node_color=self.original_mesh_color,
Expand Down
19 changes: 17 additions & 2 deletions conmech/solvers/optimization/optimization.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# CONMECH @ Jagiellonian University in Kraków
#
# Copyright (C) 2021-2024 Piotr Bartman-Szwarc <piotr.bartman@uj.edu.pl>
# Copyright (C) 2021-2026 Piotr Bartman-Szwarc <piotr.bartman@uj.edu.pl>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
Expand Down Expand Up @@ -56,6 +56,8 @@
}
GLOBAL_QSMLM_NAMES = {"dc " + name for name in GLOBAL_QSMLM_NAMES}.union(GLOBAL_QSMLM_NAMES)

ADAM_NAMES = {"adam", "torch_adam"}


class Optimization(Solver):
def __init__(
Expand Down Expand Up @@ -164,7 +166,20 @@ def _solve_impl(
self.sub2gradient if method.lower().startswith("dc") else None,
)

if method.lower() in QSMLM_NAMES:
if method.lower() in ADAM_NAMES:
# pylint: disable=import-outside-toplevel,import-error)
from adam import minimize as adam_minimize

solution, comp_time = adam_minimize(
self.loss,
solution,
args,
maxiter=maxiter * 100,
subgradient=self.subgradient,
lr=1e-5,
)
self.computation_time += comp_time
elif method.lower() in QSMLM_NAMES:
start = time.time()
solution = self.minimizer(solution, args, 0, 1, maxiter)
self.computation_time += time.time() - start
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,23 @@
"""
Created at 21.08.2019
"""
# CONMECH @ Jagiellonian University in Kraków
#
# Copyright (C) 2024-2026 Piotr Bartman-Szwarc <piotr.bartman@uj.edu.pl>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 3
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
# USA.

import pickle
import time
from dataclasses import dataclass

import numpy as np
Expand Down Expand Up @@ -247,7 +261,6 @@ def outer_forces(x, t=None):
runner = StaticSolver(setup, "schur")
validator = StaticSolver(setup, "global")

start = time.time()
state = runner.solve(
verbose=True,
fixed_point_abs_tol=0.001,
Expand All @@ -267,6 +280,7 @@ def outer_forces(x, t=None):
) # np.squeeze(initial_guess.copy().reshape(1, -1))

m_loss[force] = loss_value(state, validator), runner.step_solver.computation_time
print(method, force, m_loss[force])
path = f"{config.outputs_path}/{PREFIX}_mtd_{method}_frc_{force:.2e}"
with open(path, "wb+") as output:
state.body.dynamics.force.outer.source = None
Expand All @@ -282,23 +296,23 @@ def outer_forces(x, t=None):
print("Plotting...")

path = f"{config.outputs_path}/{PREFIX}_losses"
# if config.show:
# plot_losses(path, slopes=layers_num)
if config.show:
plot_losses(path, slopes=layers_num)

for m in methods:
for f in forces:
path = f"{config.outputs_path}/{PREFIX}_mtd_{m}_frc_{f:.2e}"
with open(path, "rb") as output:
state = pickle.load(output)

drawer = Drawer(state=state, config=config)
drawer.colorful = True
drawer.draw(
show=config.show,
save=config.save,
# title=f"{m}: {f}, "
# f"time: {runner.step_solver.last_timing}"
)
# drawer = Drawer(state=state, config=config)
# drawer.colorful = True
# drawer.draw(
# show=config.show,
# save=config.save,
# # title=f"{m}: {f}, "
# # f"time: {runner.step_solver.last_timing}"
# )

x = state.body.mesh.nodes[: state.body.mesh.contact_nodes_count - 1, 0]
u = state.displacement[: state.body.mesh.contact_nodes_count - 1, 1]
Expand All @@ -315,7 +329,7 @@ def outer_forces(x, t=None):
# plt.legend()
plt.show()

colors = ("0.7", "0.6", "0.4", "0.3", "blue", "pink", "red")
colors = ("0.7", "0.6", "0.4", "0.3", "blue", "pink", "red", "green")[-len(methods) :]
for i, m in enumerate(methods[:]):
n_ = 5
for f in forces[n_ : n_ + 1]:
Expand All @@ -324,14 +338,14 @@ def outer_forces(x, t=None):
state = pickle.load(output)

drawer = Drawer(state=state, config=config)
# drawer.deformed_mesh_color = "white"
# drawer.colorful = True
# drawer.draw(
# show=config.show,
# save=config.save,
# title=f"{m}: {f}, ",
# # f"time: {runner.step_solver.last_timing}"
# )
drawer.deformed_mesh_color = "white"
drawer.colorful = True
drawer.draw(
show=config.show,
save=config.save,
title=f"{m}: {f}, ",
# f"time: {runner.step_solver.computation_time}"
)
# print(state.displaced_nodes[drawer.mesh.contact_indices][:, 1])
x = state.body.mesh.nodes[: state.body.mesh.contact_nodes_count - 1, 0]
if m == methods[0]:
Expand Down Expand Up @@ -389,6 +403,7 @@ def survey(config):
"Powell",
"qsm",
"globqsm",
# "adam",
)[:]
forces = np.asarray(
(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# CONMECH @ Jagiellonian University in Kraków
#
# Copyright (C) 2023 Piotr Bartman-Szwarc <piotr.bartman@uj.edu.pl>
# Copyright (C) 2023-2026 Piotr Bartman-Szwarc <piotr.bartman@uj.edu.pl>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# CONMECH @ Jagiellonian University in Kraków
#
# Copyright (C) 2023 Piotr Bartman <piotr.bartman@uj.edu.pl>
# Copyright (C) 2023-2026 Piotr Bartman <piotr.bartman@uj.edu.pl>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
Expand Down
2 changes: 2 additions & 0 deletions examples/Makela_et_al_1998.py
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,7 @@ def plot_losses(path, slopes=None):
"Powell": (losses["Powell"], "blue"),
"subgradient": (losses["qsm"], "pink"),
"global subgradient": (losses["globqsm"], "red"),
"Adam": (losses["adam"], "green"),
}

# Grid of plots
Expand All @@ -265,6 +266,7 @@ def plot_losses(path, slopes=None):
"-.",
"--",
"-",
":",
]

# loss
Expand Down
Loading