Skip to content

Commit ed3d29e

Browse files
committed
marge
1 parent 74d5897 commit ed3d29e

File tree

7 files changed

+192
-74
lines changed

7 files changed

+192
-74
lines changed

.gitignore

+2-1
Original file line numberDiff line numberDiff line change
@@ -169,5 +169,6 @@ log/
169169
calibrate/
170170
experiment.py
171171
nohup.out
172-
cache.jsonl
173172
quick_test.py
173+
*.jsonl
174+
**/config.yaml

pyduino/config.template.yaml

+84
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
hyperparameters:
2+
reset_density: true #Whether or not to use gotod
3+
log_name: #Log folder name (delete to use the default)
4+
density_param: DensidadeAtual #Parameter name for density counts.
5+
brilho_param: Brilho #When Brilho = 0, optimization is turned off.
6+
maximize: false
7+
rng_seed: 2 #Random seed parameter initialization
8+
ranges:
9+
branco:
10+
- 1
11+
- 100
12+
others:
13+
- 0
14+
- 100
15+
slave:
16+
port: "5000" #Must be a string
17+
network: "192.168.1.1/24"
18+
exclude: #Leave blank if there are none to exclude
19+
system:
20+
#About the partition system (This is done at `init_spectra.py`)
21+
#`all` will create a single manager for all reactors.
22+
#`single` will create a manager for each reactor.
23+
partition: all
24+
log_level: "DEBUG" #DEBUG, INFO, WARNING, ERROR, CRITICAL
25+
sync_clocks: false #Whether or not to sync the clocks of the slaves.
26+
initial_state: "preset_state.d/all.csv"
27+
reboot_wait_time: 5 #Time in seconds to wait after a reboot.
28+
relevant_parameters:
29+
# - brilho
30+
- branco
31+
- full
32+
- "440"
33+
- "470"
34+
- "495"
35+
- "530"
36+
- "595"
37+
- "634"
38+
- "660"
39+
- "684"
40+
irradiance:
41+
#brilho: 12
42+
"branco": 10.35
43+
"full": 11.50
44+
"440": 7.72
45+
"470": 8.50
46+
"495": 8.30
47+
"530": 8.56
48+
"595": 2.17
49+
"634": 3.44
50+
"660": 4.52
51+
"684": 5.74
52+
standard_parameters:
53+
#brilho: float
54+
branco: float
55+
full: float
56+
"440": float
57+
"470": float
58+
"495": float
59+
"530": float
60+
"595": float
61+
"634": float
62+
"660": float
63+
"684": float
64+
cor: int
65+
modopainel: int
66+
brilho: float
67+
bomdia: int
68+
boanoite: int
69+
tau: int
70+
step: int
71+
modotemp: int
72+
temp: int
73+
densidade: float
74+
mododil: int
75+
ar: int
76+
ima: int
77+
modoco2: int
78+
co2: int
79+
dtco2: int
80+
tensorboard:
81+
additional_parameters:
82+
- Brilho
83+
- Temp
84+
- pH

pyduino/log.py

+29-36
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
from datetime import datetime
55
import io
66
from glob import glob
7-
from uuid import uuid1
87
from tabulate import tabulate
98
from collections import OrderedDict
109
from datetime import datetime
@@ -37,7 +36,7 @@ def to_markdown_table(data: OrderedDict) -> str:
3736
def y_to_table(y):
3837
return tabulate(list(y.items()), tablefmt="pipe")
3938

40-
class log:
39+
class Log:
4140
@property
4241
def timestamp(self):
4342
"""str: Current date."""
@@ -49,15 +48,15 @@ def prefix(self):
4948

