def zon(opofonder): city = LocationInfo() city.region = "Netherlands" ###voor nijverdal city.name = "Nijverdal" city.latitude = 52.366146 city.longitude = 6.443098 ###Voor Meppel if test(): city.name = "Meppel" city.latitude = 52.701499 city.longitude = 6.232482 tijdzoneAmsterdam = timezone("Europe/Amsterdam") nu = datetime.datetime.now() if test(): print(nu) city.timezone = tijdzoneAmsterdam s = sun(city.observer, date=nu, tzinfo=tijdzoneAmsterdam) if test(): for k in ["dawn", "sunrise", "noon", "sunset", "dusk"]: print("%7s %s" % (k, s[k])) if opofonder == "onder": return (s["sunset"]) if opofonder == "op": return (s["sunrise"])
def calc_astral_day_time(date: datetime.date, time, latitude, longitude): """ Compute sun position for given coordinates and time. :param date: UTC date :param time: UTC time :param latitude: latitude :param longitude: longitude :return: D for Day, U for Dusk, N for Night, A for Dawn (Aube in French) """ loc = LocationInfo() loc.latitude = latitude loc.longitude = longitude s = sun(loc.observer, date=date, dawn_dusk_depression=Depression.NAUTICAL) ret = '?' # The intervals and their interpretation interp = ({'from:': s['dusk'].time(), 'to:': s['dawn'].time(), '=>': 'N'}, {'from:': s['dawn'].time(), 'to:': s['sunrise'].time(), '=>': 'A'}, {'from:': s['sunrise'].time(), 'to:': s['sunset'].time(), '=>': 'D'}, {'from:': s['sunset'].time(), 'to:': s['dusk'].time(), '=>': 'U'}, ) for intrv in interp: if (intrv['from:'] < intrv['to:'] and intrv['from:'] <= time <= intrv['to:']): # Normal interval ret = intrv['=>'] elif intrv['from:'] > intrv['to:'] \ and (time >= intrv['from:'] or time <= intrv['to:']): # Change of day b/w the 2 parts of the interval ret = intrv['=>'] return ret
def calc_astral_day_time2(date: datetime.datetime, time, latitude, longitude): """ Compute sun position for given coordinates and time. :param date: UTC date :param time: UTC time :param latitude: latitude :param longitude: longitude :return: D for Day, U for Dusk, N for Night, A pour Dawn (Aube in French) """ loc = LocationInfo() loc.latitude = latitude loc.longitude = longitude sun_phases = sun(observer=loc.observer, date=date, dawn_dusk_depression=Depression.NAUTICAL) observation_time = datetime.datetime.combine(date, time, tzinfo=utc) if observation_time < sun_phases['dawn']: sun_phases = sun(observer=loc.observer, date=date - ONE_DAY, dawn_dusk_depression=Depression.NAUTICAL) elif observation_time > sun_phases['dusk']: sun_phases = sun(observer=loc.observer, date=date + ONE_DAY, dawn_dusk_depression=Depression.NAUTICAL) # The intervals and their interpretation interp = [ {'from:': sun_phases['dawn'], 'to:': sun_phases['sunrise'], '=>': 'A'}, {'from:': sun_phases['sunrise'], 'to:': sun_phases['sunset'], '=>': 'D'}, {'from:': sun_phases['sunset'], 'to:': sun_phases['dusk'], '=>': 'U'}, ] for intrv in interp: if intrv['from:'] <= observation_time <= intrv['to:']: return intrv['=>'] return '?'
def main(us_se): if 'location' not in us_se: logger.error('Invalid config file') return if us_se['location']['auto_enabled']: loc = get_loc_from_ip() if loc: loc = loc.json() else: logger.error('Couldn\'t connect to ipinfo, giving up') return loc['latitude'], loc['longitude'] = ( float(x) for x in loc['loc'].strip().split(',')) loc['time_zone'] = tzlocal.get_localzone().zone else: for k, v in us_se['location']['manual'].items(): try: val = v.strip() except AttributeError: pass else: if not val: logger.error( 'Auto location is not enabled and some manual values are missing' ) return loc = us_se['location']['manual'] try: location = LocationInfo() location.name = loc['city'] location.region = loc['region'] location.latitude = loc['latitude'] location.longitude = loc['longitude'] location.timezone = loc['time_zone'] except ValueError as e: logger.error(str(e)) return s = sun(location.observer, date=date.today(), tzinfo=pytz.timezone(location.timezone)) sunrise = s['sunrise'].replace(second=0) + timedelta( minutes=us_se['offset']['sunrise']) sunset = s['sunset'].replace(second=0) + timedelta( minutes=us_se['offset']['sunset']) # Convert to UTC for storage return sunrise.astimezone(pytz.utc), sunset.astimezone(pytz.utc)
def zon(opofonder): city = LocationInfo() city.region = "Netherlands" ###voor nijverdal city.name = "Nijverdal" city.latitude = 52.366146 city.longitude = 6.443098 ###Voor Meppel city.name = "Meppel" city.latitude = 52.701499 city.longitude = 6.232482 tijdzoneAmsterdam = timezone("Europe/Amsterdam") nu = datetime.datetime.now() city.timezone = tijdzoneAmsterdam s = sun(city.observer, date=nu, tzinfo=tijdzoneAmsterdam) if opofonder == "onder": return (f'ondergang: {s["sunset"]}') if opofonder == "op": return (f'opkomst : {s["sunrise"]}')
def zon(opofonder): city = LocationInfo() city.region = "Netherlands" ###voor nijverdal city.name = "Nijverdal" city.latitude = 52.366146 city.longitude = 6.443098 ###Voor Meppel city.name = "Meppel" city.latitude = 52.701499 city.longitude = 6.232482 tijdzoneAmsterdam = timezone("Europe/Amsterdam") nu = datetime.datetime.now() city.timezone = tijdzoneAmsterdam # print ("Huidige tijd : ") # print (nu.strftime("%Y-%m-%d %H:%M:%S")) s = sun(city.observer, date=nu ,tzinfo=tijdzoneAmsterdam ) # print(city.name) # print(city.latitude) # print(city.longitude) # print('Zon') if opofonder == "onder": # print((f'ondergang: {s["sunset"]}\n')) return((f'ondergang: {s["sunset"]}\n')) # return s["sunrise"] # return "1846" if opofonder == "op": print((f'opkomst : {s["sunrise"]}\n')) return s["sunset"]
def get_local_time_of(): location = data["location"] geo_data = get_geodata(location) city = LocationInfo() city.latitude = geo_data["latitude"] city.longitude = geo_data["longitude"] city.timezone = geo_data["timezone"] timezone = city.timezone local_tz = pytz.timezone(timezone) datetime_day_start = datetime.datetime.now()\ .replace(hour=0, minute=0, second=0, microsecond=0) current_sun = sun(city.observer, date=datetime_day_start) local_time_of = lambda x: current_sun[x]\ .replace(tzinfo=pytz.utc)\ .astimezone(local_tz)\ .strftime("%H:%M:%S") return local_time_of
def isDay(): """Checks if the time is after sunset Returns: bool: Day time """ import datetime from pytz import timezone, utc from astral import LocationInfo from astral.sun import sun import geocoder g = geocoder.ip('me') city = LocationInfo() city.latitude = g.latlng[0] city.longitude = g.latlng[1] s = sun(city.observer, date=datetime.date.today()) # This presumably depends on the computer's timezone being correct now = utc.localize(datetime.datetime.utcnow()) return s['dawn'] < now < s['dusk']
def textual_information(data_parsed, geo_data, config, html_output=False): """ Add textual information about current weather and astronomical conditions """ def _shorten_full_location(full_location, city_only=False): def _count_runes(string): return len(string.encode('utf-16-le')) // 2 words = full_location.split(",") output = words[0] if city_only: return output for word in words[1:]: if _count_runes(output + "," + word) > 50: return output output += "," + word return output def _colorize(text, color): return colorize(text, color, html_output=html_output) city = LocationInfo() city.latitude = geo_data["latitude"] city.longitude = geo_data["longitude"] city.timezone = geo_data["timezone"] output = [] timezone = city.timezone datetime_day_start = datetime.datetime.now()\ .replace(hour=0, minute=0, second=0, microsecond=0) format_line = "%c %C, %t, %h, %w, %P" current_condition = data_parsed['data']['current_condition'][0] query = {} weather_line = wttr_line.render_line(format_line, current_condition, query) output.append('Weather: %s' % weather_line) output.append('Timezone: %s' % timezone) local_tz = pytz.timezone(timezone) def _get_local_time_of(what): _sun = { "dawn": sun.dawn, "sunrise": sun.sunrise, "noon": sun.noon, "sunset": sun.sunset, "dusk": sun.dusk, }[what] current_time_of_what = _sun(city.observer, date=datetime_day_start) return current_time_of_what\ .replace(tzinfo=pytz.utc)\ .astimezone(local_tz)\ .strftime("%H:%M:%S") local_time_of = {} for what in ["dawn", "sunrise", "noon", "sunset", "dusk"]: try: local_time_of[what] = _get_local_time_of(what) except ValueError: local_time_of[what] = "-" * 8 tmp_output = [] tmp_output.append(' Now: %%{{NOW(%s)}}' % timezone) tmp_output.append('Dawn: %s' % local_time_of["dawn"]) tmp_output.append('Sunrise: %s' % local_time_of["sunrise"]) tmp_output.append(' Zenith: %s ' % local_time_of["noon"]) tmp_output.append('Sunset: %s' % local_time_of["sunset"]) tmp_output.append('Dusk: %s' % local_time_of["dusk"]) tmp_output = [ re.sub("^([A-Za-z]*:)", lambda m: _colorize(m.group(1), "2"), x) for x in tmp_output ] output.append( "%20s" % tmp_output[0] \ + " | %20s " % tmp_output[1] \ + " | %20s" % tmp_output[2]) output.append( "%20s" % tmp_output[3] \ + " | %20s " % tmp_output[4] \ + " | %20s" % tmp_output[5]) city_only = False suffix = "" if "Simferopol" in timezone: city_only = True suffix = ", Крым" if config["full_address"]: output.append('Location: %s%s [%5.4f,%5.4f]' \ % ( _shorten_full_location(config["full_address"], city_only=city_only), suffix, geo_data["latitude"], geo_data["longitude"], )) output = [ re.sub( "^( *[A-Za-z]*:)", lambda m: _colorize(m.group(1), "2"), re.sub("^( +[A-Za-z]*:)", lambda m: _colorize(m.group(1), "2"), re.sub(r"(\|)", lambda m: _colorize(m.group(1), "2"), x))) for x in output ] return "".join("%s\n" % x for x in output)
def draw_astronomical(city_name, geo_data, config): datetime_day_start = datetime.datetime.now().replace(hour=0, minute=0, second=0, microsecond=0) city = LocationInfo() city.latitude = geo_data["latitude"] city.longitude = geo_data["longitude"] city.timezone = geo_data["timezone"] answer = "" moon_line = "" for time_interval in range(72): current_date = (datetime_day_start + datetime.timedelta(hours=1 * time_interval)).replace( tzinfo=pytz.timezone(geo_data["timezone"])) try: dawn = sun.dawn(city.observer, date=current_date) except ValueError: dawn = current_date try: dusk = sun.dusk(city.observer, date=current_date) except ValueError: dusk = current_date + datetime.timedelta(hours=24) try: sunrise = sun.sunrise(city.observer, date=current_date) except ValueError: sunrise = current_date try: sunset = sun.sunset(city.observer, date=current_date) except ValueError: sunset = current_date + datetime.timedelta(hours=24) char = "." if current_date < dawn: char = " " elif current_date > dusk: char = " " elif dawn <= current_date and current_date <= sunrise: char = u"─" elif sunset <= current_date and current_date <= dusk: char = u"─" elif sunrise <= current_date and current_date <= sunset: char = u"━" answer += char if config.get("view") in ["v2n", "v2d"]: moon_phases = constants.MOON_PHASES_WI moon_phases = [" %s" % x for x in moon_phases] else: moon_phases = constants.MOON_PHASES # moon if time_interval in [0, 23, 47, 69]: # time_interval % 3 == 0: moon_phase = moon.phase(date=datetime_day_start + datetime.timedelta(hours=time_interval)) moon_phase_emoji = moon_phases[int( math.floor(moon_phase * 1.0 / 28.0 * 8 + 0.5)) % len(moon_phases)] # if time_interval in [0, 24, 48, 69]: moon_line += moon_phase_emoji # + " " elif time_interval % 3 == 0: if time_interval not in [24, 28]: #se: moon_line += " " else: moon_line += " " answer = moon_line + "\n" + answer + "\n" answer += "\n" return answer
def gmAll(): # initialize data = request.get_json() data['text'] = data['text'].strip() message = data['text'].split() count = 0 send = None # find bot id conn = sqlite3.connect('pancake.db') c = conn.cursor() for row in c.execute(f"SELECT * FROM chats WHERE id = ?", (data['group_id'], )): botid = row[2] accesstoken = row[0] try: botid except: print("invalid group") return ("invalid group") headers = { 'content-type': 'application/json', 'x-access-token': accesstoken } getInfo = requests.get('https://api.groupme.com/v3/users/me', headers=headers) getInfo = getInfo.json()['response'] user_id1 = getInfo['user_id'] c.close() if data['sender_type'] == 'system': if "added the Pancake bot" in data['text']: time.sleep(0.5) send = "Hi! I'm Pancake. I'm a fun GroupMe bot designed to spice up any groupchat!\n\nHere are a list of commands:\n\np!lmgtfy {search term}\np!pick {option 1},{option 2}\np!coinflip\np!urban {search term}\np!love {firstname1} {firstname2}\np!madgab (use command twice)\np!8ball {your question}\np!sun\np!joke\n\np!help\np!leave (can only be used by owner)\np!ban/p!unban @whoever (can only be used by owner)\n\nI highly recommend using p!madgab to start some friendly competition in this groupchat!" if data['sender_type'] == 'user': conn = sqlite3.connect('databases/banned.db') c = conn.cursor() adminList = [] for row in c.execute(f"SELECT * FROM banned"): adminList.append(row[0]) if int(data['user_id']) in adminList: return ("banned user") c.close() conn = sqlite3.connect('databases/whitelist.db') c = conn.cursor() adminList = [] for row in c.execute(f"SELECT * FROM white WHERE group_id = ?", (data['group_id'], )): adminList.append(row[0]) if data['user_id'] == user_id1: pass elif adminList == []: pass elif data['user_id'] not in adminList: return ("banned user") c.close() if ((str(message[0])) == 'p!ban') and (str(data['sender_id']) == user_id1): conn = sqlite3.connect('databases/banned.db') c = conn.cursor() try: for x in data['attachments'][0]['user_ids']: c.execute("INSERT INTO banned (user_id) VALUES (?)", (x, )) conn.commit() send = f"banned member" except Exception as e: print(str(e)) send = "error" c.close() elif ((str(message[0])) == 'p!unban') and (str(data['sender_id']) == user_id1): conn = sqlite3.connect('databases/banned.db') c = conn.cursor() try: send = None for x in data['attachments'][0]['user_ids']: c.execute("DELETE FROM banned WHERE user_id = ?", (x, )) conn.commit() send = "unbanned member" if send == None: send = "member was not banned" except: send = "error" c.close() elif ((str(message[0])) == 'p!whitelist') and (str(data['sender_id']) == user_id1): if message[1].lower() == "add": conn = sqlite3.connect('databases/whitelist.db') c = conn.cursor() try: for x in data['attachments'][0]['user_ids']: c.execute( "INSERT INTO white (user_id, group_id) VALUES (?,?)", (x, data['group_id'])) conn.commit() send = f"added member to whitelist" except Exception as e: print(str(e)) send = "error" c.close() if message[1].lower() == "remove": conn = sqlite3.connect('databases/whitelist.db') c = conn.cursor() try: send = None for x in data['attachments'][0]['user_ids']: c.execute( "DELETE FROM white WHERE user_id = ? and group_id = ?", (x, data['group_id'])) conn.commit() send = "removed member" if send == None: send = "member was not removed" except Exception as e: print(str(e)) send = "error" c.close() if message[1].lower() == "off": conn = sqlite3.connect('databases/whitelist.db') c = conn.cursor() try: c.execute("DELETE FROM white WHERE group_id = ?", (data['group_id'], )) conn.commit() send = "whitelist off" except: send = "error" c.close() #leave if message[0].lower() == 'p!leave' and data['user_id'] == user_id1: conn = sqlite3.connect('pancake.db') c = conn.cursor() c.execute("DELETE FROM chats WHERE id = ?", (data['group_id'], )) conn.commit() c.close() params = {"bot_id": botid, "text": "pancake is shutting down"} create = requests.post('https://api.groupme.com/v3/bots/post', headers=headers, params=params) params = {"bot_id": botid} create = requests.post('https://api.groupme.com/v3/bots/destroy', headers=headers, params=params) return ("removed") if message[0].lower() == 'p!help': send = "Hi! I'm Pancake. I'm a fun GroupMe bot designed to spice up any groupchat!\n\nHere are a list of commands:\n\np!lmgtfy {search term}\np!pick {option 1},{option 2}\np!coinflip\np!urban {search term}\np!love {firstname1} {firstname2}\np!madgab (use command twice)\np!8ball {your question}\np!sun\np!joke\n\np!help\np!leave (can only be used by owner)\np!ban/p!unban @whoever (can only be used by owner)\n\nI highly recommend using p!madgab to start some friendly competition in this groupchat!" #lmgtfy if message[0].lower() == 'p!lmgtfy': message.pop(0) send = "https://lmgtfy.com/?q=" + '+'.join(message) #choose elif message[0].lower() == 'p!pick': text = data['text'][6:].split(",") for i in range(len(text)): text[i] = text[i].strip() num = random.randint(0, len(text) - 1) send = "i pick \"" + text[num] + "\"" #coinflip elif message[0].lower() == 'p!coinflip': num = random.randint(0, 11) listOne = [0, 1, 2, 3, 4, 5] listTwo = [6, 7, 8, 9, 10, 11] if num in listOne: send = "Heads" elif num in listTwo: send = "Tails" #urban elif message[0].lower() == 'p!urban': message.pop(0) urbanTerm = ' '.join(message) urban = requests.get( f"http://api.urbandictionary.com/v0/define?term={urbanTerm}") try: send = urban.json()['list'][0]['definition'] except IndexError: send = f"couldn't find a definition for {urbanTerm}" #love elif message[0].lower() == 'p!love': try: first = message[1].lower() second = message[2].lower() love = requests.get( f"https://www.lovecalculator.com/love.php?name1={first}&name2={second}" ) lovesoup = BeautifulSoup(love.text, "lxml") score = lovesoup.findAll( "div", {"class": "result__score"})[0].text.strip() send = score except: send = "invalid syntax" #madgab elif message[0].lower() == 'p!madgab': conn = sqlite3.connect('databases/madgab.db') c = conn.cursor() questions = [] answers = [] channels = [] requestions = [] for x in open("databases/question.txt", "r"): questions.append(x) for x in open("databases/answer.txt", "r"): answers.append(x) for row in c.execute(f"SELECT * FROM gameplay"): channels.append(row[0]) requestions.append(row[1]) if data['group_id'] in channels: active = True else: active = False if active == True: sendAnswer = 0 for x in range(len(channels)): if data['group_id'] == channels[x]: sendAnswer = answers[int(requestions[x])] c.execute("DELETE FROM gameplay WHERE channel = ?", (data['group_id'], )) conn.commit() send = sendAnswer else: num = random.randint(0, len(questions) - 1) c.execute( "INSERT INTO gameplay (channel,question) VALUES (?,?)", (data['group_id'], num)) conn.commit() send = questions[num] c.close() elif message[0].lower() == 'p!8ball': responses = [ 'Don’t count on it.', 'It is certain.', 'It is decidedly so.', 'Most likely.', 'My reply is no.', 'My sources say no.', 'Signs point to yes.', 'Very doubtful.', 'Without a doubt.', 'Yes.', 'Yes – definitely.', 'You may rely on it.', 'As I see it, yes.', 'Ask again later.', 'Better to not tell you now.', 'Cannot predict now.', 'Concentrate and ask again.' ] send = random.choice(responses) elif message[0].lower() == "p!sun": city_name = 'Atlanta' city = LocationInfo() city.latitude = 33.7490 city.longitude = -84.3880 city.timezone = 'US/Eastern' s = sun(city.observer, date=datetime.now(), tzinfo=city.timezone) send = f"Sun Info For Atlanta\n\nDawn: {s['dawn'].strftime('%I:%M %p')}\nSunrise: {s['sunrise'].strftime('%I:%M %p')}\nNoon: {s['noon'].strftime('%I:%M %p')}\nSunset: {s['sunset'].strftime('%I:%M %p')}\nDusk: {s['dusk'].strftime('%I:%M %p')}\n" elif message[0].lower() == "p!joke": jheaders = {'User-Agent': 'curl/7.55.1'} joke = requests.get("https://icanhazdadjoke.com/", headers=jheaders) send = joke if send != None: params = {"bot_id": botid, "text": send} create = requests.post('https://api.groupme.com/v3/bots/post', headers=headers, params=params) return ("message received") if send != None: params = {"bot_id": botid, "text": send} create = requests.post('https://api.groupme.com/v3/bots/post', headers=headers, params=params) return ("message received!")
# # Gerard Doets # 18 maart 2020 # Naam : zonOpkomstEnOndergang.py from astral import LocationInfo from astral.sun import sun from pytz import * import datetime city = LocationInfo() city.region = "Netherlands" ###voor nijverdal city.name = "Nijverdal" city.latitude = 52.366146 city.longitude = 6.443098 ###Voor Meppel city.name = "Meppel" city.latitude = 52.701499 city.longitude = 6.232482 tijdzoneAmsterdam = timezone("Europe/Amsterdam") nu = datetime.datetime.now() city.timezone = tijdzoneAmsterdam print ("Huidige tijd : ") print (nu.strftime("%Y-%m-%d %H:%M:%S")) s = sun(city.observer, date=nu ,tzinfo=tijdzoneAmsterdam )
def main(): try: # need time to get internet connection once pi starts up time.sleep( 120 ) # if you lower this value and there is a critical error in your code your pi could get stuck in an infinite reboot loop! dir_path = os.path.dirname(os.path.realpath(__file__)) logging.basicConfig(filename=os.path.join(dir_path, "app.log")) # get current location with open(os.path.join(dir_path, 'location.json')) as loc_file: data = json.load(loc_file) loc = LocationInfo() loc.timezone = data["general"]["timezone"] loc.latitude = data["coordinates"]["latitude"] loc.longitude = data["coordinates"]["longitude"] # get sunrise and sunset times times = sun(loc.observer, date=datetime.now(), tzinfo=loc.timezone) # determine time until next daylight, sleep until then sleep_time = time_until_daylight(times["sunrise"], times["sunset"], loc) if sleep_time != 0: time.sleep(sleep_time) resources = Resources() while True: present_dt = datetime.now() # capture photos from both webcams resources.wb.time = present_dt.strftime("%Y-%m-%d %H_%M_%S") resources.wb.capture_usb_photo() resources.wb.capture_ribbon_photo() # send the jpgs to google photos and then delete them off local storage resources.gphotos.upload_all_photos_in_dir( resources.wb.base_dir_ribbon, "ribbon") resources.gphotos.upload_all_photos_in_dir( resources.wb.base_dir_usb, "usb") # log any errors encountered during execution of this cycle into the database if os.path.getsize("./app.log") > 0: with open("./app.log", "r") as f: error_message = f.read() resources.sql_store.insert_error( present_dt.strftime("%Y-%m-%d %H:%M:%S"), error_message) # clear out the log with open("./app.log", "w") as f: pass # regular sleep interval is 5 minutes, otherwise sleep until next sunrise sleep_time = time_until_daylight(times["sunrise"], times["sunset"], loc) if sleep_time == 0: time.sleep(300) else: resources.release() time.sleep(sleep_time) resources = Resources() times = sun(loc.observer, date=datetime.now(), tzinfo=loc.timezone) except BaseException as e: logging.exception( 'Something went wrong in the __main__ script. Restarting the pi.\n' ) os.system('sudo reboot')
def fRWU(ts, lat=49.70764, lon=5.897638, elev=200., diffx=3, slope_diff=3, maxdiffs=0.25, mintime=3.5): r"""Calulate a daily root water uptake estimate from a soil moisture time series Returns a data frame with time series of daily RWU estimates and daily evaluation references after Jackisch et al. (in review) Parameters ---------- ts : pandas.DataFrame with time zone aware datetime index time series of one soil moisture sensor (assumes vol.%) a relatively high temporal resolution of about 30 min or smaller is assumed lat : float latitude of location (degree) lon : float longitude of location (degree) elev : float elevation at location (m above msl) diffx : int number of time steps to evaluate change in moisture to (spans window) slope_diff : float minimal difference factor of slope between night and day linear regession to evaluate step shape especially in case of night decrease of soil moisture maxdiffs : float maximum of soil moistue difference to assume no significant other water transport (some sort of threshold which could be the noise of the sensed data) mintime : float minmimal time of a day or night period (in h) Returns ------- RWU : pandas.DataFrame returns a data frame with time series of daily RWU estimates and daily references: rwu :: root water uptake with extrapolated night changes rwu_nonight :: neglecting nocturnal changes lm_night :: slope of linear model during night lm_day :: slope of linear model during day step_control :: control values (1111 means all criteria met) evalx :: control values for time references eval_nse :: control values for diurnal step shape as nash-sutcliffe efficiency tin :: start of previous night tout :: start of day tix :: start of next night References ---------- Jackisch, C., Knoblauch, S., Blume, T., Zehe, E. and Hassler, S.K. (in review): Estimates of tree root water uptake from soil moisture profile dynamics. Submitted to Biogeosciences. DOI to be added """ # use astral to get sunrise/sunset time references as a function of the date l = LocationInfo() l.latitude = lat l.longitude = lon l.timezone = str(ts.index.tz) l.elevation = elev #sunrise sunset def sunr(dd): # give date and return time of sunrise sunrise = pd.to_datetime(sun(l, date=dd)['sunrise']) return sunrise.tz_convert(l.timezone) def suns(dd): # give date and return time of sunset sunset = pd.to_datetime(sun(l, date=dd)['sunset']) return sunset.tz_convert(l.timezone) # get unique days in time series ddx = ts.resample('1d').mean().index.date # get frequencies of ts freqx = (pd.Series(ts.index[1:]) - pd.Series(ts.index[:-1])).value_counts() # get change in soil moisture as smoothed diff dif_ts = pd.Series(spf.gaussian_filter1d(ts.diff(diffx), 1)) dif_ts.index = ts.index # create empty dataframe for RWU calculation and evaluation RWU = pd.DataFrame(np.zeros((len(ddx), 10)) * np.nan) RWU.index = pd.to_datetime(ddx) RWU.columns = [ 'rwu', 'rwu_nonight', 'lm_night', 'lm_day', 'step_control', 'evalx', 'eval_nse', 'tin', 'tout', 'tix' ] def startstopRWU(dd): # give soilmoisture ts and date, return time of end of RWU try: # find first steps of not declining soil moisture after sunset tsx = dif_ts.loc[suns(dd - datetime.timedelta(hours=24)) - datetime.timedelta(hours=5):suns(dd) + datetime.timedelta(hours=2)] stopRWU = tsx.index[np.where(tsx.values >= 0)[0][0]] stop2RWU = tsx.index[np.where(tsx.values > 0)[0][np.where( tsx.values > 0)[0] > np.where(tsx.values <= -0.01)[0][np.where( tsx.values <= -0.01)[0] > np.where( tsx.values >= 0)[0][0]][0]][0]] reflim = np.min([ -0.001, tsx.loc[stopRWU:stop2RWU][ tsx.loc[stopRWU:stop2RWU] < -0.001].quantile(0.95) ]) startRWU = tsx.loc[stopRWU:].index[ tsx.loc[stopRWU:].rolling(3, center=True).mean() <= reflim][0] return [stopRWU, startRWU, stop2RWU, 1] except: # in case soil moisture keeps falling without stepping assume 1 hour after sunset/sunrise but return warning flag try: stopRWU = ts.index[ts.index.get_loc( suns(dd - datetime.timedelta(hours=24)) + datetime.timedelta(hours=1), method='nearest')] startRWU = ts.index[ts.index.get_loc( sunr(dd) + datetime.timedelta(hours=2), method='nearest')] stop2RWU = ts.index[ts.index.get_loc( suns(dd) + datetime.timedelta(hours=1), method='nearest')] except: stopRWU = tsx.index[nearby( tsx.index, suns(dd - datetime.timedelta(hours=24)) + datetime.timedelta(hours=1))] startRWU = tsx.index[nearby( tsx.index, sunr(dd) + datetime.timedelta(hours=2))] stop2RWU = tsx.index[nearby( tsx.index, suns(dd) + datetime.timedelta(hours=1))] return [stopRWU, startRWU, stop2RWU, 0] def idstep_startstop(dd): # return astro reference times for idealised step try: tin = ts.index[ts.index.get_loc( suns(dd - datetime.timedelta(hours=24)) - datetime.timedelta(hours=1.5), method='nearest')] tout = ts.index[ts.index.get_loc(sunr(dd) + datetime.timedelta(hours=2), method='nearest')] tix = ts.index[ts.index.get_loc(suns(dd) - datetime.timedelta(hours=0.5), method='nearest')] except: tin = ts.index[nearby( ts.index, suns(dd - datetime.timedelta(hours=24)) - datetime.timedelta(hours=1.5))] tout = ts.index[nearby(ts.index, sunr(dd) + datetime.timedelta(hours=2))] tix = ts.index[nearby(ts.index, suns(dd) - datetime.timedelta(hours=0.5))] return [tin, tout, tix] def dayRWU(dd): # get reference times [tin, tout, tix, evalx] = startstopRWU(dd) # check for soil moisture differences and min time spans if ((tout - tin).seconds < mintime * 3600.) | ( (tix - tout).seconds < mintime * 3600.): return [np.nan, np.nan, np.nan, np.nan, 2, evalx, tin, tout, tix] if any(dif_ts.loc[tin:tix] > maxdiffs): return [np.nan, np.nan, np.nan, np.nan, 3, evalx, tin, tout, tix] # build linear extrapolation model of night time change df = pd.DataFrame([ np.arange(len(ts.loc[tin:tout - datetime.timedelta(hours=1)])), ts.loc[tin:tout - -datetime.timedelta(hours=1)].values ]).T df.columns = ['x', 'y'] try: mod = smf.ols(formula='y ~ x', data=df) res = mod.fit() except: return [np.nan, np.nan, np.nan, np.nan, 0, evalx, tin, tout, tix] # build linear model of day time change df2 = pd.DataFrame( [np.arange(len(ts.loc[tout:tix])), ts.loc[tout:tix].values]).T df2.columns = ['x', 'y'] try: mod2 = smf.ols(formula='y ~ x', data=df2) res2 = mod2.fit() except: return [ np.nan, np.nan, res.params.x, np.nan, 0, evalx, tin, tout, tix ] # create dummy time series for night time extrapolation dummy = pd.date_range(tin, tix, freq=freqx.index[0]) fuse = pd.Series(data=res.params.Intercept + res.params.x * np.arange(len(dummy)), index=dummy) # control of assumptions of a step step_control = 0 if res.params.x / ( (6. * 3600.) / freqx.index[0].seconds ) > -0.5 / 6.: #night slope shall be more than minus 0.5 vol.% per 6h step_control += 10 if res.params.x / ( (6. * 3600.) / freqx.index[0].seconds ) < 1 / 6.: #night slope shall be less than plus 1 vol.% per 6h step_control += 100 if (res2.params.x < 0) & ( res2.params.x / ((6. * 3600.) / freqx.index[0].seconds) > -0.5 / 12. ): #day slope must be negative but more than minus 0.5 vol.% per 12h step_control += 1000 if res2.params.x < slope_diff * res.params.x: #day slope must be at least 3 times more steep than night (if night was negative) step_control += 1 if fuse.loc[tix] - ts.loc[tix] < 2.: #rwu should not exceed 2 mm/day step_control += 10000 # only if step_control == 1111 fully valid results: rwu = fuse.loc[tix] - ts.loc[tix] rwu_nonight = ts.loc[tout] - ts.loc[tix] return [ rwu, rwu_nonight, res.params.x, res2.params.x, step_control, evalx, tin, tout, tix ] def dayRWU2(dd, crit_nse=0.5): # perform comparison to idealised step before evaluation # get reference times [tin, tout, tix, evalx] = startstopRWU(dd) [dtin, dtout, dtix] = idstep_startstop(dd) # construct idealised step reference idx = pd.date_range(dtin, dtix, freq=freqx.index[0]) dummy = pd.Series(np.zeros(len(idx)) * np.nan, index=idx) dummy[dtin] = ts.loc[dtin] dummy[dtout + datetime.timedelta(hours=1)] = ts.loc[dtin] + 0.01 dummy[dtix - datetime.timedelta(hours=2.5)] = ts.loc[dtix] dummy = dummy.interpolate() dummyx = pd.concat([ dummy, ts.loc[tin - datetime.timedelta(hours=0.5):tix + datetime.timedelta(hours=0.5)] ], axis=1) dummyx.columns = ['ideal', 'obs'] dummyx = dummyx.dropna() # compare observed soil moisture dynamics with idealised step evaly = he.nse_c2m(dummyx.obs.values, dummyx.ideal.values) #if evaly >= crit_nse: [ rwu, rwu_nonight, resparamsx, res2paramsx, step_control, evalx, tin2, tout2, tix2 ] = dayRWU(dd) return [ rwu, rwu_nonight, resparamsx, res2paramsx, step_control, evalx, evaly, tin, tout, tix ] for dd in ddx[:-1]: try: RWU.loc[dd] = dayRWU2(dd) except: print(str(dd) + ' could not be processed.') return RWU