def fftw_multi_normxcorr(template_array, stream_array, pad_array, seed_ids,<EOL>cores_inner, cores_outer):
utilslib = _load_cdll('<STR_LIT>')<EOL>utilslib.multi_normxcorr_fftw.argtypes = [<EOL>np.ctypeslib.ndpointer(dtype=np.float32,<EOL>flags=native_str('<STR_LIT>')),<EOL>ctypes.c_long, ctypes.c_long, ctypes.c_long,<EOL>np.ctypeslib.ndpointer(dtype=np.float32,<EOL>flags=native_str('<STR_LIT>')),<EOL>ctypes.c_long,<EOL>np.ctypeslib.ndpointer(dtype=np.float32,<EOL>flags=native_str('<STR_LIT>')),<EOL>ctypes.c_long,<EOL>np.ctypeslib.ndpointer(dtype=np.intc,<EOL>flags=native_str('<STR_LIT>')),<EOL>np.ctypeslib.ndpointer(dtype=np.intc,<EOL>flags=native_str('<STR_LIT>')),<EOL>ctypes.c_int, ctypes.c_int,<EOL>np.ctypeslib.ndpointer(dtype=np.intc,<EOL>flags=native_str('<STR_LIT>'))]<EOL>utilslib.multi_normxcorr_fftw.restype = ctypes.c_int<EOL>'''<STR_LIT>'''<EOL>used_chans = []<EOL>template_len = template_array[seed_ids[<NUM_LIT:0>]].shape[<NUM_LIT:1>]<EOL>for seed_id in seed_ids:<EOL><INDENT>used_chans.append(~np.isnan(template_array[seed_id]).any(axis=<NUM_LIT:1>))<EOL>template_array[seed_id] = (<EOL>(template_array[seed_id] -<EOL>template_array[seed_id].mean(axis=-<NUM_LIT:1>, keepdims=True)) / (<EOL>template_array[seed_id].std(axis=-<NUM_LIT:1>, keepdims=True) *<EOL>template_len))<EOL>template_array[seed_id] = np.nan_to_num(template_array[seed_id])<EOL><DEDENT>n_channels = len(seed_ids)<EOL>n_templates = template_array[seed_ids[<NUM_LIT:0>]].shape[<NUM_LIT:0>]<EOL>image_len = stream_array[seed_ids[<NUM_LIT:0>]].shape[<NUM_LIT:0>]<EOL>fft_len = next_fast_len(template_len + image_len - <NUM_LIT:1>)<EOL>template_array = np.ascontiguousarray([template_array[x]<EOL>for x in seed_ids],<EOL>dtype=np.float32)<EOL>for x in seed_ids:<EOL><INDENT>if not np.all(stream_array[x] == <NUM_LIT:0>) and np.var(stream_array[x]) < <NUM_LIT>:<EOL><INDENT>stream_array *= <NUM_LIT><EOL>warnings.warn("<STR_LIT>"<EOL>"<STR_LIT>".format(x))<EOL><DEDENT><DEDENT>stream_array = np.ascontiguousarray([stream_array[x] for x in seed_ids],<EOL>dtype=np.float32)<EOL>cccs = np.zeros((n_templates, image_len - template_len + <NUM_LIT:1>),<EOL>np.float32)<EOL>used_chans_np = np.ascontiguousarray(used_chans, dtype=np.intc)<EOL>pad_array_np = np.ascontiguousarray([pad_array[seed_id]<EOL>for seed_id in seed_ids],<EOL>dtype=np.intc)<EOL>variance_warnings = np.ascontiguousarray(<EOL>np.zeros(n_channels), dtype=np.intc)<EOL>ret = utilslib.multi_normxcorr_fftw(<EOL>template_array, n_templates, template_len, n_channels, stream_array,<EOL>image_len, cccs, fft_len, used_chans_np, pad_array_np, cores_outer,<EOL>cores_inner, variance_warnings)<EOL>if ret < <NUM_LIT:0>:<EOL><INDENT>raise MemoryError("<STR_LIT>")<EOL><DEDENT>elif ret not in [<NUM_LIT:0>, <NUM_LIT>]:<EOL><INDENT>print('<STR_LIT>')<EOL>print('<STR_LIT>' %<EOL>(cccs.max(), np.unravel_index(cccs.argmax(), cccs.shape)))<EOL>print('<STR_LIT>' %<EOL>(cccs.min(), np.unravel_index(cccs.argmin(), cccs.shape)))<EOL>raise CorrelationError("<STR_LIT>")<EOL><DEDENT>elif ret == <NUM_LIT>:<EOL><INDENT>warnings.warn("<STR_LIT>"<EOL>"<STR_LIT>")<EOL><DEDENT>for i, variance_warning in enumerate(variance_warnings):<EOL><INDENT>if variance_warning and variance_warning > template_len:<EOL><INDENT>warnings.warn("<STR_LIT>"<EOL>"<STR_LIT>".format(variance_warning,<EOL>seed_ids[i]))<EOL><DEDENT><DEDENT>return cccs, used_chans<EOL>
Use a C loop rather than a Python loop - in some cases this will be fast.

:type template_array: dict
:param template_array:
:type stream_array: dict
:param stream_array:
:type pad_array: dict
:param pad_array:
:type seed_ids: list
:param seed_ids:

rtype: np.ndarray, list
:return: 3D Array of cross-correlations and list of used channels.