Source code for RepTate.theories.TheoryUCM

# RepTate: Rheology of Entangled Polymers: Toolkit for the Analysis of Theory and Experiments
# --------------------------------------------------------------------------------------------------------
#
# Authors:
#     Jorge Ramirez, jorge.ramirez@upm.es
#     Victor Boudara, victor.boudara@gmail.com
#
# Useful links:
#     http://blogs.upm.es/compsoftmatter/software/reptate/
#     https://github.com/jorge-ramirez-upm/RepTate
#     http://reptate.readthedocs.io
#
# --------------------------------------------------------------------------------------------------------
#
# Copyright (2017-2023): Jorge Ramirez, Victor Boudara, Universidad Politécnica de Madrid, University of Leeds
#
# This file is part of RepTate.
#
# RepTate 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.
#
# RepTate 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 RepTate.  If not, see <http://www.gnu.org/licenses/>.
#
# --------------------------------------------------------------------------------------------------------
"""Module TheoryUCM

Module for the Upper Convected Maxwell model

"""
import numpy as np
from RepTate.core.Parameter import Parameter, ParameterType, OptType
from RepTate.gui.QTheory import QTheory
from PySide6.QtWidgets import QToolBar, QToolButton, QMenu, QMessageBox
from PySide6.QtCore import QSize
from PySide6.QtGui import QIcon
from RepTate.gui.Theory_rc import *
from RepTate.applications.ApplicationLAOS import ApplicationLAOS
from RepTate.theories.theory_helpers import FlowMode, EditModesDialog


