Welcome to The Smell Engine’s documentation!¶
About¶
The Smell Engine is a python framework for controlling an olfactometer to generate odors. See paper for more detail: [link to paper]
Smell Engine¶
-
class
olfactometer.smell_engine.
SmellEngine
(total_flow_rate=4000, n_odorants=3, data_container=None, debug_mode=True, write_flag=False, PID_mode=False, look_up_table_path=None, oms=None)¶ Bases:
object
-
append
(val)¶
-
automation_set_mfc_setpoints
(mfc_setpoints)¶ Override mfc setpoints in order B, A, C
-
ids
¶ List[] specifying each MFCs flow rate relative to its max.
-
-
calculate_target_achieved_error
()¶
-
close_smell_engine
()¶
-
get_desired_concentrations
()¶
-
get_mfc_setpoints
()¶
-
get_molecular_ids
()¶
-
get_valve_duty_cycles
()¶
-
initialize_equipment
()¶ Configure olfactometer equipment via Smell Composer component(s). First we specify molecules by CID number and define their vapor pressure, densities, and solution. Instantiate the olfactometer. Determines the jars and dilutions required to achieve the target specified per molecule. Perform optimization to configure olfactometer Format values for ValveDriver to execute.
-
initialize_olfactometer
()¶ Initialize Smell Driver instance which instantiates a ValveDriver instance. This instance is then assigned to the Smell Composer so the communication line of odorant mixtures is established.
-
debug_mode
¶ Flag denoting physical vs simulated hardware.
-
-
initialize_smell_engine_system
(with_nidaq=True)¶ Presumes user has manually set OM ids before initializing system pipeline
-
property
om_dilutions
¶
-
property
om_ids
¶
-
print_data_binary
(concentration)¶ A debug method for printing binary representations of concentrations (digital states of olfactometer).
- Parameters
concentration (
list
offloat
) – List of concentration states.
-
set_desired_concentrations
(concentrations)¶ Reads and writes concentration values to Smell Engine and Valve Driver
-
concentrations
¶ List containing concentration values
-
-
set_odorant_molecule_dilutions
(dilutions)¶ Assign PubChemID’s on startup to the Valve Driver cid’s.
-
ids
¶ List containing uniquely identifiable int values of OM ids
-
-
set_odorant_molecule_ids
(ids)¶ Assign PubChemID’s on startup to the Valve Driver cid’s.
-
ids
¶ List containing uniquely identifiable int values of OM ids
-
-
set_olfactometer_target_outflow
(m_flowrate)¶
-
set_starting_concentration
(starting_vector)¶
-
Odorant Molecules (PubChem)¶
Classes for odorants, mixtures, chemical orders, etc.
-
class
olfactometer.odorants.
Molecule
(cid=None, name=None, fill=False, vapor_press=None, dens=None)¶ Bases:
object
This module extracts various chemical and physical properties of odorous molecular compounds using PUG REST API. Portions of the codebase have benefitted from work by Maxim Shevelev <mdshev7@gmail.com>
For details about PubChem’s PUG REST API please visit https://pubchem.ncbi.nlm.nih.gov/pug_rest/PUG_REST.html
-
fill_details
()¶ Populate odorant molecule properties to include molecular weight and cid/name.
-
get_addtional_om_props
(required_properties)¶ Found method as courtesy of Maxim Shevelev (Github: @mawansui) 1. Accepts the compound name 2. Gets the CID for this compound 3. Searches PubChem for data for the specified CID 4. Cycles through the fetched data to select required fields 5. Returns a dictionary with specified properties of specified compound
-
get_cid_by_name
(compound_name)¶ Accepts the compound name
Searches PubChem by this name
Returns the compound’s PubChem CID
-
get_cid_from_api
()¶ Obtain pub chem ID from OM name.
-
get_density
()¶ Obtain odorant molecule density by searching density property and extra additional properties from PubChem.
-
get_vapor_pressure
()¶ Obtain odorant molecule Vapor Pressure from PubChem.
-
pubchem_parsing
(url)¶ Get the link to PubChem API, parse it for JSON and then translate that to Python dictionary; This is just to follow the DRY principle
-
Smell Controller¶
-
class
olfactometer.smell_controller.
SmellController
(olfactometer, data_container=None, valve_driver=None, kdtree_flag=False, kdtree=None, smell_data_frame=None)¶ Bases:
object
-
classmethod
calc_conc
(variables, n_jars, max_flow_rates, A)¶ This method is invoked externally to calculate concentration given olfactometer configuration variables: MUST BE np.array! Contains olfactometer mfc values and valve duty cycles n_jars: assigneed from class instance max_flow_rates: assigneed from class instance A: Gas Phase Concentration of jars x odorants
-
clean_valve_mfc_values
(values=None, print_flow_rates=False)¶ Convert dictionary that looks like: {‘w1MFC_A_High’: 0.8840516038671588, ‘w2MFC_A_High’: 0, ‘w1MFC_B_Low’: 0.11551628411711523, ‘w2MFC_B_Low’: 0, ‘fMFC_A_High’: array(1.9601) * cc/min, ‘fMFC_B_Low’: array(0.01) * cc/min, ‘MFC_Carrier’: array(2198.0299) * cc/min}
-
find_odorant_id_by_index
(m_index)¶
-
get_max_flow_rates
()¶
-
get_vapor_concs_dense
(target_odorants)¶
-
kdtree_lookup
(target_dense, mfc_names, F)¶
-
lls_olfactometer_scheduler
(vapor_concs_dense, target_outflow_rate_ccm, target_dense)¶
-
property
max_outflow_rate
¶ The maximum possible flow rate if all connected-in-parallel MFCs are at their maximum flow rates
-
mfc_flow_rates_to_voltages
(values)¶
-
property
olfactometer_schedule
¶
-
optimization_report
()¶ Report on optimization quality
-
optimize
(target_outflow_concs=None, target_outflow_rate=None, report=False)¶ Find the valve duty cycles and MFC settings that bring this route closest to target. This will be done by varying actual valve positions and flow rates, so it should only be done on a virtual olfactometer
-
property
outflow_fractions
¶
-
property
outflow_rates
¶
-
classmethod
residuals
(variables, x, n_jars, max_flow_rates, total_vapor, fixed_A, fixed_B, alpha)¶ This method is invoked by the non-linear least squares solver. wNA: The fraction of time that valve N is in state A wNB: The fraction of the remaining time that valve N is in state B fA: The flow rate through MFC A fB: The flow rate through MFC B
-
property
target_outflow
¶
-
property
target_outflow_concs
¶
-
property
target_outflow_rate
¶
-
update_target
(report=False)¶ Executed externally, ideally through the SmellEngineCommunicator class. This method takes the assigned target concentrations and flow rate then message passes target states through the Smell Engine pipeline.
-
update_target_from_logical
()¶
-
classmethod
-
olfactometer.smell_controller.
calc_conc_jit
(variables, n_jars, max_flow_rates, A)¶
Valve Driver¶
-
class
olfactometer.valve_driver.
ValveDriver
(olfactometer=None, data_container=None, debug_mode=False, PID_mode=False)¶ Bases:
object
ValveDriver is responsible for interfacing with NI-DAQmx hardware using the nidaqmx API. Provides continuous virtual communication lines with MFCs (analog) and olfactometer valves (digital).
-
olf
¶ List of mfc voltage values indexed accurately.
-
cids
¶ A ordered list of concentration ids for each valve.
-
abort
()¶ Resets NI-DAQmx device to initialized state. All prior tasks and defined channel lines are aborted.
-
close_tasks
()¶ Closes all created/open NIDAQ tasks.
-
convert_concentration_format
(data_input, debug=False)¶ Read in a list of concentrations, convert each individual concentration A/B/off state into a sequence of binary control signals for olfactometer. :param d_in: :type d_in: list of `
- Returns
A list of 5 concentration values and there states in A/B.
-
format_bits
(valve_index, state)¶ Each valve state is identified by A, B, None. The valve state is represented as a 32 bit unsigned integer. If state A, first 16 bits are used to configure digital state of olfactometer. If state B, last 16 bits are used.
- Parameters
valve_index (int) – Integer indexing of valve state (non-zero).
state (str) – A,B,None.
- Returns
Binary representation of olfactometer state.
- Return type
uint32
- Raises
Exception – Invalid state requested.
-
generate_analog_frame_writes
(analog_states)¶ Creates list of analog states to be written to MFCs.
- Parameters
analog_states (
dictionary
of(int, float)
) – A index identifier for MFC and the requested voltage values supplied.- Returns
List of voltage values per MFC.
- Return type
(
list
offloat
)
-
generate_digital_frame_writes
(valve_durations)¶ Create list (of size samples_per_frame) to populate with 32 bit values representative of the digital states for each valve.
To turn a respective valve on, it’s index location within first 16 bits of a 32-bit write must be set to high. To turn a respective valve off, it’s index location within last 16 bits of a 32-bit write must be set to high.
- Parameters
valve_durations (
dictionary
of(int, float)
) – Dictionary of valve indexes and their respective states (time in ms for A,B,off).- Returns
Writes will be written to olfactometer as multiline/channel write.
- Return type
(
list
ofuint32
)
-
init_analog_in_task
(num_samples=50, task_name='Analog_In', channel_name='analog_in_channel')¶ Initializing an Analog Input Task to read samples from the specified channel.
- Parameters
num_samples (int) – Specify # of samples per channel, default is 50
task_name (str) – Task name, used for uniquely identifying task instance.
- Returns
Success/error status represented with 1/-1.
- Raises
nidaqmx.DaqError – An error occured when trying to add an analog voltage virtual communication channel.
-
init_analog_task
(mfc_flat_list, task_name='Analog_Task', channel_name='analog_channel')¶ Initializing an Analog Output Task and Channel communication line. List of analog channels [0:3] along with voltage rates are initialized via nidaqmx API.
- Parameters
mfc_flat_list – A 1D list containing analog channels and voltages.
task_name (str) – Task name, used for uniquely identifying task instance.
- Returns
Success/error status represented with 1/-1.
- Raises
nidaqmx.DaqError – An error occured when trying to add an analog voltage virtual communication channel.
-
init_digital_task
(task_name='DigitalTask', channel_name='digital_channel')¶ Create task object with digital out on port0. Configure task to use 1 channel for all liens of communication. Append to list of tasks and update state of olfactometer.
- Parameters
task_name (str) – Task name, used for uniquely identifying task instance.
channel_name (str) – Channel name, used for unuquely identifying different channel comm lines.
- Returns
Success/error status represented with 1/-1.
- Raises
nidaqmx.DaqError – An error occured when trying to add an analog voltage virtual communication channel.
-
initialize
()¶ Reading and saving device information from NI-DAQmx hardware. Existing device references and tasks are reset.
- Returns
Success/error status.
- Raises
nidaqmx.DaqError – An error occurred when attempting to read NIDAQ hardware information.
Error codes can be found in the nidaqmx errors.py system file. –
-
issue_odorants
(valve_mfc_values)¶ Executed externally to update olfactometer schedule of odor samples, this method converts the olfactometer schedule into digital and analog control signals. Olfactometer Schedule Examples: {‘valves’:
- [
(Valve Number, time in state A, time in state B) (1, 0.6523873263385962, 0.3433522990024116), (2, 0.6523929695332448, 0.34373085569547107)
- ], ‘mfcs’:
{MyMediumMFC: MFC_A_High (1.0 L/min): array(value) * V, MyLowMFC: MFC_B_Low (10.0 cc/min): array(value) * V, MyHighMFC: MFC_Carrier (10.0 L/min): array(values) * V}
}
- Parameters
valve_mfc_values (
dictionary
of(str, float)
) – Expected dictionary of mfc voltages and valve state durations.
-
print_data_binary
(concentration)¶ A debug method for printing binary representations of concentrations (digital states of olfactometer).
- Parameters
concentration (
list
offloat
) – List of concentration states.
-
set_mfc_setpoints
(setpoints)¶ Toggle override for analog mfc setpoints and assign user defined setpoints
- Parameters
setpoints – List containing voltage values per mfc
-
set_task_clock
(task, samples_per_frame=50, frames_per_s=1, repeats=1)¶ Sets rate, number of samples, and source of the Sample Clock for developer-specified task.
- Parameters
task (
nidaqmx.task.Task
) – Task object to which sample clock is being configured for.samples_per_frame (int) – Samples generated per frame.
frames_per_s (int) – Frames per second for sampling.
repeats (int, optional) – Duplicating samples across each channel.
-
set_valve_states
(valve_states)¶ Toggle overrides for digital valve states and assign user-defined valve states
- Parameters
valve_states – A list of tuples containing high/low toggles for valve
-
specify_analog_frame_writes
(analog_states)¶ Provide a defined list of analog states to be written to MFCs.
- Parameters
analog_states (
list
of(float, int)
) – A index identifier for MFC and the requested voltage values supplied.- Returns
List of voltage values per MFC.
- Return type
(
list
offloat
)
-
specify_digital_frame_writes
(valve_states)¶ Given valve states, samples are generated with half containing given valve state other half being off
- Parameters
valve_states (
list
) – List of tuples representing A,B states for each valve
-
timer_pause
()¶ Halts thread instance.
-
timer_resume
()¶ Continues thread after being paused.
-
timer_run
()¶ The ‘update’ method for the thread instance. Writes digital valve states to olfactometer at the defined timer_interval rate. If writing values is unsuccessfull thread instance halts.
-
timer_setup
(interval=None)¶ Configuration of thread instance. Thread runs at a user-defined time interval to which it issues commands to hardware.
- Parameters
interval (float) – Rate at which thread executs write commands to olfactometer.
-
timer_start
()¶ Starts thread instance.
-
timer_stop
()¶ Pauses thread, turns off all valve, ends defined virtual communication, and releases Task object instance from memory.
-
write_output
(digital_values, analog_values=[])¶ This method will write a list of valve commands to olfactometer.
- Parameters
None –
- Returns
Success/error message. 0 success, -1 error.
- Return type
int
-
write_zeroes
()¶ This method will write a list of valve commands to olfactometer.
- Returns
A list of 5 concentration values and there states in A/B.
-