5049
def __init__(self,subdir,path="./log",name=None):
5150
"""
52-
Logs data into csvs with timestamps.
51+
Logs data into jsonls with timestamps.
5352
5453
Example:
5554
log_obj = log(['reactor_0','reactor_1'],path='./log',name='experiment_0')
5655
5756
log/YEAR/MONTH/
5857
├─ experiment_0/
59-
│ ├─ reactor_0.csv
60-
│ ├─ reactor_1.csv
58+
│ ├─ reactor_0.jsonl
59+
│ ├─ reactor_1.jsonl
6160
6261
Args:
6362
subdir (:obj:`list` of :obj:`str`): List of the names for the subdirectories of `path`.
@@ -75,7 +74,7 @@ def __init__(self,subdir,path="./log",name=None):
7574
self.subdir = subdir
7675
else:
7776
raise ValueError("Invalid type for subdir. Must be either a list of strings or a glob string.")
78-
self.subdir = list(map(lambda x: str(x)+".csv" if len(os.path.splitext(str(x))[1])==0 else str(x),self.subdir))
77+
self.subdir = list(map(lambda x: str(x)+".jsonl" if len(os.path.splitext(str(x))[1])==0 else str(x),self.subdir))
7978
self.first_timestamp = None
8079
self.data_frames = {}
8180

@@ -88,7 +87,7 @@ def __init__(self,subdir,path="./log",name=None):
8887
self.subdir = subdir
8988
else:
9089
raise ValueError("Invalid type for subdir. Must be either a list of strings or a glob string.")
91-
self.subdir = list(map(lambda x: str(x)+".csv" if len(os.path.splitext(str(x))[1])==0 else str(x),self.subdir))
90+
self.subdir = list(map(lambda x: str(x)+".jsonl" if len(os.path.splitext(str(x))[1])==0 else str(x),self.subdir))
9291
self.first_timestamp = None
9392
self.data_frames = {}
9493

@@ -100,19 +99,18 @@ def backup_config_file(self):
10099
with open(config_file) as cfile, open(filename,'w') as wfile:
101100
wfile.write(cfile.read())
102101

103-
def log_rows(self,rows,subdir,add_timestamp=True,tags=None,**kwargs):
102+
def log_rows(self,rows,subdir,add_timestamp=True,tags=None):
104103
"""
105-
Logs rows into csv format.
104+
Logs rows into jsonl format.
106105
107106
Args:
108107
rows (:obj:`list` of :obj:`dict`): List of dictionary-encoded rows or pandas dataframe.
109108
subdir (str): Subdirectory name. Intended to be an element of `self.subdir`.
110109
add_timestamp (bool,optional): Whether or not to include a timestamp column.
111110
tags (:obj:`dict` of :obj:`str`): Dictionary of strings to be inserted as constant columns.
112-
**kwargs: Additional arguments passed to `pandas.to_csv`.
113111
"""
114112
t = self.timestamp
115-
path = os.path.join(self.path,self.start_timestamp,f"{subdir}.csv")
113+
path = os.path.join(self.path,self.start_timestamp,f"{subdir}.jsonl")
116114

117115
df = pd.DataFrame()
118116
if isinstance(rows,list):
@@ -125,7 +123,7 @@ def log_rows(self,rows,subdir,add_timestamp=True,tags=None,**kwargs):
125123
if os.path.exists(path):
126124
if self.first_timestamp is None:
127125
with open(path) as file:
128-
head = pd.read_csv(io.StringIO(file.readline()+file.readline()),index_col=False,**kwargs)
126+
head = pd.read_json(io.StringIO(file.readline()+file.readline()), orient="records", lines=True)
129127
self.first_timestamp = datetime_from_str(head.log_timestamp[0])
130128
else:
131129
self.first_timestamp = t
@@ -136,25 +134,21 @@ def log_rows(self,rows,subdir,add_timestamp=True,tags=None,**kwargs):
136134
for key,value in tags.items():
137135
df.loc[:,key] = value
138136

139-
df.to_csv(
140-
path,
141-
mode="a",
142-
header=not os.path.exists(path),
143-
index=False,
144-
**kwargs
145-
)
137+
with open(path, mode="a") as log_file:
138+
log_file.write(df.to_json(orient="records", lines=True))
139+
146140
return df
147141
def log_many_rows(self,data,**kwargs):
148142
"""
149-
Logs rows into csv format.
143+
Logs rows into jsonl format.
150144
151145
Args:
152146
data (:obj:`dict` of :obj:`dict`): Dictionary encoded data frame.
153147
**kwargs: Additional arguments passed to `self.log_rows`.
154148
"""
155149
self.data_frames = {}
156150
for _id,row in data.items():
157-
df = self.log_rows(rows=[row],subdir=_id,sep='\t',**kwargs)
151+
df = self.log_rows(rows=[row],subdir=_id,**kwargs)
158152
self.data_frames[_id] = df
159153
self.data_frames = pd.concat(list(self.data_frames.values()))
160154

@@ -164,7 +158,7 @@ def log_optimal(self,column,maximum=True,**kwargs):
164158
"""
165159
i=self.data_frames.loc[:,column].astype(float).argmax() if maximum else self.data_frames.loc[:,column].astype(float).argmin()
166160
self.df_opt = self.data_frames.iloc[i,:]
167-
self.log_rows(rows=[self.df_opt.to_dict()],subdir='opt',sep='\t',**kwargs)
161+
self.log_rows(rows=[self.df_opt.to_dict()],subdir='opt',**kwargs)
168162

