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
2 changes: 1 addition & 1 deletion CITATION.cff
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ authors:
- family-names: "Weissgraeber"
given-names: "Philipp"
orcid: "https://orcid.org/0000-0001-8320-8672"
version: 3.1.2
version: 3.1.3
date-released: 2021-12-30
Comment thread
pillowbeast marked this conversation as resolved.
identifiers:
- description: Collection of archived snapshots of all versions of WEAC
Expand Down
2 changes: 1 addition & 1 deletion demo/demo.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"id": "695bafcb",
"metadata": {},
"source": [
"Note that instructions in this notebook refer to **release v3.1.2.** Please make sure you are running the latest version of weac using\n",
"Note that instructions in this notebook refer to **release v3.1.3.** Please make sure you are running the latest version of weac using\n",
"\n",
"```bash\n",
"pip install -U weac\n",
Expand Down
4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"

[project]
name = "weac"
version = "3.1.2"
version = "3.1.3"
authors = [{ name = "2phi GbR", email = "mail@2phi.de" }]
description = "Weak layer anticrack nucleation model"
readme = "README.md"
Expand Down Expand Up @@ -123,7 +123,7 @@ ignore = [
]

[tool.bumpversion]
current_version = "3.1.2"
current_version = "3.1.3"

[[tool.bumpversion.files]]
filename = "pyproject.toml"
Expand Down
2 changes: 1 addition & 1 deletion src/weac/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
WEAC - Weak Layer Anticrack Nucleation Model
"""

__version__ = "3.1.2"
__version__ = "3.1.3"
5 changes: 4 additions & 1 deletion src/weac/analysis/criteria_evaluator.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
WeakLayer,
)
from weac.constants import RHO_ICE
from weac.core.slab_touchdown import TouchdownMode
from weac.components.scenario_config import TouchdownMode
from weac.core.system_model import SystemModel

logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -741,6 +741,9 @@ def evaluate_SteadyState(
cut_length=cut_distance,
)
system_copy.update_scenario(segments=segments, scenario_config=scenario_config)
# Force the requested mode to avoid floating-point precision issues
# when l_AB/l_BC are recalculated with different scenario parameters
system_copy.set_forced_touchdown_mode(mode)
touchdown_distance = system_copy.slab_touchdown.touchdown_distance
analyzer = Analyzer(system_copy, printing_enabled=print_call_stats)
energy_release_rate, _, _ = analyzer.differential_ERR(unit="J/m^2")
Expand Down
3 changes: 2 additions & 1 deletion src/weac/components/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from .layer import Layer, WeakLayer
from .model_input import ModelInput
from .segment import Segment
from .scenario_config import ScenarioConfig, SystemType
from .scenario_config import ScenarioConfig, SystemType, TouchdownMode

__all__ = [
"Config",
Expand All @@ -18,4 +18,5 @@
"ScenarioConfig",
"ModelInput",
"SystemType",
"TouchdownMode",
]
10 changes: 10 additions & 0 deletions src/weac/components/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@

from pydantic import BaseModel, Field

from weac.components.scenario_config import TouchdownMode


class Config(BaseModel):
"""
Expand All @@ -21,11 +23,19 @@ class Config(BaseModel):
----------
touchdown : bool
Whether slab touchdown on the collapsed weak layer is considered.
forced_touchdown_mode : TouchdownMode | None
If set, forces the touchdown mode instead of calculating it from l_AB/l_BC.
This avoids floating-point precision issues when the mode boundary values
are recalculated with different scenario parameters.
"""

touchdown: bool = Field(
default=False, description="Whether to include slab touchdown in the analysis"
)
forced_touchdown_mode: TouchdownMode | None = Field(
default=None,
description="Force a specific touchdown mode instead of auto-calculating",
)


if __name__ == "__main__":
Expand Down
2 changes: 2 additions & 0 deletions src/weac/components/scenario_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
"skier", "skiers", "pst-", "-pst", "rot", "trans", "vpst-", "-vpst"
]

TouchdownMode = Literal["A_free_hanging", "B_point_contact", "C_in_contact"]


class ScenarioConfig(BaseModel):
"""
Expand Down
41 changes: 29 additions & 12 deletions src/weac/core/slab_touchdown.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from scipy.optimize import brentq

from weac.components.layer import WeakLayer
from weac.components.scenario_config import ScenarioConfig
from weac.components.scenario_config import ScenarioConfig, TouchdownMode
from weac.components.segment import Segment
from weac.constants import STIFFNESS_COLLAPSE_FACTOR
from weac.core.eigensystem import Eigensystem
Expand All @@ -20,9 +20,6 @@
logger = logging.getLogger(__name__)


TouchdownMode = Literal["A_free_hanging", "B_point_contact", "C_in_contact"]


class SlabTouchdown: # pylint: disable=too-many-instance-attributes,too-few-public-methods
"""
Handling the touchdown situation in a PST.
Expand Down Expand Up @@ -52,6 +49,9 @@ class SlabTouchdown: # pylint: disable=too-many-instance-attributes,too-few-pub
-----------
scenario: `Scenario`
eigensystem: `Eigensystem`
forced_mode: `TouchdownMode | None`
If provided, forces this touchdown mode instead of calculating from l_AB/l_BC.
This avoids floating-point precision issues when scenario parameters change.

Attributes:
-----------
Expand Down Expand Up @@ -81,9 +81,15 @@ class SlabTouchdown: # pylint: disable=too-many-instance-attributes,too-few-pub
touchdown_distance: float
collapsed_weak_layer_kR: float | None = None

def __init__(self, scenario: Scenario, eigensystem: Eigensystem):
def __init__(
self,
scenario: Scenario,
eigensystem: Eigensystem,
forced_mode: TouchdownMode | None = None,
):
self.scenario = scenario
self.eigensystem = eigensystem
self._forced_mode = forced_mode

# Create a new scenario config with phi=0 (flat slab) while preserving other settings
self.flat_config = ScenarioConfig(
Expand Down Expand Up @@ -114,14 +120,25 @@ def _calc_touchdown_mode(self):
self.l_BC = self._calc_l_BC()
except ValueError:
self.l_BC = self.scenario.L
# Assign stage
touchdown_mode = "A_free_hanging"
if self.scenario.cut_length <= self.l_AB:

# Assign stage - use forced mode if provided, otherwise calculate from thresholds
if self._forced_mode is not None:
touchdown_mode = self._forced_mode
logger.debug(
"Using forced touchdown mode: %s (l_AB=%.2f, l_BC=%.2f, cut_length=%.2f)",
touchdown_mode,
self.l_AB,
self.l_BC,
self.scenario.cut_length,
)
else:
touchdown_mode = "A_free_hanging"
elif self.l_AB < self.scenario.cut_length <= self.l_BC:
touchdown_mode = "B_point_contact"
elif self.l_BC < self.scenario.cut_length:
touchdown_mode = "C_in_contact"
if self.scenario.cut_length <= self.l_AB:
touchdown_mode = "A_free_hanging"
elif self.l_AB < self.scenario.cut_length <= self.l_BC:
touchdown_mode = "B_point_contact"
elif self.l_BC < self.scenario.cut_length:
touchdown_mode = "C_in_contact"
Comment thread
pillowbeast marked this conversation as resolved.
self.touchdown_mode = touchdown_mode

def _calc_touchdown_distance(self):
Expand Down
25 changes: 24 additions & 1 deletion src/weac/core/system_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
from weac.core.field_quantities import FieldQuantities
from weac.core.scenario import Scenario
from weac.core.slab import Slab
from weac.components.scenario_config import TouchdownMode
from weac.core.slab_touchdown import SlabTouchdown
from weac.core.unknown_constants_solver import UnknownConstantsSolver

Expand Down Expand Up @@ -164,7 +165,9 @@ def slab_touchdown(self) -> SlabTouchdown | None:
if self.config.touchdown:
logger.info("Solving for Slab Touchdown")
slab_touchdown = SlabTouchdown(
scenario=self.scenario, eigensystem=self.eigensystem
scenario=self.scenario,
eigensystem=self.eigensystem,
forced_mode=self.config.forced_touchdown_mode,
)
logger.info(
"Original cut_length: %s, touchdown_distance: %s",
Expand Down Expand Up @@ -345,6 +348,26 @@ def toggle_touchdown(self, touchdown: bool):
self._invalidate_slab_touchdown()
self._invalidate_constants()

def set_forced_touchdown_mode(self, mode: TouchdownMode | None):
"""
Set the forced touchdown mode.

When set, the touchdown mode calculation will use this mode instead of
calculating it from l_AB/l_BC thresholds. This avoids floating-point
precision issues when the mode boundaries are recalculated with different
scenario parameters.

Parameters
----------
mode : TouchdownMode | None
The mode to force ("A_free_hanging", "B_point_contact", "C_in_contact"),
or None to use automatic calculation.
"""
if self.config.forced_touchdown_mode != mode:
self.config.forced_touchdown_mode = mode
self._invalidate_slab_touchdown()
self._invalidate_constants()

def _invalidate_eigensystem(self):
"""Invalidate the eigensystem."""
self.__dict__.pop("eigensystem", None)
Expand Down
2 changes: 1 addition & 1 deletion uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.