from _collections import OrderedDict
import sfsimodels as sm
from sfsimodels import functions as sf
import liquepy as lq
from liquepy._spatial_models import Coords
import warnings
# THESE MODELS ARE STILL IN ALPHA AND MAY CHANGE OFTEN
[docs]class Loc(sm.CustomObject):
base_type = "loc"
type = "transect_location"
_soil_profile = None
def __init__(self, **kwargs):
super(Loc, self).__init__()
self._cpt = kwargs.get("cpt", None)
self.name = kwargs.get("name", None)
self.x = kwargs.get("x", -1)
self.offset = kwargs.get("offset", None)
self.off_dir = kwargs.get("off_dir", None)
self.coords = kwargs.get("coords", None)
# esp = kwargs.get("esp", None)
# if isinstance(esp, dict):
# esp = lq_esp.esp_dict_to_obj(esp)
# self._esp = esp
if self._cpt is not None: # TODO: set folder_path on CPT instead, and use lazy load from there
self.cpt_folder_path = self._cpt.folder_path # used if can't load CPT
self.cpt_file_name = self._cpt.file_name
cpt_delimiter = self._cpt.delimiter
else:
self.cpt_path = "<not-set>"
cpt_delimiter = None
self.cpt_delimiter = kwargs.get("cpt_delimiter", cpt_delimiter)
self._extra_class_inputs = ["cpt", "x", "offset", "off_dir", "cpt_folder_path", "cpt_file_name", "cpt_delimiter",
"soil_profile_id", "coords"]
self.inputs = self.inputs + self._extra_class_inputs
@property
def cpt(self):
if self._cpt is None:
self._cpt = lq.field.load_mpa_cpt_file(self.cpt_folder_path + "/" + self.cpt_file_name, delimiter=self.cpt_delimiter)
return self._cpt
# @property
# def esp(self):
#
# return self._esp
# @esp.setter
# def esp(self, esp):
# if isinstance(esp, dict):
# esp = lq_esp.esp_dict_to_obj(esp)
# self._esp = esp
[docs] def to_dict(self, extra=(), **kwargs):
outputs = OrderedDict()
skip_list = ["cpt", "soil_profile"]
if hasattr(self, "inputs"):
full_inputs = list(self.inputs) + list(extra)
else:
full_inputs = list(extra)
for item in full_inputs:
if item not in skip_list:
value = self.__getattribute__(item)
outputs[item] = sf.collect_serial_value(value)
return outputs
[docs] def add_to_dict(self, models_dict, parent_dict, **kwargs):
key = "locs"
if key not in parent_dict:
parent_dict[key] = OrderedDict()
parent_dict[key][self.id] = self.to_dict(**kwargs)
if self.soil_profile is not None:
self.soil_profile.add_to_dict(models_dict, **kwargs)
@property
def soil_profile_id(self):
if self._soil_profile is not None:
return self.soil_profile.id
@property
def soil_profile(self):
return self._soil_profile
@soil_profile.setter
def soil_profile(self, sp):
self._soil_profile = sp
[docs]class Transect(sm.CustomObject):
base_type = "transect"
type = "transect"
datum = "top of face"
def __init__(self, **kwargs):
super(Transect, self).__init__()
self._locs = OrderedDict()
self.name = kwargs.get("name", None)
start = kwargs.get("start", (0, 0)) # coords (lat, long)
end = kwargs.get("end", (0, 0))
self.s_coords = Coords(lat=start[0], lon=start[1])
self.e_coords = Coords(lat=end[0], lon=end[1])
self.ug_values = []
self.ug_xs = []
self.h_face = kwargs.get("h_face", None)
self.av_ground_slope = kwargs.get("av_ground_slope", None)
self._extra_class_inputs = ["locs", "start", "end", "ug_values", "ug_xs", "h_face", "av_ground_slope", "datum"]
self.inputs = self.inputs + self._extra_class_inputs
[docs] def add_cpt_by_coords(self, cpt, coords, **kwargs):
esp = kwargs.get("esp", None)
loc = Loc(cpt=cpt, name=cpt.file_name, esp=esp)
loc.coords = coords
return self.add_loc_by_coords(coords, loc)
[docs] def add_cpt(self, cpt, x, **kwargs):
offset = kwargs.get("offset", None)
off_dir = kwargs.get("off_dir", "-")
esp = kwargs.get("esp", None)
loc = Loc(cpt=cpt, name=cpt.file_name, offset=offset, off_dir=off_dir, esp=esp)
return self.add_loc(x, loc)
[docs] def get_cpt_names(self):
_cpts = []
for x in self.locs:
_cpts.append(self.locs[x].cpt_file_name)
return _cpts
[docs] def set_ids(self):
for i, loc_name in enumerate(self.locs):
self.locs[loc_name].id = i + 1
if self.locs[loc_name].soil_profile is not None:
self.locs[loc_name].soil_profile.id = i + 1
[docs] def to_dict(self, extra=(), **kwargs):
outputs = OrderedDict()
skip_list = ["locs"]
if hasattr(self, "inputs"):
full_inputs = list(self.inputs) + list(extra)
else:
full_inputs = list(extra)
for item in full_inputs:
if item not in skip_list:
value = self.__getattribute__(item)
outputs[item] = sf.collect_serial_value(value)
return outputs
[docs] def add_to_dict(self, models_dict):
if self.base_type not in models_dict:
models_dict[self.base_type] = OrderedDict()
outputs = self.to_dict()
models_dict[self.base_type][self.unique_hash] = outputs
for loc_num in self.locs:
self.locs[loc_num].add_to_dict(models_dict, parent_dict=models_dict[self.base_type][self.unique_hash])
[docs] def reset_cpt_folder_paths(self, folder_path):
for loc_name in self.locs:
self.locs[loc_name].cpt_folder_path = folder_path
@property
def tran_line(self):
try:
from liquepy.spatial.map_coords import Line
return Line(self.s_coords, self.e_coords)
except ImportError as e:
warnings.warn('Need to import spatial packages', stacklevel=3)
warnings.warn(e, stacklevel=3)
return None
@property
def x_end(self):
return self.tran_line.dist
@property
def locs(self):
return self._locs
[docs] def add_loc(self, x: float, loc):
loc.x = x
self._locs[x] = loc
self._sort_locs()
return self._locs[x]
[docs] def add_loc_by_coords(self, coords, loc):
if not sum(self.start) or not sum(self.end):
raise ValueError("start and end coordinates must be set")
loc.x = map_coords.calc_proj_line_dist(self.tran_line, coords)
loc.offset = map_coords.calc_line_offset(self.tran_line, coords)
loc.off_dir = map_coords.calc_line_off_dir(self.tran_line, coords)
self._locs[loc.x] = loc
self._sort_locs()
return self._locs[loc.x]
@locs.setter
def locs(self, locs):
for loc_id in locs:
loc_dist = locs[loc_id]["x"]
self.locs[loc_dist] = Loc()
sm.add_to_obj(self.locs[loc_dist], locs[loc_id])
def _sort_locs(self):
"""
Sort the locs by distance.
:return:
"""
self._locs = OrderedDict(sorted(self._locs.items(), key=lambda t: t[0]))
[docs] def get_loc_by_name(self, name):
for x in self.locs:
if self.locs[x].name == name:
return self.locs[x]
[docs] def get_loc_by_dist(self, dist):
return self.locs[dist]
[docs] def loc(self, index):
index = int(index)
if index == 0:
raise KeyError("index=%i, but must be 1 or greater." % index)
return list(self._locs.values())[index - 1]
[docs] def remove_loc(self, loc_int):
key = list(self._locs.keys())[loc_int - 1]
del self._locs[key]
[docs] def replace_loc(self, loc_int, soil):
key = list(self._locs.keys())[loc_int - 1]
self._locs[key] = soil
@property
def start(self):
return self.s_coords.as_tuple
@property
def end(self):
return self.e_coords.as_tuple
@start.setter
def start(self, values):
self.s_coords = Coords(lat=values[0], lon=values[1])
@end.setter
def end(self, values):
self.e_coords = Coords(lat=values[0], lon=values[1])
CUSTOM_MODELS = {"transect-transect": Transect,
"transect_location-transect_location": Loc}