169163
def log_average(self, cols: list, **kwargs):
170164
"""
@@ -178,38 +172,38 @@ def log_average(self, cols: list, **kwargs):
178172
df.loc[:, cols] = df.loc[:, cols].astype(float)
179173
df.elapsed_time_hours = df.elapsed_time_hours.round(decimals=2)
180174
self.df_avg = df.loc[:, cols + ['elapsed_time_hours']].groupby("elapsed_time_hours").mean().reset_index()
181-
self.log_rows(rows=self.df_avg, subdir='avg', sep='\t', **kwargs)
175+
self.log_rows(rows=self.df_avg, subdir='avg', **kwargs)
182176

183-
def cache_data(self,rows,path="./cache.csv",**kwargs):
177+
def cache_data(self,rows,path="./cache.jsonl",**kwargs):
184178
"""
185-
Dumps rows into a single csv.
179+
Dumps rows into a single jsonl.
186180
187181
Args:
188182
rows (:obj:`list` of :obj:`dict`): List of dictionary-encoded rows.
189-
path (str): Path to the csv file.
183+
path (str): Path to the jsonl file.
190184
"""
191-
pd.DataFrame(rows).T.to_csv(path,**kwargs)
185+
pd.DataFrame(rows).T.to_json(path, orient="records", lines=True, **kwargs)
192186

193-
def transpose(self,columns,destination,sep='\t',skip=1,**kwargs):
187+
def transpose(self,columns,destination,skip=1,**kwargs):
194188
"""
195-
Maps reactor csv to column csvs with columns given by columns.
189+
Maps reactor jsonl to column jsonls with columns given by columns.
196190
197191
Args:
198192
columns (:obj:list of :obj:str): List of columns to extract.
199193
destination (str): Destination path. Creates directories as needed and overwrites any existing files.
200-
sep (str, optional): Column separator. Defaults to '\t'.
194+
201195
skip (int, optional): How many rows to jump while reading the input files. Defaults to 1.
202196
"""
203197
dfs = []
204198
for file in self.paths:
205-
df = pd.read_csv(file,index_col=False,sep=sep,**kwargs)
199+
df = pd.read_json(file, orient="records", lines=True, **kwargs)
206200
df['FILE'] = file
207201
dfs.append(df.iloc[::skip,:])
208202
df = pd.concat(dfs)
209203

210204
for column in columns:
211205
Path(destination).mkdir(parents=True,exist_ok=True)
212-
df.loc[:,['ID','FILE',column,'elapsed_time_hours']].to_csv(os.path.join(destination,f"{column}.csv"),sep=sep)
206+
df.loc[:,['ID','FILE',column,'elapsed_time_hours']].to_json(os.path.join(destination,f"{column}.jsonl"), orient="records", lines=True)
213207

214208

215209
class LogAggregator:
@@ -225,20 +219,19 @@ def __init__(self,log_paths,timestamp_col="log_timestamp",elapsed_time_col="elap
225219
self.glob_list = log_paths
226220
self.timestamp_col = timestamp_col
227221
self.elapsed_time_col = elapsed_time_col
228-
def agg(self,destination,skip=1,sep='\t',**kwargs):
222+
def agg(self,destination,skip=1,**kwargs):
229223
"""
230224
Aggregator
231225
232226
Args:
233227
destination (str): Destination path. Creates directories as needed and overwrites any existing files.
234228
skip (int, optional): How many rows to jump while reading the input files. Defaults to 1.
235-
sep (str, optional): Column separator. Defaults to '\t'.
236229
"""
237230
dfs = {}
238231
for path in self.glob_list:
239232
for file in glob(path):
240233
basename = os.path.basename(file)
241-
df = pd.read_csv(file,index_col=False,sep=sep,dtype={self.elapsed_time_col:float},**kwargs)
234+
df = pd.read_json(file, orient="records", lines=True, dtype={self.elapsed_time_col:float},**kwargs)
242235
df = df.iloc[::skip,:]
243236
df['FILE'] = file
244237
if dfs.get(basename,None) is not None:
@@ -256,5 +249,5 @@ def agg(self,destination,skip=1,sep='\t',**kwargs):
256249
for filename, df in dfs.items():
257250
Path(destination).mkdir(parents=True,exist_ok=True)
258251
path = os.path.join(destination,filename)
259-
df.to_csv(path,sep=sep,index=False)
252+
df.to_json(path, orient="records", lines=True)
260253

pyduino/pyduino2.py

+17-9
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from time import sleep, time
44
import pandas as pd
55
from collections import OrderedDict
6-
from pyduino.log import log
6+
from pyduino.log import Log
77
import pandas as pd
88
from multiprocessing import Pool, Process
99
from functools import partial
@@ -227,11 +227,10 @@ def send(self,command,await_response=True,**kwargs):
227227
r._send(command)
228228
return out
229229

230-
def send_parallel(self,command,delay,await_response=True):
231-
out = []
230+
def send_parallel(self,command,await_response=True):
232231
with Pool(7) as p:
233232
out = p.map(partial(send_wrapper,command=command,await_response=await_response),list(self.reactors.items()))
234-
return out
233+
return dict(out)
235234

236235
def set(self, data=None, **kwargs):
237236
for k,r in self.reactors.items():
@@ -268,9 +267,18 @@ def log_init(self,**kwargs):
268267
Args:
269268
name (str): Name of the subdirectory in the log folder where the files will be saved.
270269
"""
271-
self.log = log(subdir=list(self.reactors.keys()),**kwargs)
270+
self.log = Log(subdir=list(self.reactors.keys()),**kwargs)
272271
print(f"Log will be saved on: {bcolors.OKGREEN}{self.log.prefix}{bcolors.ENDC}")
273272

