Skip to content

Commit

Permalink
feat: use yaslha instead of pyslha
Browse files Browse the repository at this point in the history
  • Loading branch information
misho104 committed Jul 31, 2018
1 parent df74d32 commit bcbe89d
Show file tree
Hide file tree
Showing 6 changed files with 70 additions and 251 deletions.
5 changes: 4 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,10 @@
name='simsusy',
version=version,
packages=packages,
install_requires=['click', 'pyslha', 'numpy'],
install_requires=['click', 'yaslha', 'numpy'],
dependency_links=[
'git+https://github.com/misho104/yaslha.git#egg=yaslha'
],
entry_points={
'console_scripts': 'simsusy = simsusy.simsusy:simsusy_main'
},
Expand Down
133 changes: 43 additions & 90 deletions simsusy/abs_model.py
Original file line number Diff line number Diff line change
@@ -1,49 +1,30 @@
import pyslha
import pathlib
import numpy as np
from typing import Dict, Optional, Sequence, List, Tuple, Union, Any, MutableMapping # noqa: F401

from simsusy.pyslha_customize import KeyType, ValueType, CommentType, writeSLHABlocks, writeSLHADecays
pyslha.writeSLHABlocks = writeSLHABlocks
pyslha.writeSLHADecays = writeSLHADecays
import numpy as np
import yaslha


class AbsModel:
class AbsModel(yaslha.SLHA):
"""Abstract model as a wrapper of a SLHA object."""

def __init__(self, obj: Union[pyslha.Doc, str, None]=None)->None:
self._matrix_cache = dict() # type: Dict[str, np.ndarray]
def __init__(self, obj: Union[None, str, pathlib.Path]=None)->None:
if obj is None:
self._slha = pyslha.Doc(blocks=pyslha._dict('Blocks'))
elif isinstance(obj, pyslha.Doc):
self._slha = obj
elif isinstance(obj, pathlib.Path):
self._slha = pyslha.readSLHAFile(str(obj), ignorenomass=True)
elif isinstance(obj, str):
if '\n' in obj or '\r' in obj:
# if multiline, assume obj as the SLHA content.
self._slha = pyslha.readSLHA(obj, ignorenomass=True)
else:
# if single line, it is a file path.
self._slha = pyslha.readSLHAFile(obj, ignorenomass=True)
super().__init__()
elif isinstance(obj, str) and ('\n' in obj or '\r' in obj):
super().__init__(yaslha.parse(obj)) # multiline: SLHA data itself
else:
raise ValueError('invalid initialization of Model')
super().__init__(yaslha.parse_file(obj)) # singleline: file path

def block(self, name: str) -> Optional[pyslha.Block]:
try:
return self._slha.blocks[name.upper()]
except KeyError:
return None
self._matrix_cache = dict() # type: Dict[str, np.ndarray]
self.dumper = None # type: Optional[yaslha.dumper.SLHADumper]

def get(self, block_name: str, key, default=None) -> Any:
# we introduce this because pyslha.get raises keyerror if block is not found.
block = self.block(block_name)
if block:
try:
return block[key]
except KeyError:
pass
return default
def block(self, block_name: str)->Optional[yaslha.Block]:
return self.blocks.get(block_name.upper(), None)

def get_float(self, block_name: str, key, default=None)->Optional[float]:
value = self.get(block_name, key, default)
return None if value is None else float(value)