[docs] class TheoryUCM(QTheory): """Multi-mode Upper Convected Maxwell model (see Chapter 1 of :cite:`NLVE-Larson1988`): .. math:: \\boldsymbol \\sigma &= \\sum_{i=1}^n G_i \\boldsymbol A_i\\\\ \\dfrac {\\mathrm D \\boldsymbol A_i} {\\mathrm D t} &= \\boldsymbol \\kappa \\cdot \\boldsymbol A_i + \\boldsymbol A_i\\cdot \\boldsymbol \\kappa ^T - \dfrac 1 {\\tau_i} (\\boldsymbol A_i - \\boldsymbol I) * **Functions** - Analytical solution in shear .. math:: \\eta^+(t) = \\sum_{i=1}^n G_i \\tau_i (1 - \\exp(-t/\\tau_i)) - Analytical solution in uniaxial extension .. math:: \\eta^+_\\mathrm E (t) = \\dfrac 1 {\\dot\\varepsilon} \\sum_{i=1}^n G_i (A_{xx, i}(t) - A_{yy, i}(t)) with .. math:: A_{xx, i}(t) &= \\dfrac{ 1 - 2 \\dot\\varepsilon\\tau_i \\exp(-(1 - 2 \\dot\\varepsilon\\tau_i) t / \\tau_i) } {1 - 2 \\dot\\varepsilon\\tau_i }\\\\ A_{yy, i}(t) &= \\dfrac{ 1 + \\dot\\varepsilon\\tau_i \\exp(-(1 + \\dot\\varepsilon\\tau_i)t/\\tau_i) } { 1+ \\dot\\varepsilon\\tau_i} where for each mode :math:`i`: - :math:`G_i`: weight of mode :math:`i` - :math:`\\tau_i`: relaxation time of mode :math:`i` * **Parameters** [none] """ thname = "UCM" description = "Upper-convected Maxwell constitutive equation" citations = ["Oldroyd J.G., Proc. Roy. Soc. 1950, 200, 523-541"] doi = ["http://dx.doi.org/10.1098/rspa.1950.0035"] html_help_file = "http://reptate.readthedocs.io/manual/Applications/NLVE/Theory/theory.html#multi-mode-upper-convected-maxwell-model" single_file = False def __init__(self, name="", parent_dataset=None, axarr=None): """**Constructor**""" super().__init__(name, parent_dataset, axarr) self.function = self.calculate_UCM self.has_modes = True self.parameters["nmodes"] = Parameter( name="nmodes", value=2, description="Number of modes", type=ParameterType.integer, opt_type=OptType.const, display_flag=False, ) for i in range(self.parameters["nmodes"].value): self.parameters["G%02d" % i] = Parameter( name="G%02d" % i, value=1000.0, description="Modulus of mode %02d" % i, type=ParameterType.real, opt_type=OptType.nopt, display_flag=False, min_value=0, ) self.parameters["tauD%02d" % i] = Parameter( name="tauD%02d" % i, value=10.0, description="Terminal time of mode %02d" % i, type=ParameterType.real, opt_type=OptType.nopt, display_flag=False, min_value=0, ) self.MAX_MODES = 40 self.init_flow_mode() # add widgets specific to the theory tb = QToolBar() tb.setIconSize(QSize(24, 24)) if not isinstance(parent_dataset.parent_application, ApplicationLAOS): self.tbutflow = QToolButton() self.tbutflow.setPopupMode(QToolButton.MenuButtonPopup) menu = QMenu(self) self.shear_flow_action = menu.addAction( QIcon(":/Icon8/Images/new_icons/icon-shear.png"), "Shear Flow" ) self.extensional_flow_action = menu.addAction( QIcon(":/Icon8/Images/new_icons/icon-uext.png"), "Extensional Flow" ) if self.flow_mode == FlowMode.shear: self.tbutflow.setDefaultAction(self.shear_flow_action) else: self.tbutflow.setDefaultAction(self.extensional_flow_action) self.tbutflow.setMenu(menu) tb.addWidget(self.tbutflow) connection_id = self.shear_flow_action.triggered.connect( self.select_shear_flow ) connection_id = self.extensional_flow_action.triggered.connect( self.select_extensional_flow ) else: self.function = self.calculate_UCMLAOS self.tbutmodes = QToolButton() self.tbutmodes.setPopupMode(QToolButton.MenuButtonPopup) menu = QMenu(self) self.get_modes_action = menu.addAction( QIcon(":/Icon8/Images/new_icons/icons8-broadcasting.png"), "Get Modes" ) self.edit_modes_action = menu.addAction( QIcon(":/Icon8/Images/new_icons/icons8-edit-file.png"), "Edit Modes" ) self.plot_modes_action = menu.addAction( QIcon(":/Icon8/Images/new_icons/icons8-scatter-plot.png"), "Plot Modes" ) self.save_modes_action = menu.addAction( QIcon(":/Icon8/Images/new_icons/icons8-save-Maxwell.png"), "Save Modes" ) self.tbutmodes.setDefaultAction(self.get_modes_action) self.tbutmodes.setMenu(menu) tb.addWidget(self.tbutmodes) self.thToolsLayout.insertWidget(0, tb) connection_id = self.get_modes_action.triggered.connect(self.get_modes_reptate) connection_id = self.edit_modes_action.triggered.connect(self.edit_modes_window) connection_id = self.plot_modes_action.triggered.connect(self.plot_modes_graph) connection_id = self.save_modes_action.triggered.connect(self.save_modes)
[docs] def select_shear_flow(self): self.flow_mode = FlowMode.shear self.tbutflow.setDefaultAction(self.shear_flow_action)
[docs] def select_extensional_flow(self): self.flow_mode = FlowMode.uext self.tbutflow.setDefaultAction(self.extensional_flow_action)
[docs] def get_modes_reptate(self): self.Qcopy_modes()
[docs] def edit_modes_window(self): times, G, success = self.get_modes() if not success: self.logger.warning("Could not get modes successfully") return d = EditModesDialog(self, times, G, self.MAX_MODES) if d.exec_(): nmodes = d.table.rowCount() self.set_param_value("nmodes", nmodes) success = True for i in range(nmodes): msg, success1 = self.set_param_value( "tauD%02d" % i, d.table.item(i, 0).text() ) msg, success2 = self.set_param_value( "G%02d" % i, d.table.item(i, 1).text() ) success *= success1 * success2 if not success: QMessageBox.warning( self, "Error", "Some parameter(s) could not be updated.\nPlease try again.", ) else: self.handle_actionCalculate_Theory()
[docs] def plot_modes_graph(self): pass
[docs] def init_flow_mode(self): """Find if data files are shear or extension""" try: f = self.theory_files()[0] if f.file_type.extension == "shear": self.flow_mode = FlowMode.shear else: self.flow_mode = FlowMode.uext except Exception as e: print("in UCM init:", e) self.flow_mode = FlowMode.shear # default mode: shear
[docs] def get_modes(self): """Get the values of Maxwell Modes from this theory""" nmodes = self.parameters["nmodes"].value tau = np.zeros(nmodes) G = np.zeros(nmodes) for i in range(nmodes): tau[i] = self.parameters["tauD%02d" % i].value G[i] = self.parameters["G%02d" % i].value return tau, G, True
[docs] def set_modes(self, tau, G): """Set the values of Maxwell Modes from another theory""" nmodes = len(tau) self.set_param_value("nmodes", nmodes) for i in range(nmodes): self.set_param_value("tauD%02d" % i, tau[i]) self.set_param_value("G%02d" % i, G[i]) return True
[docs] def sigma_xy_shear(self, p, times): """Upper Convected Maxwell model in shear. Returns XY component of stress tensor""" G, tauD, gd = p return G * gd * tauD * (1 - np.exp(-times / tauD))
[docs] def n1_uext(self, p, times): """Upper Convected Maxwell model in uniaxial extension. Returns N1 = (XX -YY) component of stress tensor""" G, tauD, ed = p w = tauD * ed sxx = (1 - 2 * w * np.exp(-(1 - 2 * w) * times / tauD)) / (1 - 2 * w) syy = (1 + w * np.exp(-(1 + w) * times / tauD)) / (1 + w) return G * (sxx - syy)
[docs] def calculate_UCM(self, f=None): """Calculate the theory""" ft = f.data_table tt = self.tables[f.file_name_short] tt.num_columns = ft.num_columns tt.num_rows = ft.num_rows tt.data = np.zeros((tt.num_rows, tt.num_columns)) times = ft.data[:, 0] tt.data[:, 0] = times flow_rate = float(f.file_parameters["gdot"]) nmodes = self.parameters["nmodes"].value for i in range(nmodes): if self.stop_theory_flag: break G = self.parameters["G%02d" % i].value tauD = self.parameters["tauD%02d" % i].value p = [G, tauD, flow_rate] if self.flow_mode == FlowMode.shear: tt.data[:, 1] += self.sigma_xy_shear(p, times) elif self.flow_mode == FlowMode.uext: tt.data[:, 1] += self.n1_uext(p, times)
[docs] def calculate_UCMLAOS(self, f=None): """Calculate the theory for LAOS""" ft = f.data_table tt = self.tables[f.file_name_short] tt.num_columns = ft.num_columns tt.num_rows = ft.num_rows tt.data = np.zeros((tt.num_rows, tt.num_columns)) times = ft.data[:, 0] g0 = float(f.file_parameters["gamma"]) w = float(f.file_parameters["omega"]) tt.data[:, 0] = times tt.data[:, 1] = g0 * np.sin(w * times) nmodes = self.parameters["nmodes"].value for i in range(nmodes): if self.stop_theory_flag: break G = self.parameters["G%02d" % i].value tauD = self.parameters["tauD%02d" % i].value eta = G * tauD tt.data[:, 2] += ( eta * g0 * w * ( tauD * w * np.sin(w * times) - np.exp(-times / tauD) + np.cos(w * times) ) / (1 + w**2 * tauD**2) )
[docs] def set_param_value(self, name, value): """Set the value of a theory parameter""" if name == "nmodes": oldn = self.parameters["nmodes"].value message, success = super(TheoryUCM, self).set_param_value(name, value) if not success: return message, success if name == "nmodes": for i in range(self.parameters["nmodes"].value): self.parameters["G%02d" % i] = Parameter( name="G%02d" % i, value=1000.0, description="Modulus of mode %02d" % i, type=ParameterType.real, opt_type=OptType.nopt, display_flag=False, min_value=0, ) self.parameters["tauD%02d" % i] = Parameter( name="tauD%02d" % i, value=10.0, description="Terminal time of mode %02d" % i, type=ParameterType.real, opt_type=OptType.nopt, display_flag=False, min_value=0, ) if oldn > self.parameters["nmodes"].value: for i in range(self.parameters["nmodes"].value, oldn): del self.parameters["G%02d" % i] del self.parameters["tauD%02d" % i] return "", True