273+
@property
274+
def brilho(self):
275+
"""
276+
Convenience method to get brilho from reactors.
277+
"""
278+
out = self.send_parallel(f"get({self.brilho_param.lower()})")
279+
out = {k: float(v.strip()) for k,v in out.items()}
280+
return out
281+
274282
def dados(self,save_cache=True):
275283
"""
276284
Get data from Arduinos.
@@ -284,7 +292,7 @@ def dados(self,save_cache=True):
284292

285293
len_empty = None
286294
while len_empty!=0:
287-
rows = self.send_parallel("dados",delay=20,await_response=True)
295+
rows = self.send_parallel("dados",await_response=True).items()
288296
#Checking if any reactor didn't respond.
289297
empty = list(filter(lambda x: x[1] is None,rows))
290298
len_empty = len(empty)
@@ -305,7 +313,7 @@ def dados(self,save_cache=True):
305313

306314
rows = dict(map(lambda x: (x[0],OrderedDict(zip(self.header,x[1].split(" ")))),rows))
307315
if save_cache:
308-
self.log.cache_data(rows,sep='\t',index=False) #Index set to False because ID already exists in rows.
316+
self.log.cache_data(rows) #Index set to False because ID already exists in rows.
309317
return rows
310318

311319
def log_dados(self,save_cache=True):
@@ -322,10 +330,10 @@ def log_dados(self,save_cache=True):
322330
rows = list(map(lambda x: (x[0],OrderedDict(zip(header,x[1].split(" ")))),rows))
323331

324332
for _id,row in rows:
325-
self.log.log_rows(rows=[row],subdir=_id,sep='\t')
333+
self.log.log_rows(rows=[row],subdir=_id)
326334
rows = dict(rows)
327335
if save_cache:
328-
self.log.cache_data(rows,sep='\t',index=False) #Index set to False because ID already exists in rows.
336+
self.log.cache_data(rows) #Index set to False because ID already exists in rows.
329337
return rows
330338

331339
def set_preset_state(self,path="preset_state.csv",sep="\t",chunksize=4, params=PATHS.REACTOR_PARAMETERS, **kwargs):

0 commit comments

Comments
 (0)