def get_complex(self, block_name: str, key, default=None)->Union[float, complex, None]:
real = self.get_float(block_name, key)
Expand All @@ -55,44 +36,21 @@ def get_complex(self, block_name: str, key, default=None)->Union[float, complex,
else:
return real

def get_float(self, block_name: str, key, default=None)->Optional[float]:
value = self.get(block_name, key, default)
return None if value is None else float(value)

def mass(self, pid: int)->Optional[float]:
return self.get('MASS', pid)

def width(self, pid: int)->Optional[float]:
def width(self, pid: int)->float:
try:
return self._slha.decays[pid].totalwidth
return self.decays[pid].width
except KeyError:
return None

def br(self, pid: int, *daughters: int) -> Optional[float]:
n_decay = len(daughters)
sorted_daughters = sorted(daughters)
def br_list(self, pid: int)->Optional[MutableMapping[Tuple[int, ...], float]]:
try:
particle = self._slha.decays[pid]
decay = self.decays[pid]
except KeyError:
return None
for c in particle.decays:
if n_decay == c.nda and sorted(c.ids) == sorted_daughters:
return c.br
return 0

def br_list(self, pid: int) -> Optional[Dict[Sequence[int], float]]:
try:
particle = self._slha.decays[pid]
except KeyError:
return None
return dict([(tuple(sorted(c.ids)), c.br) for c in particle.decays])

def set(self, block_name: str, key: KeyType, value: ValueType, comment: CommentType='')->None:
block_name = block_name.upper()
if self.block(block_name) is None:
self._slha.blocks[block_name] = pyslha.Block(block_name)
self._slha.blocks[block_name][key] = value
# TODO: handle comment...
return dict([(tuple(sorted(k)), v) for k, v in decay.items_br()])

def set_mass(self, key: int, mass: float)->None: # just a wrapper
self.set('MASS', key, mass)
Expand Down Expand Up @@ -122,39 +80,34 @@ def get_matrix(self, block_name: str)->Optional[np.ndarray]:
self._matrix_cache[block_name] = matrix
return self._matrix_cache[block_name]

def set_q(self, block_name, q: float):
block_name = block_name.upper()
if self.block(block_name) is None:
self._slha.blocks[block_name] = pyslha.Block(block_name)
self._slha.blocks[block_name].q = q

def remove_block(self, block_name):
try:
del self._slha.blocks[tuple(block_name.upper())]
del self.blocks[block_name.upper()]
except KeyError:
pass

def remove_value(self, block_name, key):
if self.get(block_name, key) is not None:
del self._slha.blocks[block_name].entries[key]

def write(self, filename: Optional[str]=None, ignorenobr: bool=True, precision: int=8) -> None:
"""provide own version of write, because pyslha.Doc.write has a bug."""
if filename is None:
print(pyslha.writeSLHA(self._slha, ignorenobr=ignorenobr, precision=precision))
else:
pyslha.write(filename, self._slha, ignorenobr=ignorenobr, precision=precision)

try:
del self.blocks[block_name][key]
except KeyError:
pass

class Info:
def __init__(self, name: str, version: str)->None:
self.name = name # type: str
self.version = version # type: str
self.errors = list() # type: List[str]
self.warnings = list() # type: List[str]
def write(self, filename: Optional[str]=None)->None:
dumper = self.dumper or yaslha.dumper.SLHADumper(separating_line=True)
slha_text = yaslha.dump(self, dumper=dumper)

def add_error(self, msg: str):
self.errors.append(msg)
# append trivial comments because some old tools requires a comment on every line,
# TODO: change the content to meaningful ones
lines = slha_text.splitlines()
for i, v in enumerate(lines):
if len(v) != 1 and v.endswith('#'):
lines[i] = v + ' ...'
slha_text = '\n'.join(lines)

def add_warning(self, msg: str):
self.warnings.append(msg)
if filename is None:
# print(yaslha.dump(self, dumper=dumper))
print(slha_text)
else:
# yaslha.dump_file(self, filename, dumper=dumper)
with open(filename, 'w') as f:
f.write(slha_text)
16 changes: 11 additions & 5 deletions simsusy/mssm/mg5_tree_calculator.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from collections import OrderedDict
from typing import List, Optional # noqa: F401

import pyslha
import yaslha

from simsusy.mssm.library import CPV, FLV
import simsusy.simsusy
Expand All @@ -29,14 +29,12 @@ def write_output(self, filename: Optional[str]=None, slha1: bool=False)->None:
self._reorder_no_flv_mixing_matrix('SNUMIX', [1000012, 1000014, 1000016], lighter_lr_mixing=False)

# prepare DECAY blocks with zero width, since mg5's `compute_width` fails if these are not provided.
if not self.output._slha.decays:
self.output._slha.decays = OrderedDict()
for pid in [6, 23, 24]:
self.output._slha.decays[pid] = pyslha.Particle(pid, 0)
self.output.decays[pid] = yaslha.Decay(pid)
# if self.output.mass(pid) is None:
# self.output.set_mass(pid, self.output.ewsb.mass(pid))
for pid in self.output.block('MASS').keys():
self.output._slha.decays[pid] = pyslha.Particle(pid, 0)
self.output.decays[pid] = yaslha.Decay(pid)

# remove unsupported blocks (IMVCKM, IMUPMNS, GAUGE)
for name in ['IMVCKM', 'IMUPMNS']:
Expand All @@ -52,6 +50,14 @@ def write_output(self, filename: Optional[str]=None, slha1: bool=False)->None:
self.output.set('FRALPHA', 1, self.output.get('ALPHA', None))
self.output.remove_block('ALPHA')

# dumper configuration
self.output.dumper = yaslha.dumper.SLHADumper(
separate_blocks=True,
document_blocks=[
'MODSEL', 'MINPAR', 'EXTPAR',
'VCKMIN', 'UPMNSIN', 'MSQ2IN', 'MSU2IN', 'MSD2IN', 'MSL2IN', 'MSE2IN', 'TUIN', 'TDIN', 'TEIN',
])

# done
super().write_output(filename, slha1)

Expand Down
14 changes: 2 additions & 12 deletions simsusy/mssm/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,12 @@ class MSSMModel(AbsModel):
def __init__(self, *args):
super().__init__(*args)
self.input = None # type: Optional[MSSMInput]
self.spinfo = None # type: Optional[Info]
self.dcinfo = None # type: Optional[Info]
self.sm = None # type: Optional[AbsSMParameters]
self.ewsb = None # type: Optional[AbsEWSBParameters]

def write(self, filename: Optional[str]=None, ignorenobr: bool=True, precision: int=8) -> None:
self._prepare_info()
def write(self, filename: Optional[str]=None)->None:
self._prepare_input_parameters()
super().write(filename, ignorenobr, precision)

def _prepare_info(self):
for name, info in [('SPINFO', self.spinfo), ('DCINFO', self.dcinfo)]:
if info:
for key, value in [(1, info.name), (2, info.version), (3, info.errors), (4, info.warnings)]:
if value:
self.set(name, key, value)
super().write(filename)

def _prepare_input_parameters(self):
assert self.input is not None
Expand Down
17 changes: 10 additions & 7 deletions simsusy/mssm/tree_calculator.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import simsusy.simsusy
from simsusy.abs_model import Info
from simsusy.abs_calculator import AbsCalculator
from simsusy.mssm.model import MSSMModel as Output
from simsusy.mssm.input import MSSMInput as Input
Expand Down Expand Up @@ -198,8 +197,8 @@ def write_output(self, filename: Optional[str]=None, slha1: bool=False)->None:
self.add_warning('SLHA1 does not support CPV/FLV.')
for tmp in ['HMIX', 'GAUGE', 'MSOFT', 'MSQ2', 'MSU2', 'MSD2', 'MSL2', 'MSE2',
'AU', 'AD', 'AE', 'TU', 'TD', 'TE', 'YU', 'YD', 'YE']:
if self.output.block(tmp):
self.output.set_q(tmp, 200) # TODO: more proper way...
if tmp in self.output.blocks:
self.output.blocks[tmp].q = 200 # TODO: more proper way...
self.output.write(filename)

def _load_modsel(self):
Expand Down Expand Up @@ -239,9 +238,7 @@ def _load_ewsb_parameters(self):
self.add_error(f'invalid EWSB specification ({e})')

def _check_other_input_validity(self):
for block in self.input._slha.blocks:
name = ''.join(block)
content = self.input._slha.blocks[block]
for name, content in self.input.blocks.items():
if name in ['MODSEL', 'SMINPUTS', 'VCKMIN', 'UPMNSIN']:
pass # validity is checked when it is loaded
elif name == 'MINPAR':
Expand Down Expand Up @@ -318,12 +315,12 @@ def _check_cpv_flv_consistency(self):

def calculate(self):
self.output.input = self.input
self.output.spinfo = Info(self.name, self.version)
self._load_modsel()
self._load_sminputs()
self._load_ewsb_parameters()
self._check_other_input_validity()
self._check_cpv_flv_consistency()
self._prepare_info()
self._prepare_sm_ewsb()
self._calculate_softmasses()
self._calculate_higgses()
Expand All @@ -332,6 +329,12 @@ def calculate(self):
self._calculate_gluino()
self._calculate_sfermion()

def _prepare_info(self):
self.output.set_info('SPINFO', 1, self.name)
self.output.set_info('SPINFO', 2, self.version)
self.output.set_info('SPINFO', 3, [])
self.output.set_info('SPINFO', 4, [])

def _prepare_sm_ewsb(self):
assert self.output.sm is not None
assert self.output.ewsb is not None
Expand Down
Loading

0 comments on commit bcbe89d

Please sign in to comment.