pax_global_header 0000666 0000000 0000000 00000000064 15247271707 0014526 g ustar 00root root 0000000 0000000 52 comment=7c3a65d204ade97bb49d91d116e28a373ac660ce
primer3-py-2.3.1/ 0000775 0000000 0000000 00000000000 15247271707 0013540 5 ustar 00root root 0000000 0000000 primer3-py-2.3.1/.github/ 0000775 0000000 0000000 00000000000 15247271707 0015100 5 ustar 00root root 0000000 0000000 primer3-py-2.3.1/.github/workflows/ 0000775 0000000 0000000 00000000000 15247271707 0017135 5 ustar 00root root 0000000 0000000 primer3-py-2.3.1/.github/workflows/docs.yml 0000664 0000000 0000000 00000005066 15247271707 0020617 0 ustar 00root root 0000000 0000000 # .github/workflows/docs.yml
# Documentation workflow for building and publishing Sphinx docs
# - Builds HTML documentation using Sphinx
# - Publishes to gh-pages on version tags
# - Publishes to gh-pages-test on doc branches
# - Allows manual publishing to either branch via workflow dispatch
#
# NOTE: Requires PRIMER3_TOKEN secret with "Contents" Read/Write permissions
name: Documentation
on:
push:
tags:
- "v[0-9]+.[0-9]+.[0-9]+"
branches:
- "**docs**" # Matches any branch that contains "docs"
# Allow manual triggering with branch choice
workflow_dispatch:
inputs:
target_branch:
description: 'Target branch for documentation'
required: true
default: 'gh-pages-test'
type: 'choice'
options:
- 'gh-pages'
- 'gh-pages-test'
jobs:
build-and-deploy:
name: Build and deploy documentation
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 1 # Shallow clone is fine for docs
persist-credentials: false # Don't persist credentials as we use PRIMER3_TOKEN explicitly
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.13'
cache: 'pip'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
python -m pip install -e ".[docs]"
- name: Build documentation
run: |
cd docs/
make html
cd ..
- name: Determine deployment branch
run: |
TAG_NAME=${GITHUB_REF#refs/tags/}
if [[ "$GITHUB_EVENT_NAME" == "workflow_dispatch" ]]; then
echo "BRANCH_NAME=${{ github.event.inputs.target_branch }}" >> $GITHUB_ENV
elif [[ "$TAG_NAME" == v* ]]; then
echo "BRANCH_NAME=gh-pages" >> $GITHUB_ENV
else
echo "BRANCH_NAME=gh-pages-test" >> $GITHUB_ENV
fi
- name: Prepare deployment
run: |
git clone https://github.com/libnano/primer3-py.git --branch $BRANCH_NAME --single-branch gh-pages
cp -r docs/_build/html/* gh-pages/
cd gh-pages
git config --local user.email "action@github.com"
git config --local user.name "GitHub Action"
git add .
git commit -m "Update documentation" -a || true
- name: Deploy documentation
uses: ad-m/github-push-action@v0.8.0
with:
branch: ${{ env.BRANCH_NAME }}
directory: gh-pages
github_token: ${{ secrets.PRIMER3_TOKEN }}
force: true
primer3-py-2.3.1/.github/workflows/release.yml 0000664 0000000 0000000 00000016471 15247271707 0021311 0 ustar 00root root 0000000 0000000 # .github/workflows/release.yml
# Release workflow that builds and publishes packages to PyPI
# - Builds wheels for all supported Python versions and platforms
# - Builds source distribution
# - Uses __init__.py version as source of truth (supports any valid PEP 440 version)
# - For test builds: adds .devN suffix (e.g., 2.1.0.dev1 or 2.1.0a1.dev1)
# - For production: uses base version, adds .postN only if rebuild needed
# See https://github.com/pypa/cibuildwheel for details
name: Release
on:
workflow_dispatch:
inputs:
is_test:
description: 'Push to TestPyPI'
type: boolean
default: true
required: true
build_number:
description: 'Build number (adds .devN for test, .postN for production rebuild if > 1)'
type: string
required: true
default: '1'
jobs:
validate-version:
name: Validate package version
runs-on: ubuntu-latest
outputs:
version: ${{ steps.get-version.outputs.version }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0 # Need full history for tags
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.13'
- name: Get version from __init__.py
id: get-version
run: |
# Extract version from __init__.py
# This supports any valid PEP 440 version including pre-releases (e.g., 2.1.0a1)
VERSION=$(sed -n "s/^__version__ = '\(.*\)'/\1/p" primer3/__init__.py)
echo "version=${VERSION}" >> $GITHUB_OUTPUT
echo "Base version from __init__.py: ${VERSION}"
# If this is a tagged commit, validate tag matches version
# For pre-releases: tag should match exactly (e.g., v2.1.0a1)
GIT_TAG=$(git describe --exact-match --tags HEAD 2>/dev/null || echo "")
if [[ -n "$GIT_TAG" ]]; then
# Remove 'v' prefix if present
TAG_VERSION=${GIT_TAG#v}
if [[ "$VERSION" != "$TAG_VERSION" ]]; then
echo "Error: __init__.py version ${VERSION} does not match git tag ${TAG_VERSION}"
exit 1
fi
echo "Version matches git tag"
fi
build-wheels:
name: Build wheel for ${{ matrix.os }} / Python ${{ matrix.python-version }}
needs: validate-version
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-22.04, macos-latest, windows-2022]
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13", "3.14"]
fail-fast: false
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Configure version
shell: bash
run: |
# Get base version from validate job
BASE_VERSION="${{ needs.validate-version.outputs.version }}"
if [[ "${{ inputs.is_test }}" == "true" ]]; then
# Test builds always use .devN
VERSION="${BASE_VERSION}.dev${{ inputs.build_number }}"
else
# Production builds only use .postN if build_number > 1
if [[ "${{ inputs.build_number }}" == "1" ]]; then
VERSION="${BASE_VERSION}"
else
# Subtract 1 from build_number for post suffix (so first retry is post1)
POST_NUM=$((${{ inputs.build_number }} - 1))
VERSION="${BASE_VERSION}.post${POST_NUM}"
fi
fi
echo "PACKAGE_VERSION=${VERSION}" >> $GITHUB_ENV
# Update version in setup.py
sed -i.bak "s/version=.*,/version='${VERSION}',/" setup.py
- name: Build wheels
uses: pypa/cibuildwheel@v3.3.1
env:
CIBW_PROJECT_REQUIRES_PYTHON: "==${{ matrix.python-version }}.*"
CIBW_SKIP: "{*-musllinux_*,pp*}" # Skip musl linux and PyPy versions
CIBW_ARCHS_MACOS: "${{ matrix.python-version > 3.8 && 'x86_64 arm64' || 'x86_64' }}"
CIBW_ARCHS_LINUX: "auto64"
CIBW_ARCHS_WINDOWS: "auto64"
MACOSX_DEPLOYMENT_TARGET: "10.14"
CIBW_BEFORE_BUILD: >-
python -m pip install --upgrade pip setuptools wheel &&
cd {project} &&
python -m pip install -e ".[dev]"
CIBW_TEST_COMMAND_MACOS: "pytest {project}/tests/test_thermoanalysis.py -v"
CIBW_TEST_COMMAND_LINUX: "pytest {project}/tests/test_thermoanalysis.py -v"
CIBW_TEST_COMMAND_WINDOWS: "pytest {project}\\tests\\test_thermoanalysis.py"
CIBW_BUILD_VERBOSITY: 1
- name: Upload wheel artifacts
uses: actions/upload-artifact@v4
with:
name: dist-${{ matrix.python-version }}-${{ matrix.os }}
path: ./wheelhouse/*.whl
build-sdist:
name: Build source distribution
needs: validate-version
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Configure version
shell: bash
run: |
# Get base version from validate job
BASE_VERSION="${{ needs.validate-version.outputs.version }}"
if [[ "${{ inputs.is_test }}" == "true" ]]; then
# Test builds always use .devN
VERSION="${BASE_VERSION}.dev${{ inputs.build_number }}"
else
# Production builds only use .postN if build_number > 1
if [[ "${{ inputs.build_number }}" == "1" ]]; then
VERSION="${BASE_VERSION}"
else
# Subtract 1 from build_number for post suffix (so first retry is post1)
POST_NUM=$((${{ inputs.build_number }} - 1))
VERSION="${BASE_VERSION}.post${POST_NUM}"
fi
fi
echo "PACKAGE_VERSION=${VERSION}" >> $GITHUB_ENV
# Update version in setup.py
sed -i.bak "s/version=.*,/version='${VERSION}',/" setup.py
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.13'
cache: 'pip'
- name: Install build dependencies
run: |
python -m pip install --upgrade pip
python -m pip install build "setuptools>=67.1.0" "Cython==3.0.12" wheel
- name: Build sdist
run: python -m build --sdist
- name: Upload sdist artifact
uses: actions/upload-artifact@v4
with:
name: dist-sdist
path: dist/*.tar.gz
publish:
name: Publish to ${{ inputs.is_test && 'TestPyPI' || 'PyPI' }}
needs: [validate-version, build-wheels, build-sdist]
runs-on: ubuntu-latest
permissions:
id-token: write # Required for trusted publishing
steps:
- name: Download distribution artifacts
uses: actions/download-artifact@v4
with:
path: dist
merge-multiple: true
- name: Verify distribution files
run: ls -lR dist/
- name: Publish to PyPI
if: inputs.is_test == false
uses: pypa/gh-action-pypi-publish@v1.13.0
with:
password: ${{ secrets.PRIMER3_PYPI_API_TOKEN }}
verify-metadata: true
verbose: true
- name: Publish to TestPyPI
if: inputs.is_test == true
uses: pypa/gh-action-pypi-publish@v1.13.0
with:
password: ${{ secrets.PRIMER3_TEST_PYPI_API_TOKEN }}
repository-url: https://test.pypi.org/legacy/
verify-metadata: true
verbose: true
skip-existing: false
primer3-py-2.3.1/.github/workflows/test.yml 0000664 0000000 0000000 00000003362 15247271707 0020643 0 ustar 00root root 0000000 0000000 # .github/workflows/test.yml
# Primary CI workflow that runs on every push and PR
# - Builds the package
# - Runs all tests
# - Runs pre-commit hooks for code quality
# - Full matrix testing on pull requests and workflow_dispatch
# - Minimal testing (ubuntu-latest + Python 3.13) on push
name: Test
on: [push, pull_request, workflow_dispatch]
jobs:
test:
name: Test Python ${{ matrix.python-version }} on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
# Testing strategy:
# - Push events: Limited testing (ubuntu-latest + Python 3.13 only) for quick feedback
# - Pull requests and manual triggers: Full matrix testing across all platforms and Python versions
matrix:
os: >-
${{
github.event_name == 'push'
&& fromJSON('["ubuntu-latest"]')
|| fromJSON('["ubuntu-latest", "macos-latest", "windows-latest"]')
}}
python-version: >-
${{
github.event_name == 'push'
&& fromJSON('["3.13"]')
|| fromJSON('["3.8", "3.9", "3.10", "3.11", "3.12", "3.13", "3.14"]')
}}
fail-fast: false
defaults:
run:
shell: bash -l {0}
permissions:
id-token: write
contents: read
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
cache: 'pip'
- name: Install package with dev dependencies
run: |
python -m pip install --upgrade pip
python -m pip install -e ".[dev]"
- name: Run tests
run: pytest
- name: Run pre-commit hooks
run: pre-commit run --all-files
primer3-py-2.3.1/.gitignore 0000664 0000000 0000000 00000001320 15247271707 0015524 0 ustar 00root root 0000000 0000000 *.py[cod]
# C extensions
*.so
*.o
*.a
long_seq_tm_test
ntdpal
ntthal
oligotm
primer3_core
amplicon3_core
primer3_masker
# cython artifacts
primer3/thermoanalysis.c
primer3/p3helpers.c
# test artifacts
primer3/src/libprimer3/long_seq_tm_test.dSYM/
primer3/src/libprimer3/oligotm.dSYM/
primer3/src/libprimer3/amplicon3_core.dSYM/
primer3/src/libprimer3/primer3_masker.dSYM/
# Packages
*.egg
*.egg-info
.eggs/
dist
build
eggs
parts
bin
var
sdist
develop-eggs
.installed.cfg
lib
lib64
__pycache__
# Installer logs
pip-log.txt
# Unit test / coverage reports
.coverage
.tox
# Translations
*.mo
# Mr Developer
.mr.developer.cfg
.project
.pydevproject
# MacOS
.DS_Store
.vscode/
# Docs artifacts
_build/
docs/_build/
primer3-py-2.3.1/.pre-commit-config.yaml 0000664 0000000 0000000 00000001377 15247271707 0020031 0 ustar 00root root 0000000 0000000 default_language_version:
python: python3.12
repos:
- repo: https://github.com/asottile/add-trailing-comma
rev: v3.1.0
hooks:
- id: add-trailing-comma
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v5.0.0
hooks:
- id: double-quote-string-fixer
- id: trailing-whitespace
- id: end-of-file-fixer
- repo: https://github.com/pycqa/isort
rev: 6.0.0
hooks:
- id: isort
- repo: https://github.com/pycqa/flake8
rev: 7.1.1
hooks:
- id: flake8
- repo: https://github.com/hhatto/autopep8
rev: v2.3.2
hooks:
- id: autopep8
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.15.0
hooks:
- id: mypy
additional_dependencies: [types-certifi]
primer3-py-2.3.1/AUTHORS 0000664 0000000 0000000 00000002204 15247271707 0014606 0 ustar 00root root 0000000 0000000 ## Authors
The original Primer3 source was developed at Whitehead Institute and Howard
Hughes Medical Institute by Steve Rozen, Andreas Untergasser, Maido Remm,
Triinu Koressaar, Helen Skaletsky and many others (please let us know if
we missed you):
Untergrasser A, Cutcutache I, Koressaar T, Ye J, Faircloth BC, Remm M,
Rozen SG. 2012. Primer3 - new capabilities and interfaces.
Nucleic Acids Research 40(15):e115
Koressaar T, Remm M. 2007. Enhancements and modifications of primer
design program Primer3. Bioinformatics 23(10):1289-91
See https://github.com/primer3-org/primer3 for more information.
### Modifications
The included Primer3 source incorporates modifications and optimizations
intended to streamline performance and facilitate Python integration.
The following individuals are responsible for the implementation and
development of the Python bindings and derivative source code:
### Maintainers
- Ben Pruitt (https://github.com/benpruitt)
- Nick Conway (https://github.com/grinner)
### Contributors
The list of [contributors](https://github.com/libnano/primer3-py/graphs/contributors)
whose help has made this project a success.
primer3-py-2.3.1/CHANGES 0000664 0000000 0000000 00000023112 15247271707 0014532 0 ustar 00root root 0000000 0000000 # Changelog
## Version 2.3.1 (September 6, 2026)
- Fix swapped "enthalpy" / "entropy" references in `ThermoResult` docstrings (see issue #169)
- Correct the oligo analysis example output shown in the README (see issue #171)
- Fix `misprime_lib` / `mishyb_lib` rejecting `bytes` sequence values (see issue #173)
- Memory safety & correctness fixes across the bindings and bundled Primer3 source
(see PR #175): out-of-bounds lookup-table reads in `p3helpers` for non-ASCII input,
UTF-8 length handling in the string sequence helpers, `parse_intron_list` heap
overflow, `oligotm` out-of-bounds read for short sequences, and NULL-pointer
dereferences in `pdh_create_seq_lib` / `_set_globals_and_seq_args`
- `_set_globals_and_seq_args` no longer mutates the caller's `global_args` dict and
now rejects empty `seq_args` (see PR #175)
- Add an "Included Primer3 modifications" documentation page (see PR #175)
- Correct license metadata to `GPL-2.0-or-later` to match the source file headers
(see PR #176)
## Version 2.3.0 (Jan 6, 2026)
- Support for Python 3.14
- Support for objects that implement the __str__ interface (see issue #164)
- Support for modern GCC (see issue #165)
## Version 2.2.0 (May 19, 2025)
- Test improvements (determinism + increased coverage)
- Sanitize `calc_tm` input (see issue #115)
- Modernize build system & release process (see issue #154)
## Version 2.1.0 (February 26, 2025)
- Support for python 3.13
- Silence stderr output during ascii structure generation (issue #146)
- Updated default formamide concentration to match latest primer3web value + oligotm default (issue #140)
## Version 2.0.3 (February 15, 2024)
- Fix `_ThermoAnalysis._set_globals_and_seq_args` for improper checks on `misprime_lib` and
`mishyb_lib` leading to incorrect initialization of `mp_lib` and `mh_lib`. See issue #133
## Version 2.0.2 (February 9, 2024)
- Support for python 3.12 (build, test, docs)
## Version 2.0.1 (September 18, 2023)
- Fixed bug in `todict` method of `ThermoAnalysis`
## Version 2.0.0 (May 30, 2023)
- Migrated primer3 header file Cython extern imports to `thermoanalysis.pxi`
- Optional C structure string argument `c_ascii_structure` added to `_ThermoAnalysis` methods to enable 3rd party use for structures
- Version bump to 2.0.0 due to breaking change
- Fix issue whereby no_structure is not correctly 1 set to 1 when no secondary structure in found
- Add list version of `PRIMER_{PAIR, LEFT, RIGHT, INTERNAL}` to design output dictionary keys. Retaining original keys as well for compatibility.
- Fix for missing `thal_result.sec_struct` and `dpal_results.sec_struct` initialization to `NULL` in `recalc_primer_sec_struct`
## Version 1.2.2 (May 16, 2023)
- Bug fixes for output formatting related to penalty, "problem", and mispriming fields
## Version 1.2.1 (April 28, 2023)
- Bug fixes for `pdh_create_seq_lib` to correct missing `seq_lib` datastructure allocation and variable name typos.
- Increase test coverage to include `misprime_lib` and `mishyb_lib` arguments
## Version 1.2.0 (March 22, 2023)
- Threadsafe changes made to `thal.c` resulting in new `thalflex.c` and `thalflex.h` and `thalflexsignatures.h`.
- Threadsafe changes made to `libprimer3.c` resulting in new `libprimer3flex.c` and `ibprimer3flex.c.h`.
- `libprimer3.seq_args` datatype is now renamed to `libprimer3.seq_args_t`
- `test_threadsafe.py` add and `nogil` instituted for calls to `thal()` and `seqtm()` added `run_design` and `calc_heterodimer` threadsafe tests
- `ThermoAnalysis` class no longer needs to be a `Singleton` so this was removed as a parent class
- `p3helpers.pyx` houses new sequence and design helper functions
- `setup.py` `package_data` and `MANIFEST.in` to assist with future builds from `tar.gz` (`conda`)
## Version 1.1.0 (March 1, 2023)
- Added specificity to error non-N IUPAC error for issue #59
- Wheel build support for python 3.8 to move towards following the CPython EOL model for issue #88. See https://devguide.python.org/versions/
## Version 1.0.0 (February 11, 2023)
- Migrated `primer3` source to 2.6.1 version, which adds new arguments for melting temperature code
- Intergrated all Python C-API related code into `thermoanalysis.pyx`/`pxd`
- Deprecated `camelCase` related functions and added `snake_case` functions / methods in `bindings.py` and `thermoanalysis.pyx`
- Migrated `primer3/wrappers.py` to `tests/wrappers.py` to indicate it should not be used.
- Expanded test coverage and now using pytest for testing
- Added `pre-commit` hooks
- Call signature update and pattern update: `designPrimers` now `design_primers` integrates setting of sequence arguments and global arguments as they are coupled in `primer3_boulder_main.c`.
Note `primer3.primerdesign` was removed, including `setGlobals`.
Replace `setGlobals(GLOBALS, MISPRIME, MISHYB)` and `designPrimers(SEQARGS)` with a single call `design_primers(SEQARGS, GLOBALS, MISPRIME, MISHYB)`.
- `primer3` C code bug fixes to improve compiler warnings
- Using `primer3` `read_boulder_record` to setup primer3 data structures instead of reproducing code in `primer3-py` C or Cython via a code signature update
- `drawDimer` and `drawHairpin` updates to unify sequence structure output for testing
- Integrated GitHub Actions for CI testing
- Updated `sphinx` documentation
- Begin process of making `primer3-py` code thread-safe
- Documentation migrated to `MyST` Markdown
- Autobuild GitHub action for `PyPI` wheels and dist `tar.gz` on version tag
- Autobuild GitHub action `sphinx` documentation updates on version tag
## Version 0.6.1 (May 9, 2020)
- Fixed issue related to absolute paths populated in `SOURCES.txt` of sdist
- Clean up in `setup.py` and better Windows build support
## Version 0.6.0 (May 10, 2019)
- Added functionality for bindings to expose the ASCII representation of
computed dimer and hairpin structures
## Version 0.5.7 (August 10, 2018)
- Changes to upper case sequences in seqtm() in oligotm.c because calls to `ThermoAnalysis.calcTm` returned 0.0 for strings with lower case letters
- disabled existing tests on Windows due to incompatibility with process and
memory calls. TODO: create more tests for `ThermoAnalysis`
## Version 0.5.6 (July 12, 2018)
- Fixes to `primerdesign_helpers.c` C macro errors.
- Added the `todict(`)` methods in `t`hermoanalysis.pyx` for serialization help for
tests there
## Version 0.5.5 (October 30, 2017)
- Remove unicode character from `README.rst`
## Version 0.5.4 (June 20, 2017)
- Migration of Cython extension build process to `build_clib` to remove Cython
as a runtime requirement for `setup.py` (thanks to @tdsmith)
## Version 0.5.3 (May 6, 2017)
- Fixed improper assignment of `"PRIMER_PAIR_MAX_COMPL_END_TH"` during design
arg parsing
## Version 0.5.2 (May 1, 2017)
- Fixed issue where `pa->num_intervals` was not properly set via the bindings
- Fixed typo that caused incorrect output for `PRIMER_PAIR_EXPLAIN`
## Version 0.5.1 (May 25, 2016)
- Update `thal.c` to incorporate traceback fix from Primer3 dev team
(thanks Triinu)
## Version 0.5.0 (February 25, 2016)
- Update `libprimer3` to version 2.3.7
- Better test coverage for low level bindings
## Version 0.4.3 (December 1, 2015)
- Fixed compilation errors, unicode-related build problems
- Fixed memory allocation / deallocation issues with mispriming libraries
## Version 0.4.2 (September 18, 2015)
- Added `misprimingCheck` function to `primer3/thermoanalysis.pyx`
- Corrected unclear syntax in C API code
## Version 0.4.1 (November 28, 2014)
- Better documentation regarding max. seq. lengths for thermo. calcs
- `calcHairpin`, `calcHomodimer`, `calcHeterodimer`, and `calcEndStability` now raise
`RuntimeError`s as appropriate
## Version 0.4.0 (November 25, 2014)
- Several major bug fixes in the design bindings pipeline
- Better testing framework for the design bindings
- New documentation system
- Better under-the-hood thermodynamic analysis abstraction
## Version 0.3.1 (August 13, 2014)
- Improved support for sequences stored in Bytes objects
- Renamed getThermoParams to loadThermoParams for clarity
## Version 0.3.0 (August 12, 2014)
- Fixed memory leak in global param struct allocation for design bindings
- Integrated C API patch code into `libprimer3`
- Refactored `libprimer3` to pure C (`khash` lib is now used in lieu of hashmap)
- Corrected many minor compiler warnings in `libprimer3`
- (POTENTIAL BREAKING CHANGE) Refactored thermodynamic alignment bindings to
always return a thermoresult namedtuple (in the previous embodiment, if no
structure was found, the return value was `None`)
## Version 0.2.5 (August 7, 2014)
- Fixed incorrect tm/salt correction method lookups in `calcTm` function in
both bindings and wrappers
## Version 0.2.4 (June 17, 2014)
- Addressed bug in mispriming/mishybridization library parsing in which
memory for the global parameters struct was not being properly allocated
## Version 0.2.3 (June 5, 2014)
- Corrected several potential sources of memory leaks in the C API design
bindings.
## Version 0.2.2 (June 3, 2014)
- Corrected issue with parsing `"SEQUENCE_PRIMER_PAIR_OK_REGION_LIST"` as a
python sequence object. `"SEQUENCE_PRIMER_PAIR_OK_REGION_LIST"` should now
be provided as a list of lists or tuple of tuples (or a combination of the
two). -1 should be used in the case where an index is ommitted. For example:
```
Primer3 boulder IO input: 100,50,300,50 ; 900,60,,
Primer3 python input: [[100,50,300,50], [900,60,-1,-1]]
```
## Version 0.2.1 (April 24, 2014)
- C API path fix
## Version 0.2 (April 23, 2014)
- Corrected installation issue (replace inplace with `build_lib` in `setup.cfg`)
- Documentation updates
-
## Version 0.1 (March 3, 2014)
- Initial release
primer3-py-2.3.1/LICENSE 0000664 0000000 0000000 00000043152 15247271707 0014552 0 ustar 00root root 0000000 0000000 GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
{description}
Copyright (C) {year} {fullname}
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
{signature of Ty Coon}, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.
primer3-py-2.3.1/MANIFEST.in 0000664 0000000 0000000 00000001523 15247271707 0015277 0 ustar 00root root 0000000 0000000 # Package metadata
include pyproject.toml setup.cfg
include README.md LICENSE CHANGES AUTHORS
include .pre-commit-config.yaml
# Documentation
include docs/Makefile docs/conf.py
include docs/*.md
include docs/api/*.md
recursive-include docs *.rst *.py *.md
# Source files
include primer3/*.pxd primer3/*.pxi primer3/*.pyx primer3/*.h
recursive-include primer3/src/libprimer3 *.h *.c *.txt *.ds *.dh Makefile
include primer3/src/libprimer3/klib/khash.h
include primer3/src/libprimer3/klib/README.md
# Tests and examples
recursive-include tests *.py *_input thal_output
recursive-include examples *.py
# Debug and profiling
include valgrind-python.supp
# Exclude generated files
global-exclude *.pyc *.pyo *.pyd *.so *.dylib *.dll
global-exclude __pycache__/ *.egg-info/
global-exclude .DS_Store
global-exclude .*.swp
prune primer3/thermoanalysis.c
primer3-py-2.3.1/README.md 0000664 0000000 0000000 00000004746 15247271707 0015032 0 ustar 00root root 0000000 0000000 ## primer3-py: simple oligo analysis and primer design

**Primer3-py** is a Python-abstracted API for the popular Primer3 library. The
intention is to provide a simple and reliable interface for automated oligo
analysis and design.
Routine oligo analysis is simple:
```python
>>> import primer3
>>> primer3.calc_tm('GTAAAACGACGGCCAGT')
54.695494691112515
>>> primer3.calc_hairpin('CCCCCATCCGATCAGGGGG')
ThermoResult(structure_found=True, tm=66.75, dg=-3176.92, dh=-36300.00, ds=-106.80)
```
... and `fast` (**~1000X** faster than traditional subprocess wrappers):
```python
In [1]: import primer3
In [2]: import tests.wrapper
In [3]: %timeit primer3.calc_tm('GTAAAACGACGGCCAGT')
100000 loops, best of 3: 4.74 us per loop
In [4]: %timeit test.wrappers.calc_tm('GTAAAACGACGGCCAGT')
100000 loops, best of 3: 5.78 ms per loop
```
**Primer3-py** also includes bindings for the Primer3 `primer design engine`
if you'd prefer to use an established pipeline. The IO parameters mirror those
of the original Primer3.
**Please note that while we provide bindings, we do not provide support for
the Primer3 design engine. Please contact the Primer3 dev team with your
questions: https://github.com/primer3-org/primer3**
A copy of the Primer3 2.6.1 design parameters manual can be found at:
[primer3 v2.6.1 manual](https://htmlpreview.github.io/?https://github.com/primer3-org/primer3/blob/v2.6.1/src/primer3_manual.htm)
## Documentation
- [API Documentation](https://libnano.github.io/primer3-py)
- [Quick Start Guide](https://libnano.github.io/primer3-py/quickstart.html)
- [Development Guide](https://libnano.github.io/primer3-py/development.html)
- [Release Process](https://libnano.github.io/primer3-py/development.html#release-process)
primer3-py-2.3.1/docs/ 0000775 0000000 0000000 00000000000 15247271707 0014470 5 ustar 00root root 0000000 0000000 primer3-py-2.3.1/docs/Makefile 0000664 0000000 0000000 00000015630 15247271707 0016135 0 ustar 00root root 0000000 0000000 # Makefile for Sphinx documentation
#
# You can set these variables from the command line.
SPHINXOPTS =
SPHINXBUILD = sphinx-build
PAPER =
BUILDDIR = _build
# User-friendly check for sphinx-build
ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1)
$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/)
endif
# Internal variables.
PAPEROPT_a4 = -D latex_paper_size=a4
PAPEROPT_letter = -D latex_paper_size=letter
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
# the i18n builder cannot share the environment and doctrees with the others
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest coverage gettext
help:
@echo "Please use \`make ' where is one of"
@echo " html to make standalone HTML files"
@echo " dirhtml to make HTML files named index.html in directories"
@echo " singlehtml to make a single large HTML file"
@echo " pickle to make pickle files"
@echo " json to make JSON files"
@echo " htmlhelp to make HTML files and a HTML help project"
@echo " qthelp to make HTML files and a qthelp project"
@echo " devhelp to make HTML files and a Devhelp project"
@echo " epub to make an epub"
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
@echo " latexpdf to make LaTeX files and run them through pdflatex"
@echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx"
@echo " text to make text files"
@echo " man to make manual pages"
@echo " texinfo to make Texinfo files"
@echo " info to make Texinfo files and run them through makeinfo"
@echo " gettext to make PO message catalogs"
@echo " changes to make an overview of all changed/added/deprecated items"
@echo " xml to make Docutils-native XML files"
@echo " pseudoxml to make pseudoxml-XML files for display purposes"
@echo " linkcheck to check all external links for integrity"
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
@echo " coverage to run coverage check of the documentation (if enabled)"
clean:
rm -rf $(BUILDDIR)/*
html:
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
dirhtml:
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
singlehtml:
$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
@echo
@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
pickle:
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
@echo
@echo "Build finished; now you can process the pickle files."
json:
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
@echo
@echo "Build finished; now you can process the JSON files."
htmlhelp:
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
@echo
@echo "Build finished; now you can run HTML Help Workshop with the" \
".hhp project file in $(BUILDDIR)/htmlhelp."
qthelp:
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
@echo
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/primer3-py.qhcp"
@echo "To view the help file:"
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/primer3-py.qhc"
devhelp:
$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
@echo
@echo "Build finished."
@echo "To view the help file:"
@echo "# mkdir -p $$HOME/.local/share/devhelp/primer3-py"
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/primer3-py"
@echo "# devhelp"
epub:
$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
@echo
@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
latex:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
@echo "Run \`make' in that directory to run these through (pdf)latex" \
"(use \`make latexpdf' here to do that automatically)."
latexpdf:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo "Running LaTeX files through pdflatex..."
$(MAKE) -C $(BUILDDIR)/latex all-pdf
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
latexpdfja:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo "Running LaTeX files through platex and dvipdfmx..."
$(MAKE) -C $(BUILDDIR)/latex all-pdf-ja
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
text:
$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
@echo
@echo "Build finished. The text files are in $(BUILDDIR)/text."
man:
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
@echo
@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
texinfo:
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo
@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
@echo "Run \`make' in that directory to run these through makeinfo" \
"(use \`make info' here to do that automatically)."
info:
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo "Running Texinfo files through makeinfo..."
make -C $(BUILDDIR)/texinfo info
@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
gettext:
$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
@echo
@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
changes:
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
@echo
@echo "The overview file is in $(BUILDDIR)/changes."
linkcheck:
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
@echo
@echo "Link check complete; look for any errors in the above output " \
"or in $(BUILDDIR)/linkcheck/output.txt."
doctest:
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
@echo "Testing of doctests in the sources finished, look at the " \
"results in $(BUILDDIR)/doctest/output.txt."
coverage:
$(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage
@echo "Testing of coverage in the sources finished, look at the " \
"results in $(BUILDDIR)/coverage/python.txt."
xml:
$(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml
@echo
@echo "Build finished. The XML files are in $(BUILDDIR)/xml."
pseudoxml:
$(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml
@echo
@echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml."
primer3-py-2.3.1/docs/api/ 0000775 0000000 0000000 00000000000 15247271707 0015241 5 ustar 00root root 0000000 0000000 primer3-py-2.3.1/docs/api/bindings.md 0000664 0000000 0000000 00000000143 15247271707 0017356 0 ustar 00root root 0000000 0000000 # Primary analysis and design API
```{eval-rst}
.. automodule:: primer3.bindings
:members:
```
primer3-py-2.3.1/docs/api/index.md 0000664 0000000 0000000 00000000320 15247271707 0016665 0 ustar 00root root 0000000 0000000 # API Documentation
This includes a thorough documentation of all pertinent modules, functions,
and classes contained within **primer3-py**.
```{toctree}
:maxdepth: 2
bindings
thermoanalysis
p3helpers
```
primer3-py-2.3.1/docs/api/p3helpers.md 0000664 0000000 0000000 00000000130 15247271707 0017462 0 ustar 00root root 0000000 0000000 ```{eval-rst}
.. automodule:: primer3.p3helpers
:members:
:inherited-members:
```
primer3-py-2.3.1/docs/api/thermoanalysis.md 0000664 0000000 0000000 00000000201 15247271707 0020616 0 ustar 00root root 0000000 0000000 # Low-level thermodynamic analysis
```{eval-rst}
.. automodule:: primer3.thermoanalysis
:members:
:inherited-members:
```
primer3-py-2.3.1/docs/changes_link.md 0000664 0000000 0000000 00000000111 15247271707 0017430 0 ustar 00root root 0000000 0000000 ```{eval-rst}
.. include:: ../CHANGES
:parser: myst_parser.sphinx_
```
primer3-py-2.3.1/docs/conf.py 0000664 0000000 0000000 00000023215 15247271707 0015772 0 ustar 00root root 0000000 0000000 # -*- coding: utf-8 -*-
# type: ignore
# primer3-py documentation build configuration file, created by
# sphinx-quickstart on Tue Nov 25 12:19:07 2014.
#
# This file is execfile()d with the current directory set to its
# containing dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.
# flake8: noqa
import os
import sys
import sphinx_rtd_theme
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
THIS_DIR = os.path.dirname(os.path.abspath(__file__))
PACKAGE_DIR = os.path.dirname(THIS_DIR)
sys.path.insert(0, THIS_DIR)
sys.path.insert(0, PACKAGE_DIR)
import primer3
# -- General configuration ------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
# needs_sphinx = '1.0'
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = [
'sphinx.ext.autodoc',
# 'sphinx.ext.intersphinx',
'sphinx.ext.ifconfig',
'sphinx.ext.viewcode',
'sphinx.ext.napoleon',
'sphinx_rtd_theme',
'myst_parser',
'sphinx.ext.autodoc',
'sphinx_autodoc_typehints',
]
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
# The suffix of source filenames.
source_suffix = {
'.rst': 'restructuredtext',
'.md': 'markdown',
}
# The encoding of source files.
# source_encoding = 'utf-8-sig'
# The master toctree document.
master_doc = 'index'
# General information about the project.
project = 'Primer3-py'
copyright = primer3.__copyright__
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = primer3.__version__
# The full version, including alpha/beta/rc tags.
release = primer3.__version__
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#
# This is also used if you do content translation via gettext catalogs.
# Usually you set "language" from the command line for these cases.
language = 'en'
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
# today = ''
# Else, today_fmt is used as the format for a strftime call.
# today_fmt = '%B %d, %Y'
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
exclude_patterns = ['_build']
# The reST default role (used for this markup: `text`) to use for all
# documents.
# default_role = None
# If true, '()' will be appended to :func: etc. cross-reference text.
# add_function_parentheses = True
# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
# add_module_names = True
# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
# show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
# A list of ignored prefixes for module index sorting.
# modindex_common_prefix = []
# If true, keep warnings as "system message" paragraphs in the built documents.
# keep_warnings = False
# -- Options for HTML output ----------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
html_theme = 'sphinx_rtd_theme'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
# html_theme_options = {}
# Add any paths that contain custom themes here, relative to this directory.
html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
# The name for this set of Sphinx documents. If None, it defaults to
# " v documentation".
# html_title = None
# A shorter title for the navigation bar. Default is the same as html_title.
# html_short_title = None
# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
# html_logo = None
# The name of an image file (within the static path) to use as favicon of the
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
# html_favicon = None
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
# html_static_path = ['_static']
# Add any extra paths that contain custom files (such as robots.txt or
# .htaccess) here, relative to this directory. These files are copied
# directly to the root of the documentation.
# html_extra_path = []
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
# html_last_updated_fmt = '%b %d, %Y'
# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
# html_use_smartypants = True
# Custom sidebar templates, maps document names to template names.
# html_sidebars = {}
# Additional templates that should be rendered to pages, maps page names to
# template names.
# html_additional_pages = {}
# If false, no module index is generated.
# html_domain_indices = True
# If false, no index is generated.
# html_use_index = True
# If true, the index is split into individual pages for each letter.
# html_split_index = False
# If true, links to the reST sources are added to the pages.
# html_show_sourcelink = True
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
# html_show_sphinx = True
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
# html_show_copyright = True
# If true, an OpenSearch description file will be output, and all pages will
# contain a tag referring to it. The value of this option must be the
# base URL from which the finished HTML is served.
# html_use_opensearch = ''
# This is the file name suffix for HTML files (e.g. ".xhtml").
# html_file_suffix = None
# Language to be used for generating the HTML full-text search index.
# Sphinx supports the following languages:
# 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja'
# 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr'
# html_search_language = 'en'
# A dictionary with options for the search language support, empty by default.
# Now only 'ja' uses this config value
# html_search_options = {'type': 'default'}
# The name of a javascript file (relative to the configuration directory) that
# implements a search results scorer. If empty, the default will be used.
# html_search_scorer = 'scorer.js'
# Output file base name for HTML help builder.
htmlhelp_basename = 'primer3-pydoc'
# -- Options for LaTeX output ---------------------------------------------
latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
# 'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
# 'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
# 'preamble': '',
# Latex figure (float) alignment
# 'figure_align': 'htbp',
}
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title,
# author, documentclass [howto, manual, or own class]).
latex_documents = [
(
'index', 'primer3-py.tex', 'primer3-py Documentation',
'Ben Pruitt, Nick Conway', 'manual',
),
]
# The name of an image file (relative to this directory) to place at the top of
# the title page.
# latex_logo = None
# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
# latex_use_parts = False
# If true, show page references after internal links.
# latex_show_pagerefs = False
# If true, show URL addresses after external links.
# latex_show_urls = False
# Documents to append as an appendix to all manuals.
# latex_appendices = []
# If false, no module index is generated.
# latex_domain_indices = True
# -- Options for manual page output ---------------------------------------
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
(
'index', 'primer3-py', 'primer3-py Documentation',
['Ben Pruitt, Nick Conway'], 1,
),
]
# If true, show URL addresses after external links.
# man_show_urls = False
# -- Options for Texinfo output -------------------------------------------
# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
(
'index',
'primer3-py',
'primer3-py Documentation',
'Ben Pruitt, Nick Conway',
'primer3-py',
primer3.DESCRIPTION,
'Miscellaneous',
),
]
# Documents to append as an appendix to all manuals.
# texinfo_appendices = []
# If false, no module index is generated.
# texinfo_domain_indices = True
# How to display URL addresses: 'footnote', 'no', or 'inline'.
# texinfo_show_urls = 'footnote'
# If true, do not generate a @detailmenu in the "Top" node's menu.
# texinfo_no_detailmenu = False
# Example configuration for intersphinx: refer to the Python standard library.
# intersphinx_mapping = {'http://docs.python.org/': None}
myst_heading_anchors = 3
primer3-py-2.3.1/docs/cython_help.md 0000664 0000000 0000000 00000002152 15247271707 0017326 0 ustar 00root root 0000000 0000000 # Building new Cython modules against `thermoanalysis.pxd`
It is of great use to build modules that depend on `primer3-py`.
To do so, first, make sure `primer3-py` installed in your environment.
Write your code like this below:
```python
# this works with a file named thermoanalysis.pxd in the primer3 repo
cimport primer3.thermoanalysis as thermoanalysis
"""
# but below does not
from primer3 cimport thermoanalysis
as You MUST use absolute package paths in cimports i.e.
cimport A.B and not from A cimport B
"""
from primer3 import thermoanalysis
cdef thermoanalysis.ThermoAnalysis a = thermoanalysis.ThermoAnalysis()
print("MAX NN LENGTH", a.max_nn_length)
cdef char* foo = "ACGTACGT"
print("TM:", a.calc_tm_c(foo))
```
and to build/install using a standard `setup.py` add the lines (fill in the ...s)
```python
import primer3
...
my_ext = Extension(
...
include_dirs=primer3.includes()
...)
```
and it should work.
## Notes
- Many `_ThermoAnalysis` methods (e.g. `calc_heterodimer_c`) have C string argument
`c_ascii_structure` to enable 3rd party use for structures reuse
primer3-py-2.3.1/docs/development.md 0000664 0000000 0000000 00000024542 15247271707 0017343 0 ustar 00root root 0000000 0000000 # Development Guide
[](https://github.com/libnano/primer3-py/actions/workflows/test.yml)
[](https://github.com/libnano/primer3-py/actions/workflows/docs.yml)
[](https://github.com/libnano/primer3-py/actions/workflows/release.yml)
Thank you for your interest in contributing to primer3-py! This document provides comprehensive guidelines for development, contribution, and release processes.
## Development Environment Setup
Development requires Python 3.8+ and our development dependencies.
1. Set up your Python environment:
```console
# Install the package in editable mode with development dependencies
$ pip install -e ".[dev]"
```
2. Install pre-commit hooks:
```console
$ pre-commit install
```
## Development Workflow
We use a fork-based development workflow:
1. Fork the repository on GitHub
2. Clone your fork:
```console
$ git clone git@github.com:username/primer3-py.git
$ cd primer3-py
```
3. Add upstream remote:
```console
$ git remote add upstream git@github.com:libnano/primer3-py.git
```
4. Create a feature branch:
```console
# Create a feature, fix, or docs branch
$ git checkout -b feat/my-feature
```
5. Make your changes, following our [coding standards](#coding-standards)
6. Run tests and checks:
```console
# Run the test suite
$ pytest
# Run all pre-commit hooks
$ pre-commit run -a
```
7. Push changes and open a PR
## Branching Strategy
We follow a fork-based development model with version-specific staging branches:
```mermaid
graph TD
A[upstream/master] -->|fork| B[fork/master]
B -->|branch| C[fork/feature branch]
C -->|PR| A
A -->|branch| D[upstream/2.1.0-staging]
D -->|version/docs updates + testing| A
%% Styling
style A fill:#f9f,stroke:#333,stroke-width:2px
style B fill:#bbf,stroke:#333,stroke-width:2px
style C fill:#dfd,stroke:#333,stroke-width:2px
style D fill:#fdd,stroke:#333,stroke-width:2px
```
### Branch Types
1. **Main Branch** (`master`):
- Primary development branch
- All features and fixes merge here first
- Always contains the latest development code
2. **Staging Branches** (e.g., `2.1.0-staging`):
- Created for each version being prepared for release
- Used for version-specific changes and testing
- Named according to the target version (e.g., `2.1.0-staging`)
- Merged back to master after successful release
3. **Feature Branches**:
- Created in personal forks
- Used for developing new features or fixes
- Should have descriptive names (e.g., `feat/pin_cython`, `fix/formamide_conc`)
- Submit PRs from these branches to upstream master
### Workflow Details
1. **Feature Development**:
- Fork the repository
- Create feature branch from master
- Develop and test changes
- Submit PR to upstream master
2. **Release Preparation**:
- Create version-specific staging branch from master
- Make version/documentation updates
- Perform testing and validation
- Merge back to master when ready
3. **Maintenance**:
- Keep your fork's master in sync with upstream
- Rebase feature branches on latest master when needed
- Clean up branches after merging
## Continuous Integration
We use GitHub Actions for CI/CD. Three main workflows are available:
### Test Workflow (`test.yml`)
- Runs on every push and PR
- Builds the package
- Runs all tests
- Runs pre-commit hooks
- Manual trigger available via workflow_dispatch
### Documentation Workflow (`docs.yml`)
- Builds Sphinx documentation
- Publishes to gh-pages on version tags
- Publishes to gh-pages-test on doc branches
- Manual builds available with branch selection
- Requires PRIMER3_TOKEN secret for publishing
### Release Workflow (`release.yml`)
- Builds wheels for all supported Python versions
- Builds source distribution
- Validates versions against __init__.py
- Supports test builds (.devN) and production (.postN)
- Manual trigger with test/production options
## Pull Request Guidelines
1. PR Description:
- Use clear, descriptive titles
- Reference related issues
- Describe all significant changes
- Use markdown for code blocks
2. Code Requirements:
- Add tests for new functionality
- Update documentation as needed
- Follow existing code style
- Keep changes focused and atomic
3. Review Process:
- Address all CI failures
- Respond to reviewer feedback
- Rebase if needed for clean history
- Squash commits if requested
## Coding Standards
1. Python Code:
- Follow PEP 8
- Always use type hints for function parameters and return values
- Document public APIs
- Keep functions focused and testable
- Respect 80 character line length limit
- Review and follow `setup.cfg` linter configuration
- Always run pre-commit hooks before committing:
```console
# Run all pre-commit hooks on all files
$ pre-commit run -a
```
2. Cython Code:
- Follow Python conventions where applicable
- Document complex algorithms
- Optimize only with benchmarks
3. Documentation:
- Use clear, concise language
- Include code examples
- Keep API docs up to date
- Follow Google docstring style
## Version Numbers
Primer3-py follows [PEP 440](https://peps.python.org/pep-0440/) versioning conventions. The version number is maintained in a single source of truth: `primer3/__init__.py`.
### Version Format Types
1. **Release versions** (e.g., `2.1.0`):
- Standard format: `X.Y.Z` (major.minor.patch)
- Used for stable releases
- Stored in source code and git tags
2. **Pre-release versions** (e.g., `2.1.0a1`, `2.1.0b1`, `2.1.0rc1`):
- Used for feature-complete code that needs testing
- Alpha (`a`): Early testing, expect bugs
- Beta (`b`): Feature complete, testing for bugs
- Release Candidate (`rc`): Final testing before release
- Stored in source code and git tags
3. **Development builds** (e.g., `2.1.0.dev1` or `2.1.0a1.dev1`):
- Added automatically by CI/CD for test builds
- NOT stored in source code
- Used for testing package builds on TestPyPI
- Can be combined with pre-releases
4. **Post-releases** (e.g., `2.1.0.post1`):
- Added automatically by CI/CD for production rebuilds
- Used when fixing packaging/build issues only
- NOT stored in source code
- Source remains unchanged from base version
### Version Number Guidelines
- Source code version (in `__init__.py`): Always use base version (`X.Y.Z` or pre-release like `X.Y.Za1`)
- Git tags: Must be prefixed with 'v' and match source code version exactly (e.g., `v2.1.0`)
- Test builds: CI/CD automatically adds `.devN` suffix
- Production rebuilds: CI/CD automatically adds `.postN` suffix if needed
## Release Process
### 1. Preparing a Release
1. Update version in `__init__.py` to target version
2. Update `CHANGES` file:
- Add new version section at the top with release date
- List all significant changes since the last release, ensuring each entry:
- Matches corresponding PR descriptions
- References related issue numbers (e.g., "Fix formamide concentration (issue #140)")
- Groups changes by type (e.g., Features, Bug Fixes, Documentation)
3. Update copyright end dates in source files if needed (e.g., `__init__.py`)
4. For pre-releases, use appropriate suffix:
```python
__version__ = "2.1.0a1" # Alpha release
__version__ = "2.1.0b1" # Beta release
__version__ = "2.1.0rc1" # Release candidate
```
5. Commit changes and push to GitHub
### 2. Testing Releases
1. Go to GitHub Actions → Release workflow
2. Click "Run workflow"
3. Configure:
- Set "Push to TestPyPI" to `true`
- Set "Build number" (increments `.devN` suffix)
4. Review build logs and test on TestPyPI
5. Go to GitHub Actions → Docs workflow
6. Click "Run workflow" and select your branch
7. Review the documentation build for any errors
8. Test the documentation locally if needed
9. Repeat with incremented build numbers if needed
### 3. Production Release
1. Go to GitHub Actions → Release workflow
2. Click "Run workflow"
3. Configure:
- Set "Push to TestPyPI" to `false`
- Set "Build number" to `1` for first attempt
4. If build fails due to packaging (not code):
- Increment build number
- CI/CD will add `.postN` suffix automatically
5. Go to GitHub Actions → Docs workflow
6. Click "Run workflow" and select your branch
7. Verify the documentation builds and deploys successfully
8. After successful release:
- For pre-releases (alpha/beta/rc):
```console
# Tag and push an alpha/beta/rc release
$ git tag v2.1.0a1
$ git push origin v2.1.0a1
```
- For full releases:
- Create a new GitHub release at https://github.com/libnano/primer3-py/releases/new
- Tag version: `v2.1.0` (use actual version number)
- Title: `v2.1.0` (use actual version number)
- Description: Copy the relevant section from CHANGES as the release description
- This will automatically create and push the git tag
### When to Use Each Version Type
1. **Version Number Components** (X.Y.Z):
- **Major (X)**: Breaking API changes including:
- Removal of package functions
- Changes to function parameters
- Changes to function output formats
- Core algorithm changes
- **Minor (Y)**: New features and functionality in a backward-compatible manner
- **Patch (Z)**: Backward-compatible bug fixes and minor improvements
2. **Pre-releases** (`a`/`b`/`rc`):
- Used when you want to publicly test a new version before final release
- Particularly important for major version changes
- Allows community testing while indicating the code is not yet production-ready
3. **Development builds** (`.devN`):
- For testing the complete build and distribution system
- Verifying packaging on TestPyPI
- CI/CD pipeline verification
- Not for production use
4. **Post-releases** (`.postN`):
- Fix packaging issues
- No code changes
- Build environment issues
## Getting Help
- Open an issue for bugs or feature requests
- Join discussions in existing issues
- Contact maintainers for guidance
- Check documentation for common solutions
## License
By contributing, you agree that your contributions will be licensed under the GPL-2.0-or-later License.
primer3-py-2.3.1/docs/included_primer3_modifications.md 0000664 0000000 0000000 00000005717 15247271707 0023164 0 ustar 00root root 0000000 0000000 # Included Primer3 modifications
The C sources under `primer3/src/libprimer3/` are the included copy of the
open-source Primer3 v2.6.1 library, modified to make them amenable to the
Python C API / Cython bindings (see also [](miscellany.md#derivative-work)). In
addition to the pervasive build-glue and API-surface changes, we occasionally
patch this included C to fix bugs that are reachable through the bindings.
This page records those **intentional, behavior-affecting divergences** from
upstream Primer3 so they can be reviewed and re-applied if the included tree is
ever updated to a newer upstream release. It is a living document: add an entry
here whenever you change the included C in a way that alters behavior (pure
mechanical/build changes and comments do not need to be listed).
Each entry notes the file and function, the category of change, what changed
and why, and whether it is reachable from the Python API.
---
## Safety / correctness fixes
### `read_boulder.c` — `parse_intron_list` bounds check
- **Category:** memory-safety fix (out-of-bounds write)
- **Reachable from Python:** yes — `run_design` /
`bindings.design_primers` via the `SEQUENCE_OVERLAP_JUNCTION_LIST` and
`SEQUENCE_INTERNAL_OVERLAP_JUNCTION_LIST` tags.
`parse_intron_list` wrote `list[*count]` and incremented `*count` with no
check against `PR_MAX_INTERVAL_ARRAY` (200). The destination arrays
(`sa->primer_overlap_junctions`, `sa->intl_overlap_junctions`) are fixed
`int[PR_MAX_INTERVAL_ARRAY]` fields of `seq_args`, so a junction list with more
than 200 integers overran the array and corrupted adjacent struct fields. The
sibling interval parsers already bounds-check; this one was the outlier.
The parser now resets `*count` and returns `0` (its existing error signal, on
which the caller appends an `"Error in SEQUENCE_..._JUNCTION_LIST"` message)
when the array is full.
### `oligotm.c` — reject sequences shorter than 2 nt in `oligotm()`
- **Category:** memory-safety + correctness fix (out-of-bounds read / nonsense
result)
- **Reachable from Python:** yes — `calc_tm` / `bindings.calc_tm` via `seqtm`.
`oligotm()` computed `len = strlen(s) - 1` and then applied the
nearest-neighbor terminal penalty at `s[len]`. For an empty string `len`
underflowed to `-1`, so the code read `s[-1]` (out of bounds); a 1-nt sequence
produced a nonsense Tm instead of the `OLIGOTM_ERROR` sentinel that the
function's own `ERROR:` label documents for "length < 2".
`oligotm()` now returns `OLIGOTM_ERROR` up front when `strlen(s) < 2`. Empty
input still returns the same sentinel (now without the OOB read), and 1-nt
input returns the sentinel instead of a meaningless value.
---
## Notes
- Line numbers are intentionally omitted; search for the function name and the
`primer3-py:` comment that marks each patch in the source.
- When updating the included tree from a newer upstream Primer3, check each
entry above against the incoming source and re-apply any patch that upstream
has not itself adopted.
primer3-py-2.3.1/docs/index.md 0000664 0000000 0000000 00000004522 15247271707 0016124 0 ustar 00root root 0000000 0000000 # **Primer3-py** documentation
[](https://github.com/libnano/primer3-py/actions/workflows/test.yml)
[](https://github.com/libnano/primer3-py/actions/workflows/docs.yml)
[](https://github.com/libnano/primer3-py/actions/workflows/release.yml)
[](https://pypi.python.org/pypi/primer3-py)
[](http://www.gnu.org/licenses/gpl-2.0.html)
**Primer3-py** is a Python-abstracted API for the popular Primer3 library. The
intention is to provide a simple and reliable interface for automated oligo
analysis and design.
Routine oligo analysis is extremely simple:
```python
>>> import primer3
>>> primer3.calc_tm('GTAAAACGACGGCCAGT')
54.695494691112515
>>> primer3.calc_hairpin('CCCCCATCCGATCAGGGGG')
ThermoResult(structure_found=True, tm=66.75, dg=-3176.92, dh=-36300.00, ds=-106.80)
```
... and `fast` (**1000X** faster than traditional subprocess wrappers):
```python
In [1]: import primer3
In [2]: import tests.wrapper
In [3]: %timeit primer3.calc_tm('GTAAAACGACGGCCAGT')
100000 loops, best of 3: 4.74 µs per loop
In [4]: %timeit tests.wrappers.calc_tm('GTAAAACGACGGCCAGT')
100000 loops, best of 3: 5.78 ms per loop
```
**Primer3-py** also includes bindings for the Primer3 `primer design engine`
if you'd prefer to use an established pipeline. The IO parameters mirror those
of the original Primer3, but you don't have to deal with messy and slow file
IO for your automated workflows.
**Please note that while we provide bindings, we do not provide support for
the Primer3 design engine. Please contact the Primer3 dev team with your
questions: https://github.com/primer3-org/primer3 **
A copy of the Primer3 2.6.1 design parameters manual can be found at:
[primer3 v2.6.1 manual](https://htmlpreview.github.io/?https://github.com/primer3-org/primer3/blob/v2.6.1/src/primer3_manual.htm)
## Contents
```{toctree}
:maxdepth: 2
quickstart
api/index
development
cython_help
miscellany
included_primer3_modifications
changes_link
```
## Indices and tables
- {ref}`genindex`
- {ref}`modindex`
- {ref}`search`
primer3-py-2.3.1/docs/make.bat 0000664 0000000 0000000 00000016124 15247271707 0016101 0 ustar 00root root 0000000 0000000 @ECHO OFF
REM Command file for Sphinx documentation
if "%SPHINXBUILD%" == "" (
set SPHINXBUILD=sphinx-build
)
set BUILDDIR=_build
set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% .
set I18NSPHINXOPTS=%SPHINXOPTS% .
if NOT "%PAPER%" == "" (
set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS%
)
if "%1" == "" goto help
if "%1" == "help" (
:help
echo.Please use `make ^` where ^ is one of
echo. html to make standalone HTML files
echo. dirhtml to make HTML files named index.html in directories
echo. singlehtml to make a single large HTML file
echo. pickle to make pickle files
echo. json to make JSON files
echo. htmlhelp to make HTML files and a HTML help project
echo. qthelp to make HTML files and a qthelp project
echo. devhelp to make HTML files and a Devhelp project
echo. epub to make an epub
echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
echo. text to make text files
echo. man to make manual pages
echo. texinfo to make Texinfo files
echo. gettext to make PO message catalogs
echo. changes to make an overview over all changed/added/deprecated items
echo. xml to make Docutils-native XML files
echo. pseudoxml to make pseudoxml-XML files for display purposes
echo. linkcheck to check all external links for integrity
echo. doctest to run all doctests embedded in the documentation if enabled
echo. coverage to run coverage check of the documentation if enabled
goto end
)
if "%1" == "clean" (
for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
del /q /s %BUILDDIR%\*
goto end
)
REM Check if sphinx-build is available and fallback to Python version if any
%SPHINXBUILD% 2> nul
if errorlevel 9009 goto sphinx_python
goto sphinx_ok
:sphinx_python
set SPHINXBUILD=python -m sphinx.__init__
%SPHINXBUILD% 2> nul
if errorlevel 9009 (
echo.
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
echo.installed, then set the SPHINXBUILD environment variable to point
echo.to the full path of the 'sphinx-build' executable. Alternatively you
echo.may add the Sphinx directory to PATH.
echo.
echo.If you don't have Sphinx installed, grab it from
echo.http://sphinx-doc.org/
exit /b 1
)
:sphinx_ok
if "%1" == "html" (
%SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/html.
goto end
)
if "%1" == "dirhtml" (
%SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
goto end
)
if "%1" == "singlehtml" (
%SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
goto end
)
if "%1" == "pickle" (
%SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can process the pickle files.
goto end
)
if "%1" == "json" (
%SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can process the JSON files.
goto end
)
if "%1" == "htmlhelp" (
%SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can run HTML Help Workshop with the ^
.hhp project file in %BUILDDIR%/htmlhelp.
goto end
)
if "%1" == "qthelp" (
%SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can run "qcollectiongenerator" with the ^
.qhcp project file in %BUILDDIR%/qthelp, like this:
echo.^> qcollectiongenerator %BUILDDIR%\qthelp\primer3-py.qhcp
echo.To view the help file:
echo.^> assistant -collectionFile %BUILDDIR%\qthelp\primer3-py.ghc
goto end
)
if "%1" == "devhelp" (
%SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished.
goto end
)
if "%1" == "epub" (
%SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The epub file is in %BUILDDIR%/epub.
goto end
)
if "%1" == "latex" (
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
if errorlevel 1 exit /b 1
echo.
echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
goto end
)
if "%1" == "latexpdf" (
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
cd %BUILDDIR%/latex
make all-pdf
cd %~dp0
echo.
echo.Build finished; the PDF files are in %BUILDDIR%/latex.
goto end
)
if "%1" == "latexpdfja" (
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
cd %BUILDDIR%/latex
make all-pdf-ja
cd %~dp0
echo.
echo.Build finished; the PDF files are in %BUILDDIR%/latex.
goto end
)
if "%1" == "text" (
%SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The text files are in %BUILDDIR%/text.
goto end
)
if "%1" == "man" (
%SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The manual pages are in %BUILDDIR%/man.
goto end
)
if "%1" == "texinfo" (
%SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo.
goto end
)
if "%1" == "gettext" (
%SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The message catalogs are in %BUILDDIR%/locale.
goto end
)
if "%1" == "changes" (
%SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
if errorlevel 1 exit /b 1
echo.
echo.The overview file is in %BUILDDIR%/changes.
goto end
)
if "%1" == "linkcheck" (
%SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
if errorlevel 1 exit /b 1
echo.
echo.Link check complete; look for any errors in the above output ^
or in %BUILDDIR%/linkcheck/output.txt.
goto end
)
if "%1" == "doctest" (
%SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
if errorlevel 1 exit /b 1
echo.
echo.Testing of doctests in the sources finished, look at the ^
results in %BUILDDIR%/doctest/output.txt.
goto end
)
if "%1" == "coverage" (
%SPHINXBUILD% -b coverage %ALLSPHINXOPTS% %BUILDDIR%/coverage
if errorlevel 1 exit /b 1
echo.
echo.Testing of coverage in the sources finished, look at the ^
results in %BUILDDIR%/coverage/python.txt.
goto end
)
if "%1" == "xml" (
%SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The XML files are in %BUILDDIR%/xml.
goto end
)
if "%1" == "pseudoxml" (
%SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml.
goto end
)
:end
primer3-py-2.3.1/docs/miscellany.md 0000664 0000000 0000000 00000005662 15247271707 0017163 0 ustar 00root root 0000000 0000000 # Miscellany
## Motivation
Primer3 is a very mature and widely used primer design platform; however,
integrating it into more complex pipelines has historically required obtuse
subprocess wrappers and inefficient file IO. We hope that this Python API will
allow for cleaner and more efficient integration of the Primer3 core
functionalities into your projects and applications.
## Derivative work
The included `libprimer3` source is a derivative of the Primer3 v2.6.1
library that includes a number of optimizations and improvements to make it
more amenable to Python C API / Cython bindings. Every effort has been made
to ensure that the underlying algorithms and calculations deterministically
produce the same results as the vanilla v2.6.1 Primer3 library.
Intentional, behavior-affecting changes to the included C sources are tracked
in [](included_primer3_modifications.md).
## Future work
We are happy with the current state of **Primer3-py** and have no intention of
making any major changes to the API or underlying code base in the near future.
We will provide support for bug fixes and compatibility improvements, and will
consider incorporating any changes included in major releases of the main
Primer3 project.
## Contributions
We welcome any contributions that improve the stability, compatibility or
test coverage (shoutout to pramasoul () for his
help with the testing framework). The best way to interface with the
project and dev team is through [primer3-py Github]()
and review the documentation at [](quickstart.md#Contributing)
## Licensing
Citations should reference the [lastest Primer3 paper](http://nar.oxfordjournals.org/content/early/2012/06/21/nar.gks596):
```
Untergasser, Andreas, et al. "Primer3—new capabilities and interfaces."
Nucleic acids research 40.15 (2012): e115-e115.
doi: 10.1093/nar/gks596
```
All project code, including the derivative Primer3 library, is licensed
under GPL-2.0-or-later. The included Python and Python C API bindings are
Copyright (c) 2014-2026 Ben Pruitt, Nick Conway; 2014-2018 Wyss Institute for
Biologically Inspired Engineering.
See LICENSE for full GPLv2 license text; source file headers grant "or (at
your option) any later version" per the GPL's own terms.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
primer3-py-2.3.1/docs/quickstart.md 0000664 0000000 0000000 00000020556 15247271707 0017214 0 ustar 00root root 0000000 0000000 # Getting Started
**Primer3-py** is designed to be simple to install and use.
## Requirements
**Primer3-py** is built and tested on MacOS, Linux and Windows 64-bit systems; we do not provide official Windows support. Python versions 3.8 - 3.14 builds are supported.
Wheels are released for CPython versions following the [EOL model](https://devguide.python.org/versions/). Pre-built wheels are available for:
- MacOS (x86-64, arm64)
- Linux (x86-64)
- Windows (x86-64)
For other platforms (e.g., Linux aarch64), the package can be built from source but is not officially supported.
## Installation
### Standard Installation
To install the latest stable version:
```console
$ pip install primer3-py
```
### Development Installation
For development or to work with the latest code:
1. Clone the repository:
```console
$ git clone https://github.com/libnano/primer3-py
$ cd primer3-py
```
2. Install in development mode with dev dependencies:
```console
$ pip install -e ".[dev]"
```
### Windows-Specific Setup
If building on Windows, you'll need the TDM-GCC MinGW Compiler:
1. Download and install from [TDM-GCC MinGW](https://jmeubank.github.io/tdm-gcc/)
2. Ensure the compiler is in your system PATH
3. Use the installation commands above
## Thermodynamic analysis
The thermodynamic {py:mod}`primer3.bindings` include support for **Tm, homodimer, heterodimer,
hairpin,** and **3' end stability calculations**:
All of these low-level thermodynamic functions share a set of keyword arguments
used to define the parameters of the respective calculation:
```{eval-rst}
`For all low-level calculations`:
**mv_conc** (float/int)
Monovalent cation concentration (mM)
**dv_conc** (float/int)
Divalent cation concentration (mM)
**dntp_conc** (float/int)
dNTP concentration (mM)
**dna_conc** (float/int)
DNA concentration (nM)
`For homodimer/heterodimer/end stabilty calculation`:
**temp_c** (int)
Simulation temperature for dG calcs (C)
**max_loop** (int)
Maximum size of loops in the structure
`For Tm calculations`:
**dmso_conc** (float)
Concentration of DMSO (%)
**dmso_fact** (float)
DMSO correction factor
**formamide_conc** (float)
Concentration of formamide (mol/l)
**annealing_temp_c** (float)
Actual annealing temperature of the PCR reaction
**max_nn_length** (int)
Maximum length for nearest-neighbor calcs
**tm_method** (str)
Tm calculation method (breslauer or santalucia)
**salt_corrections_method**
Salt correction method (schildkraut, wczarzy, santalucia)
```
For finer grain control of analysis, use {py:mod}`primer3.thermoanalysis`.
NOTE. camelCase methods are deprecated. Please write all new code with
{py:class}`primer3.thermoanalysis.ThermoAnalysis` snake case methods
## Primer design
**Primer3-py** includes bindings for the Primer3 primer design pipeline. The
parameters for the design process are provided as Python dictionaries that
mirror the BoulderIO input files required by the Primer3 binaries. There
are numerous examples of how to use the pipeline in the `tests/` directory.
For documentation regarding the input and output parameters of the pipeline,
please see the [Primer3 2.6.1 documentation](https://htmlpreview.github.io/?https://github.com/primer3-org/primer3/blob/v2.6.1/src/primer3_manual.htm) (the underlying library for
this package is a derivative of v2.6.1).
It is worth noting that some of the inputs deviate from the string format
described in the Primer3 documentation, with notable exceptions being related
to index lists and ranges (i.e., ranges are typically provided as lists/tuples,
and lists of ranges as lists of lists or tuples of tuples). Here we highlight
the differences between the typical `SEQUENCE_PRIMER_PAIR_OK_REGION_LIST`
input and the Python binding input:
```
Primer3 BoulderIO input: 100,50,300,50 ; 900,60,,
Primer3-py Python input: [[100,50,300,50], [900,60,-1,-1]]
```
Similarly, `PRIMER_PRODUCT_SIZE_RANGE` is provided in the following forms:
```
Primer3 BoulderIO input: 75-100 100-125 125-150
Primer3-py Python input: [[75,100],[100,125],[125,150]]
```
### Workflow
The easiest way to run the primer design pipeline is with
{py:func}`primer3.bindings.design_primers`. Notice that Primer3 parameters prefixed with
"SEQUENCE\_" are provided in a separate dictionary from those prefixed with
"PRIMER\_". For more advanced / modular approaches, see the {doc}`api/bindings`
documentation.
Example usage:
```python
bindings.design_primers(
seq_args={
'SEQUENCE_ID': 'MH1000',
'SEQUENCE_TEMPLATE': (
'GCTTGCATGCCTGCAGGTCGACTCTAGAGGATCCCCCTACATTTT'
'AGCATCAGTGAGTACAGCATGCTTACTGGAAGAGAGGGTCATGCA'
'ACAGATTAGGAGGTAAGTTTGCAAAGGCAGGCTAAGGAGGAGACG'
'CACTGAATGCCATGGTAAGAACTCTGGACATAAAAATATTGGAAG'
'TTGTTGAGCAAGTNAAAAAAATGTTTGGAAGTGTTACTTTAGCAA'
'TGGCAAGAATGATAGTATGGAATAGATTGGCAGAATGAAGGCAAA'
'ATGATTAGACATATTGCATTAAGGTAAAAAATGATAACTGAAGAA'
'TTATGTGCCACACTTATTAATAAGAAAGAATATGTGAACCTTGCA'
'GATGTTTCCCTCTAGTAG',
),
'SEQUENCE_INCLUDED_REGION': [36,342]
},
global_args={
'PRIMER_OPT_SIZE': 20,
'PRIMER_PICK_INTERNAL_OLIGO': 1,
'PRIMER_INTERNAL_MAX_SELF_END': 8,
'PRIMER_MIN_SIZE': 18,
'PRIMER_MAX_SIZE': 25,
'PRIMER_OPT_TM': 60.0,
'PRIMER_MIN_TM': 57.0,
'PRIMER_MAX_TM': 63.0,
'PRIMER_MIN_GC': 20.0,
'PRIMER_MAX_GC': 80.0,
'PRIMER_MAX_POLY_X': 100,
'PRIMER_INTERNAL_MAX_POLY_X': 100,
'PRIMER_SALT_MONOVALENT': 50.0,
'PRIMER_DNA_CONC': 50.0,
'PRIMER_MAX_NS_ACCEPTED': 0,
'PRIMER_MAX_SELF_ANY': 12,
'PRIMER_MAX_SELF_END': 8,
'PRIMER_PAIR_MAX_COMPL_ANY': 12,
'PRIMER_PAIR_MAX_COMPL_END': 8,
'PRIMER_PRODUCT_SIZE_RANGE': [
[75,100], [100,125], [125,150],
[150,175], [175,200], [200,225]
],
})
```
## Advanced Installation
Users interested in contributing to development may want to work with the
latest development build. To get the latest and greatest code, head over to
[our Github repo](https://github.com/libnano/primer3-py) and clone the
repo or download a tarball. Building from source is easy:
```console
# For regular installation from source
$ pip install .
# For development installation (recommended)
$ pip install -e .
```
We recommend using the development installation (`-e` flag) if you are testing or
developing `primer3-py` enhancements. This creates an "editable" installation that
links to your source code, allowing you to modify the code without reinstalling.
NOTE: If you're attempting to build on Windows, please review the `primer3`
documentation regarding environment requirements. You'll need to install
the latest version of the TDM-GCC MinGW Compiler if building in a
`MinGW / Mingw-w64` environment: [TDM-GCC MinGW Compiler](https://jmeubank.github.io/tdm-gcc/)
## Testing
Every commit pushed to [the primer3-py GitHub repo](https://github.com/libnano/primer3-py)
is tested via GitHub Actions to ensure it builds properly and passes our unit tests.
If you'd like to run the tests yourself:
```console
# Clone the repository
$ git clone https://github.com/libnano/primer3-py
$ cd primer3-py
# Create and activate a virtual environment
$ python -m venv p3p-test-env
# On Unix/macOS:
$ source p3p-test-env/bin/activate
# On Windows (run this instead of the source command above):
# p3p-test-env\Scripts\activate
# Install development dependencies and the package in editable mode
$ pip install -e ".[dev]"
# Run tests from the package directory
$ pytest
# When finished, deactivate the virtual environment
$ deactivate
```
Using a virtual environment is recommended to ensure a clean, isolated development environment
and avoid conflicts with other Python packages in your system.
## Contributing
Contributions are welcomed via pull requests. Contact the `primer3-py` maintainers prior to beginning your work to make sure it makes sense for the project.
By contributing, you also agree to release your code under GPL-2.0-or-later.
For detailed contribution guidelines, development setup, workflows, and release process, see our [Development Guide](development.md).
primer3-py-2.3.1/examples/ 0000775 0000000 0000000 00000000000 15247271707 0015356 5 ustar 00root root 0000000 0000000 primer3-py-2.3.1/examples/basicprimerdesign.py 0000664 0000000 0000000 00000006345 15247271707 0021432 0 ustar 00root root 0000000 0000000 # Copyright (C) 2023. Ben Pruitt & Nick Conway
# See LICENSE for full GPLv2 license.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
'''
examples.basicprimerdesign
A simple script to demonstrate running primer design
'''
import os.path as op
import random
import sys
from typing import (
Any,
Dict,
)
try:
import primer3
except ModuleNotFoundError:
PACKAGE_DIR = op.dirname(op.dirname(op.abspath(__file__)))
sys.path.append(PACKAGE_DIR)
import primer3
def basic_primer_design() -> Dict[str, Any]:
'''Peform basic primer design given the parameters defined in the function
below
Returns:
Dictionary of the design results
'''
sequence_template = (
'GCTTGCATGCCTGCAGGTCGACTCTAGAGGATCCCCCTACATTTTAGCATCAGTGAGTACAGCAT'
'GCTTACTGGAAGAGAGGGTCATGCAACAGATTAGGAGGTAAGTTTGCAAAGGCAGGCTAAGGAGG'
'AGACGCACTGAATGCCATGGTAAGAACTCTGGACATAAAAATATTGGAAGTTGTTGAGCAAGTNA'
'AAAAAATGTTTGGAAGTGTTACTTTAGCAATGGCAAGAATGATAGTATGGAATAGATTGGCAGAA'
'TGAAGGCAAAATGATTAGACATATTGCATTAAGGTAAAAAATGATAACTGAAGAATTATGTGCCA'
'CACTTATTAATAAGAAAGAATATGTGAACCTTGCAGATGTTTCCCTCTAGTAG'
)
quality_list = [
random.randint(20, 90)
for i in range(len(sequence_template))
]
seq_args = {
'SEQUENCE_ID': 'MH1000',
'SEQUENCE_TEMPLATE': sequence_template,
'SEQUENCE_QUALITY': quality_list,
'SEQUENCE_INCLUDED_REGION': (36, 342),
}
global_args = {
'PRIMER_OPT_SIZE': 20,
'PRIMER_PICK_INTERNAL_OLIGO': 1,
'PRIMER_INTERNAL_MAX_SELF_END': 8,
'PRIMER_MIN_SIZE': 18,
'PRIMER_MAX_SIZE': 25,
'PRIMER_OPT_TM': 60.0,
'PRIMER_MIN_TM': 57.0,
'PRIMER_MAX_TM': 63.0,
'PRIMER_MIN_GC': 20.0,
'PRIMER_MAX_GC': 80.0,
'PRIMER_MAX_POLY_X': 100,
'PRIMER_INTERNAL_MAX_POLY_X': 100,
'PRIMER_SALT_MONOVALENT': 50.0,
'PRIMER_DNA_CONC': 50.0,
'PRIMER_MAX_NS_ACCEPTED': 0,
'PRIMER_MAX_SELF_ANY': 12,
'PRIMER_MAX_SELF_END': 8,
'PRIMER_PAIR_MAX_COMPL_ANY': 12,
'PRIMER_PAIR_MAX_COMPL_END': 8,
'PRIMER_PRODUCT_SIZE_RANGE': [
[75, 100],
[100, 125],
[125, 150],
[150, 175],
[175, 200],
[200, 225],
],
}
design_result_dict = primer3.design_primers(
seq_args=seq_args,
global_args=global_args,
)
return design_result_dict
if __name__ == '__main__':
result_dict = basic_primer_design()
import pprint
print('Generated the following result')
pprint.pprint(result_dict)
primer3-py-2.3.1/examples/orthogonalprimers.py 0000664 0000000 0000000 00000012506 15247271707 0021512 0 ustar 00root root 0000000 0000000 # Copyright (C) 2023. Ben Pruitt & Nick Conway
# See LICENSE for full GPLv2 license.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
'''
examples.orthogonalprimers
A simple script to find a complementary oligo set.
NOTE: More advanced desing might use windowed-hamming distance between reference
genome and do more off target checks or look at energy in addition to
melting temperature
'''
import os.path as op
import random
import sys
from typing import (
Set,
Tuple,
)
try:
from primer3 import thermoanalysis
except ModuleNotFoundError:
PACKAGE_DIR = op.dirname(op.dirname(op.abspath(__file__)))
sys.path.append(PACKAGE_DIR)
from primer3 import thermoanalysis
def rev_complement(seq: str) -> str:
'''Compute the reverse complement of a sequence
Args:
seq: 5' to 3' sequence reverse complement
Returns:
Reverse complement string
'''
lut = {
'A': 'T',
'T': 'A',
'C': 'G',
'G': 'C',
}
return ''.join(lut[x] for x in seq[::-1])
def check_3p_prime_end(seq: str) -> bool:
'''Check the 3 prime end of an oligo for GC content
Args:
seq: sequence to check
Returns:
True if GC content at the 3' end is 3 or less else False
'''
end3p = seq[-5:]
return True if end3p.count('G') + end3p.count('C') < 4 else False
def check_gc_content(seq: str, seq_len: int) -> bool:
'''Check a sequence for total GC content
Args:
seq: sequence to check
seq_len: length sequence string
Returns:
True if GC content is less than 50 else False
'''
gc_total = seq.count('G') + seq.count('C')
return True if (gc_total / seq_len) < 0.51 else False
def search_for_30_mers() -> Tuple[int, Set[str]]:
''' A simple and inexhaustive search for a set 20-mers that do not
heterodimerize among themselves or form hairpins or homodimers.
Returns:
Tuple of the form::
,
'''
# Requirements
oligo_screen_set_size_limit = 1000 # screen search size
desired_total_seqs = 200 # break out of loop after 200 are found
oligo_size = 30 # we are looking for 30 mers
# Temperature limits and cutoffs in Celcius
tm_lim_lo_c = 60
tm_lim_hi_c = 65
tm_hairpin_homodimer_cutoff_c = 40
tm_offtarget_cutoff_c = 40
# Define analysis parameters and instance
thermo_params = {
'mv_conc': 50, # Monovalent cation concentration in mM
'dv_conc': 1.5, # Divalent cation concentration in mM
'dntp_conc': 0.2, # dNTP concentration in mM
'dna_conc': 200, # DNA concentration in nM
}
ta_obj = thermoanalysis.ThermoAnalysis()
ta_obj.set_thermo_args(**thermo_params)
# Count the number of qualifying sequences
found_seqs = 0
candidate_seq_list = []
for _ in range(oligo_screen_set_size_limit):
# Generate a random candidate
candidate_seq = ''.join([
random.choice('ATGC') for _ in
range(oligo_size)
])
if not (
check_gc_content(candidate_seq, 20) and
check_3p_prime_end(candidate_seq)
):
continue
cand_tm_c = ta_obj.calc_tm(candidate_seq)
cand_hrp_tm = ta_obj.calc_hairpin(candidate_seq).tm
cand_homo_tm = ta_obj.calc_hairpin(candidate_seq).tm
if (
(tm_lim_lo_c < cand_tm_c < tm_lim_hi_c) and
(cand_hrp_tm > tm_hairpin_homodimer_cutoff_c) and
(cand_homo_tm > tm_hairpin_homodimer_cutoff_c)
):
candidate_seq_list.append(candidate_seq)
found_seqs += 1
if found_seqs > desired_total_seqs:
break
# Now check heterodimers and create output greedily
good_set: Set[str] = set()
for i, seq1 in enumerate(candidate_seq_list):
seq1_rev = rev_complement(seq1)
# NOTE: nothing is done with the bad set but this could be used in a
# different search pattern
bad_set: Set[str] = set()
for _, seq2 in enumerate(candidate_seq_list[i + 1:]):
tr_obj = ta_obj.calc_heterodimer(seq1, seq2)
if tr_obj.tm > tm_offtarget_cutoff_c:
bad_set.add(seq2)
tr_obj = ta_obj.calc_heterodimer(seq1_rev, seq2)
if tr_obj.tm > tm_offtarget_cutoff_c:
bad_set.add(seq2)
good_set.add(seq1)
return len(candidate_seq_list), good_set
if __name__ == '__main__':
number_of_candidates, result_set = search_for_30_mers()
print(
f'Found {number_of_candidates} candidates, with total primer '
f'set size of {len(result_set)}',
)
print(f'The {result_set=}')
primer3-py-2.3.1/primer3/ 0000775 0000000 0000000 00000000000 15247271707 0015121 5 ustar 00root root 0000000 0000000 primer3-py-2.3.1/primer3/__init__.py 0000664 0000000 0000000 00000005750 15247271707 0017241 0 ustar 00root root 0000000 0000000 # Copyright (C) 2014-2025. Ben Pruitt & Nick Conway; 2014-2018 Wyss Institute
# See LICENSE for full GPLv2 license.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
'''
primer3-py
~~~~~~~~~~
Python bindings / abstractions for the Primer3 primer design /
oligonucleotide thermodynamics library.
'''
import os
from typing import List
# Per PEP-440 https://peps.python.org/pep-0440/#public-version-identifiers
__version__ = '2.3.1'
__author__ = 'Ben Pruitt, Nick Conway'
__copyright__ = (
'Copyright 2014-2026, Ben Pruitt & Nick Conway; 2014-2018 Wyss Institute'
)
__license__ = 'GPL-2.0-or-later'
DESCRIPTION = 'Python bindings for Primer3'
LOCAL_DIR = os.path.dirname(os.path.realpath(__file__))
def includes() -> List[str]:
'''
Returns:
List of directories to include in egg/wheel during packaging
'''
return [LOCAL_DIR, os.path.join(LOCAL_DIR, 'src', 'libprimer3')]
# `try` block here allows __version__, etc to be available prior to
# Cython extension building
try:
from . import ( # type: ignore
argdefaults,
thermoanalysis,
)
from .bindings import ( # Deprecated below
calc_end_stability,
calc_hairpin,
calc_hairpin_tm,
calc_heterodimer,
calc_heterodimer_tm,
calc_homodimer,
calc_homodimer_tm,
calc_tm,
calcEndStability,
calcHairpin,
calcHairpinTm,
calcHeterodimer,
calcHeterodimerTm,
calcHomodimer,
calcHomodimerTm,
calcTm,
design_primers,
designPrimers,
)
# ~~~~~~~~~~~~~~~~ Load thermodynamic parameters into memory ~~~~~~~~~~~~~ #
__all__ = [
# Low-level Tm-only bindings
'calc_hairpin_tm', 'calc_homodimer_tm', 'calc_heterodimer_tm',
# Low-level bindings
'calc_end_stability', 'calc_hairpin', 'calc_homodimer',
'calc_heterodimer', 'calc_tm',
# Primer3 design bindings
'design_primers',
# Modules
'argdefaults', 'thermoanalysis',
# Deprecated Low-level Tm-only bindings
'calcHairpinTm', 'calcHomodimerTm', 'calcHeterodimerTm',
# Deprecated Low-level bindings
'calcEndStability', 'calcHairpin', 'calcHomodimer',
'calcHeterodimer', 'calcTm',
# Deprecated Primer3 design bindings
'designPrimers',
]
except BaseException:
pass
primer3-py-2.3.1/primer3/argdefaults.py 0000664 0000000 0000000 00000024556 15247271707 0020010 0 ustar 00root root 0000000 0000000 # Copyright (C) 2023-2025. Ben Pruitt & Nick Conway
# See LICENSE for full GPLv2 license.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
'''
primer3.argdefaults
~~~~~~~~~~~~~~~~~~~
'''
import dataclasses
import os.path
import re
from typing import (
Any,
Dict,
List,
Tuple,
Union,
)
LOCAL_DIR = os.path.dirname(os.path.realpath(__file__))
LIBPRIMER3_DIR = os.path.join(LOCAL_DIR, 'src', 'libprimer3')
@dataclasses.dataclass()
class Primer3PyArguments:
'''Class containing the defaults values for the system
NOTE: Goal is to match defaults of Primer3web at https://primer3.ut.ee
'''
mv_conc: float = 50.0
dv_conc: float = 1.5
dntp_conc: float = 0.6
dna_conc: float = 50.0
temp_c: float = 37.
max_loop: int = 30
output_structure: bool = False
salt_corrections_method: str = 'santalucia'
salt_corrections_method_int: int = 1
max_nn_length: int = 60
tm_method: str = 'santalucia'
tm_method_int: int = 1
temp_only: int = 0
calc_type_wrapper = 'ANY'
dmso_conc: float = 0.0
dmso_fact: float = 0.6
formamide_conc: float = 0.0
annealing_temp_c: float = -10.0 # per `oligotm_main.c`` and `libprimer.c`
def todict(self) -> dict:
return dataclasses.asdict(self)
TAGS_INTERVAL_LIST = set([
'SEQUENCE_INCLUDED_REGION',
'SEQUENCE_TARGET',
'SEQUENCE_EXCLUDED_REGION',
'SEQUENCE_INTERNAL_EXCLUDED_REGION',
])
TAGS_SIZE_RANGE_LIST = set(['PRIMER_PRODUCT_SIZE_RANGE'])
# (semicolon separated list of integer "quadruples"; default empty)
TAGS_SEMI_QUAD = set(['SEQUENCE_PRIMER_PAIR_OK_REGION_LIST'])
TAGS_PATH_FIX = set([
'PRIMER_THERMODYNAMIC_PARAMETERS_PATH',
'PRIMER_MASK_KMERLIST_PATH',
])
# these tags can show up more than once in a boulder file. We will append
# them to a list
TAGS_APPEND = set(['SEQUENCE_EXCLUDED_REGION'])
Sequence_T = Union[List[Any], Tuple[Any, ...]]
Str_Bytes_T = Union[str, bytes]
def _wrap_path_fix(k: str, v: str) -> str:
'''Update a path value that _might_ be a `LIBPRIMER3_DIR` relative path/
for example it is necessary in the `*_input` files with `primer_config/`
for the `PRIMER_THERMODYNAMIC_PARAMETERS_PATH` key
Args:
k: key
v: path value
Returns:
absolute path
Raises:
ValueError: path not found for key
'''
if not os.path.isdir(v):
if v[0:1] == './':
x = os.path.join(LIBPRIMER3_DIR, v[2:-1])
elif v[0:2] == '../':
x = os.path.join(LIBPRIMER3_DIR, v[3:-1])
else:
x = os.path.join(LIBPRIMER3_DIR, v)
else:
x = v
if not os.path.isdir(x):
raise ValueError(f'{k}: path {x} not found')
return x
def wrap_list_of_quads(v: Sequence_T) -> str:
''' Wrap a list of ordered quads, potentially containing -1's
Produces a string 'list of semicolon separated list of integer "quadruples"'
Used for SEQUENCE_PRIMER_PAIR_OK_REGION_LIST
>>> wrap_list_of_quads([1, 2, 3, 4])
'1,2,3,4'
>>> wrap_list_of_quads([(1, 2, 3, 4)])
'1,2,3,4'
>>> wrap_list_of_quads([[1, 2, 3, 4]])
'1,2,3,4'
>>> wrap_list_of_quads([[1, 2, 3, 4], [5, 6, 7, 8]])
'1,2,3,4 ; 5,6,7,8'
>>> wrap_list_of_quads(((1, 2, 3, 4), [5, 6, 7, 8]))
'1,2,3,4 ; 5,6,7,8'
>>> wrap_list_of_quads(((1, 2, 3, 4), [5, 6, -1, -1]))
'1,2,3,4 ; 5,6,,'
Args:
v: Sequence of items to wrap or Sequence of lists/tuples to wrap
Returns:
Specially string formatted sequence
'''
def int_to_str(i):
return str(i) if i > -1 else ''
try:
rv = ' ; '.join(
','.join(map(int_to_str, quad))
for quad in v
)
except TypeError:
rv = ','.join(str(x) if x > -1 else '' for x in v)
return rv
def _wrap_list_with_format(v: Sequence_T, fmt: str, sep: str = ' ') -> str:
'''
Specially format a list as a string
Args:
v: Sequence of items to format
fmt: format string
sep: Optional separator
Returns:
string formatted list
'''
try:
rv = fmt % tuple(v)
except TypeError:
rv = sep.join(fmt % tuple(x) for x in v)
return rv
def wrap(k: str, v: Any) -> Tuple[str, str]:
'''Convert a primer3 input in python-friendly bindings-style form
to a string form for use by the process wrapper
>>> wrap(('SEQUENCE_TEMPLATE', 'ATCG'))
('SEQUENCE_TEMPLATE', 'ATCG')
>>> wrap(('SEQUENCE_QUALITY', range(5)))
('SEQUENCE_QUALITY', '0 1 2 3 4')
>>> wrap(('SEQUENCE_EXCLUDED_REGION', (5,7)))
('SEQUENCE_EXCLUDED_REGION', '5,7')
>>> wrap(('SEQUENCE_EXCLUDED_REGION', [(5,7), (11,13)]))
('SEQUENCE_EXCLUDED_REGION', '5,7 11,13')
>>> wrap(('PRIMER_PRODUCT_SIZE_RANGE', (7,11)))
('PRIMER_PRODUCT_SIZE_RANGE', '7-11')
Args:
k: Key
v: Value tuple where the value is correctly typed in python
Returns
Key, Value tuple where the value is always a string
'''
if isinstance(v, (list, tuple)):
if len(v) == 0:
rv = ''
else:
if k in TAGS_SEMI_QUAD:
rv = wrap_list_of_quads(v)
elif k in TAGS_INTERVAL_LIST:
rv = _wrap_list_with_format(v, '%d,%d')
elif k in TAGS_SIZE_RANGE_LIST:
rv = _wrap_list_with_format(v, '%d-%d')
elif isinstance(v[0], (list, tuple)):
rv = _wrap_list_with_format(v, '%d-%d')
elif isinstance(v[0], int):
rv = ' '.join(map(str, v))
else:
rv = v # type: ignore
elif k in TAGS_PATH_FIX:
rv = _wrap_path_fix(k, v)
else:
rv = v
return k, rv
def unwrap(k: str, v: str) -> Tuple[str, Any]:
'''convert a wrapper result into the intended form of the
bindings result
>>> unwrap('A_FLOAT', '1.23')
('A_FLOAT', 1.23)
>>> unwrap('AN_INT', '42')
('AN_INT', 42)
>>> unwrap('A_SIZE_RANGE', '2020-2520')
('A_SIZE_RANGE', (2020, 2520))
>>> unwrap('AN_INTERVAL', '7,11')
('AN_INTERVAL', (7, 11)
>>> unwrap('MULTI_SIZE_RANGE', '1-2 3-5 7-11')
('MULTI_SIZE_RANGE', ((1, 2), (3, 5), (7, 11))
>>> unwrap('MULTIPLE_INTS', '2 3 5 7 11 13')
('MULTIPLE_INTS', (2, 3, 5, 7, 11, 13))
>>> unwrap('A_SEQUENCE', 'ATCG')
('A_SEQUENCE', 'ATCG')
Args:
k: key
v: value is always a string
Returns
Key, Value tuple where the value is correctly typed in python
'''
rv = v
def cond_int(s):
return int(s) if s != '' else -1
for lam in [
lambda x: float(x) if '.' in x else int(x),
lambda x: tuple(int(s) for s in x.split(' ')),
lambda x: tuple(int(s) for s in x.split('-')),
lambda x: tuple(int(s) for s in x.split(',')),
lambda x: tuple(
tuple(int(ss) for ss in s.split('-'))
for s in x.split(' ')
),
lambda x: tuple(
tuple(cond_int(ss) for ss in s.split(','))
for s in x.split(' ')
),
lambda x: tuple(
tuple(
cond_int(ss) for ss in
s.strip().split(',')
) for s in x.split(';')
),
]:
try:
rv = lam(v) # type: ignore
except BaseException:
pass
else:
break
return k, rv
# ~~~~~~~ RUDIMENTARY PRIMER3 MAIN WRAPPER (see Primer3 docs for args) ~~~~~~ #
def format_boulder_io(p3_args: Dict[str, Any]) -> bytes:
'''Convert argument dictionary to boulder formatted bytes
Args:
p3_args: primer3 arguments to format boulder style
Returns:
Boulder formatted byte string
'''
out_list = []
for k, v in p3_args.items():
try:
if k in TAGS_APPEND:
for subvalue in v:
_, rv = wrap(k, subvalue)
out_list.append(f'{k}={rv}\n')
else:
_, rv = wrap(k, v)
out_list.append(f'{k}={rv}\n')
except (ValueError, TypeError):
raise ValueError(f'transform error: {k} | {v} | {type(v)}')
out_list.append('=\n')
boulder_str = ''.join(out_list)
return boulder_str.encode('utf8')
def parse_boulder_io(boulder_bytes: bytes) -> Dict[str, str]:
'''Convert boulder info to a key/value dictionary
Args:
boulder_bytes: Bytes of boulder formatted information to parse
Returns:
Dictionary of key/values
'''
data_dict: Dict[str, Any] = {}
for line in boulder_bytes.decode('utf8').split('\n'):
try:
k, v = line.strip().split('=')
if k in TAGS_APPEND:
if k not in data_dict:
data_dict[k] = []
_, rv = unwrap(k, v)
data_dict[k].append(rv)
else:
_, rv = unwrap(k, v)
data_dict[k] = rv
except ValueError:
pass
return data_dict
def parse_multirecord_boulder_io(boulder_str: str) -> List[Dict[str, str]]:
'''
Args:
boulder_str: boulder string to parse with multiple records
Returns:
List of dicts per record
'''
data_dict_list = []
for record in re.split('=\r?\n', boulder_str):
if record == '':
continue
data_dict: Dict[str, Any] = {}
for line in record.split('\n'):
try:
k, v = line.strip().split('=')
if k in TAGS_APPEND:
if k not in data_dict:
data_dict[k] = []
_, rv = unwrap(k, v)
data_dict[k].append(rv)
else:
_, rv = unwrap(k, v)
data_dict[k] = rv
except ValueError:
pass
data_dict_list.append(data_dict)
return data_dict_list
primer3-py-2.3.1/primer3/bindings.py 0000664 0000000 0000000 00000052636 15247271707 0017304 0 ustar 00root root 0000000 0000000 # Copyright (C) 2014-2020. Ben Pruitt & Nick Conway; Wyss Institute
# See LICENSE for full GPLv2 license.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
'''
primer3.bindings
~~~~~~~~~~~~~~~~
This module provides a simple API for the Primer3 primer design / thermodynamic
calculations library.
These are direct bindings to an optimized version of the Primer3 C library,
as opposed to the more commonly used subprocess-based wrappers (we provide a
set of wrappers for comparison / testing purposes as well).
Note that this module effectively abstracts the C API / Cython bindings for
the primer design and thermodynamic analysis functionality of Primer3. This is
done primarly to provide a clean, consistent interface. For applications with
stringent performance requirments, you should consider using the C API
and/or Cython modules directly. See the docs for more details.
'''
import warnings
from typing import (
Any,
Dict,
Optional,
Union,
)
from primer3 import ( # type: ignore
argdefaults,
thermoanalysis,
)
DEFAULT_P3_ARGS = argdefaults.Primer3PyArguments()
THERMO_ANALYSIS = thermoanalysis.ThermoAnalysis()
Str_Bytes_T = Union[str, bytes, object]
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Low level bindings ~~~~~~~~~~~~~~~~~~~~~~~~~~~ #
def calc_hairpin(
seq: Str_Bytes_T,
mv_conc: Union[float, int] = DEFAULT_P3_ARGS.mv_conc,
dv_conc: Union[float, int] = DEFAULT_P3_ARGS.dv_conc,
dntp_conc: Union[float, int] = DEFAULT_P3_ARGS.dntp_conc,
dna_conc: Union[float, int] = DEFAULT_P3_ARGS.dna_conc,
temp_c: Union[float, int] = DEFAULT_P3_ARGS.temp_c,
max_loop: int = DEFAULT_P3_ARGS.max_loop,
output_structure: bool = False,
):
'''Calculate the hairpin formation thermodynamics of a DNA sequence.
**Note that the maximum length of ``seq`` is 60 bp.** This is a cap
suggested by the Primer3 team as the longest reasonable sequence length for
which a two-state NN model produces reliable results
(see ``primer3/src/libnano/thal.h:59``).
Args:
seq: DNA sequence to analyze for hairpin formation
mv_conc: Monovalent cation conc. (mM)
dv_conc: Divalent cation conc. (mM)
dntp_conc: dNTP conc. (mM)
dna_conc: DNA conc. (nM)
temp_c: Simulation temperature for dG (Celsius)
max_loop(int, optional): Maximum size of loops in the structure
output_structure (bool) : If :const:`True`, the ASCII dimer structure is
saved
Returns:
A :class:`ThermoResult` object with thermodynamic characteristics of the
hairpin formation.
Raises:
:class:`RuntimeError`
'''
THERMO_ANALYSIS.set_thermo_args(**locals())
return THERMO_ANALYSIS.calc_hairpin(seq, output_structure).check_exc()
def calcHairpin(
seq: Str_Bytes_T,
mv_conc: Union[float, int] = DEFAULT_P3_ARGS.mv_conc,
dv_conc: Union[float, int] = DEFAULT_P3_ARGS.dv_conc,
dntp_conc: Union[float, int] = DEFAULT_P3_ARGS.dntp_conc,
dna_conc: Union[float, int] = DEFAULT_P3_ARGS.dna_conc,
temp_c: Union[float, int] = DEFAULT_P3_ARGS.temp_c,
max_loop: int = DEFAULT_P3_ARGS.max_loop,
output_structure: bool = False,
):
'''.. deprecated:: 1.0.0. Choose :func:`calc_hairpin` function instead
Calculate the hairpin formation thermodynamics of a DNA sequence.
**Note that the maximum length of `seq` is 60 bp.** This is a cap suggested
by the Primer3 team as the longest reasonable sequence length for which
a two-state NN model produces reliable results
(see ``primer3/src/libnano/thal.h:59``).
Args:
seq: DNA sequence to analyze for hairpin formation
mv_conc: Monovalent cation conc. (mM)
dv_conc: Divalent cation conc. (mM)
dntp_conc: dNTP conc. (mM)
dna_conc: DNA conc. (nM)
temp_c: Simulation temperature for dG (Celsius)
max_loop(int, optional): Maximum size of loops in the structure
output_structure (bool) : If :const:`True`, the ASCII dimer structure
is saved
Returns:
A :class:`ThermoResult` object with thermodynamic characteristics of the
hairpin formation.
Raises:
:class:`RuntimeError`
'''
THERMO_ANALYSIS.set_thermo_args(**locals())
return THERMO_ANALYSIS.calcHairpin(seq, output_structure).check_exc()
def calc_homodimer(
seq: Str_Bytes_T,
mv_conc: Union[float, int] = DEFAULT_P3_ARGS.mv_conc,
dv_conc: Union[float, int] = DEFAULT_P3_ARGS.dv_conc,
dntp_conc: Union[float, int] = DEFAULT_P3_ARGS.dntp_conc,
dna_conc: Union[float, int] = DEFAULT_P3_ARGS.dna_conc,
temp_c: Union[float, int] = DEFAULT_P3_ARGS.temp_c,
max_loop: int = DEFAULT_P3_ARGS.max_loop,
output_structure: bool = False,
):
'''Calculate the homodimerization thermodynamics of a DNA sequence.
**Note that the maximum length of ``seq`` is 60 bp.** This is a cap imposed
by Primer3 as the longest reasonable sequence length for which
a two-state NN model produces reliable results (see
``primer3/src/libnano/thal.h:59``).
Args:
seq: DNA sequence to analyze for homodimer formation calculations
mv_conc: Monovalent cation conc. (mM)
dv_conc: Divalent cation conc. (mM)
dntp_conc: dNTP conc. (mM)
dna_conc: DNA conc. (nM)
temp_c: Simulation temperature for dG (Celsius)
max_loop: Maximum size of loops in the structure
output_structure: If :const:`True`, the ASCII dimer structure
is saved
Returns:
A :class:`ThermoResult` object with thermodynamic characteristics of the
homodimer interaction.
Raises:
:class:`RuntimeError`
'''
THERMO_ANALYSIS.set_thermo_args(**locals())
return THERMO_ANALYSIS.calc_homodimer(seq, output_structure).check_exc()
def calcHomodimer(
seq: Str_Bytes_T,
mv_conc: Union[float, int] = DEFAULT_P3_ARGS.mv_conc,
dv_conc: Union[float, int] = DEFAULT_P3_ARGS.dv_conc,
dntp_conc: Union[float, int] = DEFAULT_P3_ARGS.dntp_conc,
dna_conc: Union[float, int] = DEFAULT_P3_ARGS.dna_conc,
temp_c: Union[float, int] = DEFAULT_P3_ARGS.temp_c,
max_loop: int = DEFAULT_P3_ARGS.max_loop,
output_structure: bool = False,
):
'''.. deprecated:: 1.0.0. Choose :func:`calc_homodimer` function instead
Calculate the homodimerization thermodynamics of a DNA sequence.
**Note that the maximum length of ``seq`` is 60 bp.** This is a cap imposed
by Primer3 as the longest reasonable sequence length for which
a two-state NN model produces reliable results (see
``primer3/src/libnano/thal.h:59``).
Args:
seq: DNA sequence to analyze for homodimer formation calculations
mv_conc: Monovalent cation conc. (mM)
dv_conc: Divalent cation conc. (mM)
dntp_conc: dNTP conc. (mM)
dna_conc: DNA conc. (nM)
temp_c: Simulation temperature for dG (Celsius)
max_loop: Maximum size of loops in the structure
output_structure: If :const:`True`, the ASCII dimer structure
is saved
Returns:
A :class:`ThermoResult` object with thermodynamic characteristics of the
homodimer interaction.
Raises:
:class:`RuntimeError`
'''
THERMO_ANALYSIS.set_thermo_args(**locals())
return THERMO_ANALYSIS.calcHomodimer(seq, output_structure).check_exc()
def calc_heterodimer(
seq1: Str_Bytes_T,
seq2: Str_Bytes_T,
mv_conc: Union[float, int] = DEFAULT_P3_ARGS.mv_conc,
dv_conc: Union[float, int] = DEFAULT_P3_ARGS.dv_conc,
dntp_conc: Union[float, int] = DEFAULT_P3_ARGS.dntp_conc,
dna_conc: Union[float, int] = DEFAULT_P3_ARGS.dna_conc,
temp_c: Union[float, int] = DEFAULT_P3_ARGS.temp_c,
max_loop: int = DEFAULT_P3_ARGS.max_loop,
output_structure: bool = False,
) -> thermoanalysis.ThermoResult:
''' Calculate the heterodimerization thermodynamics of two DNA sequences.
**Note that at least one of the two sequences must by <60 bp in length.**
This is a cap imposed by Primer3 as the longest reasonable sequence length
for which a two-state NN model produces reliable results (see
``primer3/src/libnano/thal.h:59``).
Args:
seq1: First DNA sequence to analyze for heterodimer formation
seq2: Second DNA sequence to analyze for heterodimer formation
mv_conc: Monovalent cation conc. (mM)
dv_conc: Divalent cation conc. (mM)
dntp_conc: dNTP conc. (mM)
dna_conc: DNA conc. (nM)
temp_c: Simulation temperature for dG (Celsius)
max_loop: Maximum size of loops in the structure
output_structure: If `True`, the ASCII dimer structure is saved
Returns:
A :class:`ThermoResult` object with thermodynamic characteristics of the
heterodimer interaction.
Raises:
:class:`RuntimeError`
'''
THERMO_ANALYSIS.set_thermo_args(**locals())
return THERMO_ANALYSIS.calc_heterodimer(
seq1,
seq2,
output_structure,
).check_exc()
def calcHeterodimer(
seq1: Str_Bytes_T,
seq2: Str_Bytes_T,
mv_conc: Union[float, int] = DEFAULT_P3_ARGS.mv_conc,
dv_conc: Union[float, int] = DEFAULT_P3_ARGS.dv_conc,
dntp_conc: Union[float, int] = DEFAULT_P3_ARGS.dntp_conc,
dna_conc: Union[float, int] = DEFAULT_P3_ARGS.dna_conc,
temp_c: Union[float, int] = DEFAULT_P3_ARGS.temp_c,
max_loop: int = DEFAULT_P3_ARGS.max_loop,
output_structure: bool = False,
) -> thermoanalysis.ThermoResult:
'''.. deprecated:: 1.0.0. Choose :func:`calc_heterodimer` function instead
Calculate the heterodimerization thermodynamics of two DNA sequences.
**Note that at least one of the two sequences must by <60 bp in length.**
This is a cap imposed by Primer3 as the longest reasonable sequence length
for which a two-state NN model produces reliable results (see
``primer3/src/libnano/thal.h:59``).
Args:
seq1: First DNA sequence to analyze for heterodimer formation
seq2: Second DNA sequence to analyze for heterodimer formation
mv_conc: Monovalent cation conc. (mM)
dv_conc: Divalent cation conc. (mM)
dntp_conc: dNTP conc. (mM)
dna_conc: DNA conc. (nM)
temp_c: Simulation temperature for dG (Celsius)
max_loop: Maximum size of loops in the structure
output_structure: If `True`, the ASCII dimer structure is saved
Returns:
A :class:`ThermoResult` object with thermodynamic characteristics of the
heterodimer interaction.
Raises:
:class:`RuntimeError`
'''
THERMO_ANALYSIS.set_thermo_args(**locals())
return THERMO_ANALYSIS.calcHeterodimer(
seq1,
seq2,
output_structure,
).check_exc()
def calc_end_stability(
seq1: Str_Bytes_T,
seq2: Str_Bytes_T,
mv_conc: Union[float, int] = DEFAULT_P3_ARGS.mv_conc,
dv_conc: Union[float, int] = DEFAULT_P3_ARGS.dv_conc,
dntp_conc: Union[float, int] = DEFAULT_P3_ARGS.dntp_conc,
dna_conc: Union[float, int] = DEFAULT_P3_ARGS.dna_conc,
temp_c: Union[float, int] = DEFAULT_P3_ARGS.temp_c,
max_loop: int = DEFAULT_P3_ARGS.max_loop,
) -> thermoanalysis.ThermoResult:
'''Calculate the 3' end stability of DNA sequence `seq1` against DNA
sequence `seq2`.
**Note that at least one of the two sequences must by <60 bp in length.**
This is a cap imposed by Primer3 as the longest reasonable sequence length
for which a two-state NN model produces reliable results (see
``primer3/src/libnano/thal.h:59``).
Args:
seq1: DNA sequence to analyze for 3' end hybridization against the
target sequence
seq2: Target DNA sequence to analyze for seq1 3' end hybridization
mv_conc: Monovalent cation conc. (mM)
dv_conc: Divalent cation conc. (mM)
dntp_conc: dNTP conc. (mM)
dna_conc: DNA conc. (nM)
temp_c: Simulation temperature for dG (Celsius)
max_loop: Maximum size of loops in the structure
Returns:
A :class:`ThermoResult` object with thermodynamic characteristics of the
3' hybridization interaction.
Raises:
:class:`RuntimeError`
'''
THERMO_ANALYSIS.set_thermo_args(**locals())
return THERMO_ANALYSIS.calc_end_stability(seq1, seq2).check_exc()
def calcEndStability(
seq1: Str_Bytes_T,
seq2: Str_Bytes_T,
mv_conc: Union[float, int] = DEFAULT_P3_ARGS.mv_conc,
dv_conc: Union[float, int] = DEFAULT_P3_ARGS.dv_conc,
dntp_conc: Union[float, int] = DEFAULT_P3_ARGS.dntp_conc,
dna_conc: Union[float, int] = DEFAULT_P3_ARGS.dna_conc,
temp_c: Union[float, int] = DEFAULT_P3_ARGS.temp_c,
max_loop: int = DEFAULT_P3_ARGS.max_loop,
) -> thermoanalysis.ThermoResult:
'''**Deprecated**. Choose :func:`calc_end_stability` function instead
Calculate the 3' end stability of DNA sequence `seq1` against DNA
sequence `seq2`.
**Note that at least one of the two sequences must by <60 bp in length.**
This is a cap imposed by Primer3 as the longest reasonable sequence length
for which a two-state NN model produces reliable results (see
``primer3/src/libnano/thal.h:59``).
Args:
seq1: DNA sequence to analyze for 3' end hybridization against the
target sequence
seq2: Target DNA sequence to analyze for seq1 3' end hybridization
mv_conc: Monovalent cation conc. (mM)
dv_conc: Divalent cation conc. (mM)
dntp_conc: dNTP conc. (mM)
dna_conc: DNA conc. (nM)
temp_c: Simulation temperature for dG (Celsius)
max_loop: Maximum size of loops in the structure
Returns:
A :class:`ThermoResult` object with thermodynamic characteristics of the
3' hybridization interaction.
Raises:
:class:`RuntimeError`
'''
THERMO_ANALYSIS.set_thermo_args(**locals())
return THERMO_ANALYSIS.calcEndStability(seq1, seq2).check_exc()
def calc_tm(
seq: Str_Bytes_T,
mv_conc: Union[float, int] = DEFAULT_P3_ARGS.mv_conc,
dv_conc: Union[float, int] = DEFAULT_P3_ARGS.dv_conc,
dntp_conc: Union[float, int] = DEFAULT_P3_ARGS.dntp_conc,
dna_conc: Union[float, int] = DEFAULT_P3_ARGS.dna_conc,
dmso_conc: float = DEFAULT_P3_ARGS.dmso_conc,
dmso_fact: float = DEFAULT_P3_ARGS.dmso_fact,
formamide_conc: float = DEFAULT_P3_ARGS.formamide_conc,
annealing_temp_c: float = DEFAULT_P3_ARGS.annealing_temp_c,
max_nn_length: int = DEFAULT_P3_ARGS.max_nn_length,
tm_method: str = DEFAULT_P3_ARGS.tm_method,
salt_corrections_method: str = DEFAULT_P3_ARGS.salt_corrections_method,
) -> float:
'''Calculate the melting temperature (Tm) of a DNA sequence.
Note that NN thermodynamics will be used to calculate the Tm of sequences
up to 60 bp in length, after which point the following formula will be
used::
Tm = 81.5 + 16.6(log10([mv_conc])) + 0.41(%GC) - 600/length
Args:
seq: DNA sequence
mv_conc: Monovalent cation conc. (mM)
dv_conc: Divalent cation conc. (mM)
dntp_conc: dNTP conc. (mM)
dna_conc: DNA conc. (nM)
dmso_conc: Concentration of DMSO (%)
dmso_fact: DMSO correction factor, default 0.6
formamide_conc: Concentration of formamide (mol/l)
annealing_temp_c: Actual annealing temperature of the PCR reaction
in (C)
temp_c: Simulation temperature for dG (Celsius)
max_nn_length: Maximum length for nearest-neighbor calcs
tm_method: Tm calculation method (breslauer or santalucia)
salt_corrections_method: Salt correction method (schildkraut, owczarzy,
santalucia)
Returns:
The melting temperature in degrees Celsius (float).
'''
THERMO_ANALYSIS.set_thermo_args(**locals())
return THERMO_ANALYSIS.calc_tm(seq)
def calcTm(
seq: Str_Bytes_T,
mv_conc: Union[float, int] = DEFAULT_P3_ARGS.mv_conc,
dv_conc: Union[float, int] = DEFAULT_P3_ARGS.dv_conc,
dntp_conc: Union[float, int] = DEFAULT_P3_ARGS.dntp_conc,
dna_conc: Union[float, int] = DEFAULT_P3_ARGS.dna_conc,
dmso_conc: float = DEFAULT_P3_ARGS.dmso_conc,
dmso_fact: float = DEFAULT_P3_ARGS.dmso_fact,
formamide_conc: float = DEFAULT_P3_ARGS.formamide_conc,
annealing_temp_c: float = DEFAULT_P3_ARGS.annealing_temp_c,
max_nn_length: int = DEFAULT_P3_ARGS.max_nn_length,
tm_method: str = DEFAULT_P3_ARGS.tm_method,
salt_corrections_method: str = DEFAULT_P3_ARGS.salt_corrections_method,
) -> float:
'''.. deprecated:: 1.0.0. Choose :func:`calc_tm` function instead
Calculate the melting temperature (Tm) of a DNA sequence.
Note that NN thermodynamics will be used to calculate the Tm of sequences
up to 60 bp in length, after which point the following formula will be
used::
Tm = 81.5 + 16.6(log10([mv_conc])) + 0.41(%GC) - 600/length
Args:
seq: DNA sequence
mv_conc: Monovalent cation conc. (mM)
dv_conc: Divalent cation conc. (mM)
dntp_conc: dNTP conc. (mM)
dna_conc: DNA conc. (nM)
dmso_conc: Concentration of DMSO (%)
dmso_fact: DMSO correction factor, default 0.6
formamide_conc: Concentration of formamide (mol/l)
annealing_temp_c: Actual annealing temperature of the PCR reaction
in (C)
temp_c: Simulation temperature for dG (Celsius)
max_nn_length: Maximum length for nearest-neighbor calcs
tm_method: Tm calculation method (breslauer or santalucia)
salt_corrections_method: Salt correction method (schildkraut, owczarzy,
santalucia)
Returns:
The melting temperature in degrees Celsius (float).
'''
THERMO_ANALYSIS.set_thermo_args(**locals())
return THERMO_ANALYSIS.calcTm(seq)
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Tm-only aliases ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #
def calc_hairpin_tm(*args, **kwargs) -> float:
return calc_hairpin(*args, **kwargs).tm
def calcHairpinTm(*args, **kwargs) -> float:
'''.. deprecated:: 1.0.0. Choose :func:`calc_hairpin_tm` function instead
'''
return calcHairpin(*args, **kwargs).tm
def calc_homodimer_tm(*args, **kwargs) -> float:
return calc_homodimer(*args, **kwargs).tm
def calcHomodimerTm(*args, **kwargs) -> float:
'''.. deprecated:: 1.0.0. Choose :func:`calc_homodimer_tm` function instead
'''
return calcHomodimer(*args, **kwargs).tm
def calc_heterodimer_tm(*args, **kwargs) -> float:
return calc_heterodimer(*args, **kwargs).tm
def calcHeterodimerTm(*args, **kwargs) -> float:
'''.. deprecated:: 1.0.0. Choose :func:`calc_heterodimer_tm` function
instead
'''
return calcHeterodimer(*args, **kwargs).tm
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Design bindings ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #
def design_primers(
seq_args: Dict[str, Any],
global_args: Dict[str, Any],
misprime_lib: Optional[Dict[str, Any]] = None,
mishyb_lib: Optional[Dict[str, Any]] = None,
) -> Dict[str, Any]:
'''Run the Primer3 design process.
This is a wrapper around :meth:`_ThermoAnalysis.run_design`.
Args:
seq_args: Primer3 sequence/design args as per Primer3 docs
global_args: Primer3 global args as per Primer3 docs
misprime_lib: `Sequence name: sequence` dictionary for mispriming
checks.
mishyb_lib: `Sequence name: sequence` dictionary for mishybridization
checks.
Returns:
A dictionary of Primer3 results (should be identical to the expected
BoulderIO output from ``primer3_main``)
'''
return THERMO_ANALYSIS.run_design(
global_args=global_args,
seq_args=seq_args,
misprime_lib=misprime_lib,
mishyb_lib=mishyb_lib,
)
def designPrimers(
seq_args: Dict[str, Any],
global_args: Dict[str, Any],
misprime_lib: Optional[Dict[str, Any]] = None,
mishyb_lib: Optional[Dict[str, Any]] = None,
) -> Dict[str, Any]:
'''.. deprecated:: 1.0.0 Choose :func:`design_primers` function instead
Run the Primer3 design process.
Args:
seq_args: Primer3 sequence/design args as per Primer3 docs
global_args: Primer3 global args as per Primer3 docs
misprime_lib: `Sequence name: sequence` dictionary for mispriming
checks.
mishyb_lib: `Sequence name: sequence` dictionary for mishybridization
checks.
Returns:
A dictionary of Primer3 results (should be identical to the expected
BoulderIO output from ``primer3_main``)
'''
warnings.warn('Function deprecated please use "design_primers" instead')
return THERMO_ANALYSIS.run_design(
global_args=global_args,
seq_args=seq_args,
misprime_lib=misprime_lib,
mishyb_lib=mishyb_lib,
)
primer3-py-2.3.1/primer3/p3helpers.h 0000664 0000000 0000000 00000016201 15247271707 0017177 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2023-2026. Ben Pruitt & Nick Conway;
* See LICENSE for full GPLv2 license.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* primer3.p3helpers.h
* Helper functions C definitions for p3helpers.pyx
*/
#ifndef __P3PY_P3HELPERS_H
#define __P3PY_P3HELPERS_H
/*
* NOTE: These tables are indexed by the raw (unsigned char) byte value, which
* spans 0-255. They MUST therefore have 256 entries -- a 128-entry table is
* read out of bounds for any byte >= 0x80 (e.g. an arbitrary `bytes` argument,
* or a non-ASCII `str` after UTF-8 encoding). Entries 128-255 map to the
* invalid-base sentinel ('?' / 0) so such bytes are rejected, not read OOB.
*/
const char COMP_BASE_LUT[256] = {
'?', '?', '?', '?', '?', '?', '?', '?', // 7
'?', '?', '?', '?', '?', '?', '?', '?', // 15
'?', '?', '?', '?', '?', '?', '?', '?', // 23
'?', '?', '?', '?', '?', '?', '?', '?', // 31
'?', '?', '?', '?', '?', '?', '?', '?', // 39
'?', '?', '?', '?', '?', '?', '?', '?', // 47
'?', '?', '?', '?', '?', '?', '?', '?', // 55
'?', '?', '?', '?', '?', '?', '?', '?', // 63
'?', 'T', 'V', 'G', 'H', '?', '?', 'C', // 71
'D', '?', '?', 'M', '?', 'K', 'N', '?', // 79
'?', '?', 'Y', 'S', 'A', '?', 'B', 'W', // 87
'?', 'R', '?', '?', '?', '?', '?', '?', // 95
'?', 't', 'v', 'g', 'h', '?', '?', 'c', // 103
'd', '?', '?', 'm', '?', 'k', 'n', '?', // 111
'?', '?', 'y', 's', 'a', '?', 'b', 'w', // 119
'?', 'r', '?', '?', '?', '?', '?', '?', // 127
'?', '?', '?', '?', '?', '?', '?', '?', // 135
'?', '?', '?', '?', '?', '?', '?', '?', // 143
'?', '?', '?', '?', '?', '?', '?', '?', // 151
'?', '?', '?', '?', '?', '?', '?', '?', // 159
'?', '?', '?', '?', '?', '?', '?', '?', // 167
'?', '?', '?', '?', '?', '?', '?', '?', // 175
'?', '?', '?', '?', '?', '?', '?', '?', // 183
'?', '?', '?', '?', '?', '?', '?', '?', // 191
'?', '?', '?', '?', '?', '?', '?', '?', // 199
'?', '?', '?', '?', '?', '?', '?', '?', // 207
'?', '?', '?', '?', '?', '?', '?', '?', // 215
'?', '?', '?', '?', '?', '?', '?', '?', // 223
'?', '?', '?', '?', '?', '?', '?', '?', // 231
'?', '?', '?', '?', '?', '?', '?', '?', // 239
'?', '?', '?', '?', '?', '?', '?', '?', // 247
'?', '?', '?', '?', '?', '?', '?', '?' // 255
};
const char SANITIZE_LUT[256] = {
'?', '?', '?', '?', '?', '?', '?', '?', // 7
'?', '?', '?', '?', '?', '?', '?', '?', // 15
'?', '?', '?', '?', '?', '?', '?', '?', // 23
'?', '?', '?', '?', '?', '?', '?', '?', // 31
'?', '?', '?', '?', '?', '?', '?', '?', // 39
'?', '?', '?', '?', '?', '?', '?', '?', // 47
'?', '?', '?', '?', '?', '?', '?', '?', // 55
'?', '?', '?', '?', '?', '?', '?', '?', // 63
'?', 'A', 'N', 'C', 'N', '?', '?', 'G', // 71
'N', '?', '?', 'N', '?', 'N', 'N', '?', // 79
'?', '?', 'N', 'N', 'T', 'N', 'N', 'N', // 87
'?', 'N', '?', '?', '?', '?', '?', '?', // 95
'?', 'a', 'n', 'c', 'n', '?', '?', 'g', // 103
'n', '?', '?', 'n', '?', 'n', 'n', '?', // 111
'?', '?', 'n', 'n', 't', 'n', 'n', 'n', // 119
'?', 'n', '?', '?', '?', '?', '?', '?', // 127
'?', '?', '?', '?', '?', '?', '?', '?', // 135
'?', '?', '?', '?', '?', '?', '?', '?', // 143
'?', '?', '?', '?', '?', '?', '?', '?', // 151
'?', '?', '?', '?', '?', '?', '?', '?', // 159
'?', '?', '?', '?', '?', '?', '?', '?', // 167
'?', '?', '?', '?', '?', '?', '?', '?', // 175
'?', '?', '?', '?', '?', '?', '?', '?', // 183
'?', '?', '?', '?', '?', '?', '?', '?', // 191
'?', '?', '?', '?', '?', '?', '?', '?', // 199
'?', '?', '?', '?', '?', '?', '?', '?', // 207
'?', '?', '?', '?', '?', '?', '?', '?', // 215
'?', '?', '?', '?', '?', '?', '?', '?', // 223
'?', '?', '?', '?', '?', '?', '?', '?', // 231
'?', '?', '?', '?', '?', '?', '?', '?', // 239
'?', '?', '?', '?', '?', '?', '?', '?', // 247
'?', '?', '?', '?', '?', '?', '?', '?' // 255
};
const char ACGT_UPPER_LUT[256] = {
'?', '?', '?', '?', '?', '?', '?', '?', // 7
'?', '?', '?', '?', '?', '?', '?', '?', // 15
'?', '?', '?', '?', '?', '?', '?', '?', // 23
'?', '?', '?', '?', '?', '?', '?', '?', // 31
'?', '?', '?', '?', '?', '?', '?', '?', // 39
'?', '?', '?', '?', '?', '?', '?', '?', // 47
'?', '?', '?', '?', '?', '?', '?', '?', // 55
'?', '?', '?', '?', '?', '?', '?', '?', // 63
'?', 'A', '?', 'C', '?', '?', '?', 'G', // 71
'?', '?', '?', '?', '?', '?', '?', '?', // 79
'?', '?', '?', '?', 'T', '?', '?', '?', // 87
'?', '?', '?', '?', '?', '?', '?', '?', // 95
'?', 'A', '?', 'C', '?', '?', '?', 'G', // 103
'?', '?', '?', '?', '?', '?', '?', '?', // 111
'?', '?', '?', '?', 'T', '?', '?', '?', // 119
'?', '?', '?', '?', '?', '?', '?', '?', // 127
'?', '?', '?', '?', '?', '?', '?', '?', // 135
'?', '?', '?', '?', '?', '?', '?', '?', // 143
'?', '?', '?', '?', '?', '?', '?', '?', // 151
'?', '?', '?', '?', '?', '?', '?', '?', // 159
'?', '?', '?', '?', '?', '?', '?', '?', // 167
'?', '?', '?', '?', '?', '?', '?', '?', // 175
'?', '?', '?', '?', '?', '?', '?', '?', // 183
'?', '?', '?', '?', '?', '?', '?', '?', // 191
'?', '?', '?', '?', '?', '?', '?', '?', // 199
'?', '?', '?', '?', '?', '?', '?', '?', // 207
'?', '?', '?', '?', '?', '?', '?', '?', // 215
'?', '?', '?', '?', '?', '?', '?', '?', // 223
'?', '?', '?', '?', '?', '?', '?', '?', // 231
'?', '?', '?', '?', '?', '?', '?', '?', // 239
'?', '?', '?', '?', '?', '?', '?', '?', // 247
'?', '?', '?', '?', '?', '?', '?', '?' // 255
};
const char IS_UPPERCASE_ACGT_LUT[256] = {
0, 0, 0, 0, 0, 0, 0, 0, // 7
0, 0, 0, 0, 0, 0, 0, 0, // 15
0, 0, 0, 0, 0, 0, 0, 0, // 23
0, 0, 0, 0, 0, 0, 0, 0, // 31
0, 0, 0, 0, 0, 0, 0, 0, // 39
0, 0, 0, 0, 0, 0, 0, 0, // 47
0, 0, 0, 0, 0, 0, 0, 0, // 55
0, 0, 0, 0, 0, 0, 0, 0, // 63
0, 1, 0, 1, 0, 0, 0, 1, // 71 (A=65, C=67, G=71)
0, 0, 0, 0, 0, 0, 0, 0, // 79
0, 0, 0, 0, 1, 0, 0, 0, // 87 (T=84)
0, 0, 0, 0, 0, 0, 0, 0, // 95
0, 0, 0, 0, 0, 0, 0, 0, // 103
0, 0, 0, 0, 0, 0, 0, 0, // 111
0, 0, 0, 0, 0, 0, 0, 0, // 119
0, 0, 0, 0, 0, 0, 0, 0, // 127
0, 0, 0, 0, 0, 0, 0, 0, // 135
0, 0, 0, 0, 0, 0, 0, 0, // 143
0, 0, 0, 0, 0, 0, 0, 0, // 151
0, 0, 0, 0, 0, 0, 0, 0, // 159
0, 0, 0, 0, 0, 0, 0, 0, // 167
0, 0, 0, 0, 0, 0, 0, 0, // 175
0, 0, 0, 0, 0, 0, 0, 0, // 183
0, 0, 0, 0, 0, 0, 0, 0, // 191
0, 0, 0, 0, 0, 0, 0, 0, // 199
0, 0, 0, 0, 0, 0, 0, 0, // 207
0, 0, 0, 0, 0, 0, 0, 0, // 215
0, 0, 0, 0, 0, 0, 0, 0, // 223
0, 0, 0, 0, 0, 0, 0, 0, // 231
0, 0, 0, 0, 0, 0, 0, 0, // 239
0, 0, 0, 0, 0, 0, 0, 0, // 247
0, 0, 0, 0, 0, 0, 0, 0 // 255
};
#endif
primer3-py-2.3.1/primer3/p3helpers.pxd 0000664 0000000 0000000 00000002033 15247271707 0017541 0 ustar 00root root 0000000 0000000 # cython: language_level=3
# Copyright (C) 2023-2026. Ben Pruitt & Nick Conway;
# See LICENSE for full GPLv2 license.
# Declare external C functions and variables
cdef extern from "p3helpers.h":
const char COMP_BASE_LUT[256]
const char SANITIZE_LUT[256]
const char ACGT_UPPER_LUT[256]
const char IS_UPPERCASE_ACGT_LUT[256]
# Declare internal C functions
cdef int ss_rev_comp_seq(char* seq, Py_ssize_t length) except -1 nogil
cdef int ss_sanitize_seq(char* seq, Py_ssize_t length) except -1 nogil
cdef int ss_needs_conversion(const char* seq, Py_ssize_t length) except -1 nogil
cdef int ss_ensure_acgt_upper(char* seq, Py_ssize_t length) except -1 nogil
# Declare Python-visible functions - these must match EXACTLY how they're defined in pyx
cpdef str reverse_complement(str seq, bint do_sanitize=*)
cpdef bytes reverse_complement_b(bytes seq, bint do_sanitize=*)
cpdef str sanitize_sequence(str seq)
cpdef bytes sanitize_sequence_b(bytes seq)
cpdef str ensure_acgt_uppercase(str seq)
cpdef bytes ensure_acgt_uppercase_b(bytes seq)
primer3-py-2.3.1/primer3/p3helpers.pyx 0000664 0000000 0000000 00000031353 15247271707 0017575 0 ustar 00root root 0000000 0000000 # cython: language_level=3
# Copyright (C) 2023-2026. Ben Pruitt & Nick Conway;
# See LICENSE for full GPLv2 license.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
'''
primer3.p3helpers
~~~~~~~~~~~~~~~~~~~~~~
Contains Cython functions and classes that aid primer design
'''
from cpython.mem cimport (
PyMem_Free,
PyMem_Malloc,
)
from cython cimport typeof
from libc.string cimport memcpy
cdef extern from "p3helpers.h":
const char COMP_BASE_LUT[256]
const char SANITIZE_LUT[256]
const char ACGT_UPPER_LUT[256]
const char IS_UPPERCASE_ACGT_LUT[256]
cdef:
char INVALID_BASE = 63 # '?' character
cdef inline void copy_c_char_buffer(
const char* in_buf,
char* out_buf,
Py_ssize_t str_length,
) noexcept nogil:
'''Copy bytes from input buffer to output buffer.
This is a low-level helper that performs a direct memory copy without any bounds checking.
The caller must ensure buffers are properly sized.
Safety requirements:
- in_buf must be valid for at least str_length bytes
- out_buf must be valid for at least str_length bytes
- Buffers must not overlap
Args:
in_buf: input buffer to copy from
out_buf: output buffer to copy to
str_length: number of bytes to copy
'''
memcpy(out_buf, in_buf, str_length) # Copy exactly str_length bytes
cdef int ss_rev_comp_seq(
char* seq,
Py_ssize_t length,
) except -1 nogil:
'''Reverse complement sequence C string
Args:
seq: sequence to sanitize
length: length of sequence
Returns:
0 on success, 1 on error (Invalid base)
'''
cdef:
char temp
char* end_ptr = NULL
end_ptr = seq + (length - 1)
while end_ptr > seq:
temp = end_ptr[0]
end_ptr[0] = COMP_BASE_LUT[ seq[0]]
if end_ptr[0] == INVALID_BASE:
return 1
end_ptr -= 1
seq[0] = COMP_BASE_LUT[ temp]
if seq[0] == INVALID_BASE:
return 1
seq += 1
if length % 2:
seq[0] = COMP_BASE_LUT[ seq[0]]
if seq[0] == INVALID_BASE:
return 1
return 0
cdef int ss_sanitize_seq(
char* seq,
Py_ssize_t length,
) except -1 nogil:
'''Sanitize sequence C string IUPAC non-{A,C,G,T,a,c,g,t} bases with {N, n}
Args:
seq: sequence to sanitize
length: length of sequence
Returns:
0 on success, 1 on error (Invalid base)
'''
cdef:
char* end_ptr = seq + length
while seq < end_ptr:
seq[0] = SANITIZE_LUT[ seq[0]]
if seq[0] == INVALID_BASE:
return 1
seq += 1
return 0
cdef int ss_needs_conversion(
const char* seq,
Py_ssize_t length,
) except -1 nogil:
'''Fast check if sequence needs conversion (contains lowercase or non-ACGT chars)
using lookup table for O(1) per-character checks.
Args:
seq: sequence to check
length: length of sequence
Returns:
1 if sequence needs conversion, 0 if it's already uppercase ACGT
'''
cdef:
const char* end_ptr = seq + length
while seq < end_ptr:
if not IS_UPPERCASE_ACGT_LUT[ seq[0]]:
return 1
seq += 1
return 0
cdef int ss_ensure_acgt_upper(
char* seq,
Py_ssize_t length,
) except -1 nogil:
'''Convert sequence to uppercase and validate it contains only A, C, G, T bases
Args:
seq: sequence to convert to uppercase and validate
length: length of sequence
Returns:
0 on success, 1 on error (non-ACGT base)
'''
cdef:
char* end_ptr = seq + length
while seq < end_ptr:
seq[0] = ACGT_UPPER_LUT[ seq[0]]
if seq[0] == INVALID_BASE:
return 1
seq += 1
return 0
cpdef str reverse_complement(
str seq,
bint do_sanitize = False,
):
'''Compute reverse complement of the python string sequence
Args:
seq: sequence string
do_sanitize: If True, convert non-IUPAC characters to N's
Returns:
Reverse complement of sequence string
Raises:
ValueError: Invalid base in sequence
'''
# Delegate to the bytes implementation, which operates on a private
# malloc'd copy (never mutating an immutable bytes buffer) and uses the
# UTF-8 byte length rather than the code-point count.
return reverse_complement_b(seq.encode('utf8'), do_sanitize).decode('utf8')
cpdef bytes reverse_complement_b(
bytes seq,
bint do_sanitize = False,
):
'''Compute reverse complement of the bytes sequence
Args:
seq: sequence in bytes
do_sanitize: If True, convert non-IUPAC characters to N's
Returns:
Reverse complement of sequence in bytes
Raises:
ValueError: Invalid base in sequence
OSError: ``malloc`` failure
'''
cdef:
char* seq_c = NULL
Py_ssize_t seq_len = len(seq)
char* seq_operate_c = NULL
bytes seq_out
int check = 0
# Allocate one extra byte for null termination
seq_operate_c = PyMem_Malloc((seq_len + 1) * sizeof(char))
if seq_operate_c == NULL:
raise OSError('malloc failure')
# convert to C str
seq_c = seq
# MUST COPY as python does not mutate bytes
copy_c_char_buffer(seq_c, seq_operate_c, seq_len)
seq_operate_c[seq_len] = 0 # ensure null terminated
check = ss_rev_comp_seq(seq_operate_c, seq_len)
if check:
PyMem_Free(seq_operate_c)
seq_operate_c = NULL
raise ValueError(f'Invalid base in sequence {seq}')
if do_sanitize:
check = ss_sanitize_seq(seq_operate_c, seq_len)
if check:
PyMem_Free(seq_operate_c)
seq_operate_c = NULL
raise ValueError(f'Invalid base in sequence {seq}')
# Create bytes object of exact length without null terminator
seq_out = seq_operate_c[:seq_len]
PyMem_Free(seq_operate_c)
seq_operate_c = NULL
return seq_out
cpdef str sanitize_sequence(
str seq,
):
'''Sanitize sequence with non-standard bases with `N`s
IUPAC {R,Y,M,K,S,W,H,D,B,V,r,y,m,k,s,w,h,d,b,v}
IUPAC non-{A,C,G,T,a,c,g,t} bases become {N, n}
NOTE: Consider keeping a copy of original ``seq`` argument for record
keeping
Args:
seq: sequence to sanitize nonstandard with `N`s or `n`s
Returns:
sanitized version of ``seq``
Raises:
ValueError: Invalid base in sequence
'''
# Delegate to the bytes implementation, which operates on a private
# malloc'd copy (never mutating an immutable bytes buffer) and uses the
# UTF-8 byte length rather than the code-point count.
return sanitize_sequence_b(seq.encode('utf8')).decode('utf8')
cpdef bytes sanitize_sequence_b(
bytes seq,
):
'''Sanitize bytes sequence with non-standard bases with `N`s
IUPAC {R,Y,M,K,S,W,H,D,B,V,r,y,m,k,s,w,h,d,b,v}
IUPAC non-{A,C,G,T,a,c,g,t} bases become {N, n}
NOTE: Consider keeping a copy of original ``seq`` argument for record
keeping
Args:
seq: sequence to sanitize nonstandard with `N`s or `n`s
Returns:
sanitized version of ``seq``
Raises:
ValueError: Invalid base in sequence
OSError: ``malloc`` failure
'''
cdef:
char* seq_c = NULL
Py_ssize_t seq_len = len(seq)
char* seq_operate_c = NULL
bytes seq_out
int check = 0
# Allocate one extra byte for null termination
seq_operate_c = PyMem_Malloc((seq_len + 1) * sizeof(char))
if seq_operate_c == NULL:
raise OSError('malloc failure')
# convert to C str
seq_c = seq
# MUST COPY as python does not mutate bytes
copy_c_char_buffer(seq_c, seq_operate_c, seq_len)
seq_operate_c[seq_len] = 0 # ensure null terminated
check = ss_sanitize_seq(seq_operate_c, seq_len)
if check:
PyMem_Free(seq_operate_c)
seq_operate_c = NULL
raise ValueError(f'Invalid base in sequence {seq}')
# Create bytes object of exact length without null terminator
seq_out = seq_operate_c[:seq_len]
PyMem_Free(seq_operate_c)
seq_operate_c = NULL
return seq_out
cpdef str ensure_acgt_uppercase(
str seq,
):
'''Convert sequence to uppercase and validate it contains only A, C, G, T bases.
This is stricter than sanitize_sequence() as it only allows A, C, G, T bases.
If the sequence is already uppercase ACGT, returns the original string without
any allocation or copying.
Args:
seq: sequence to convert to uppercase and validate
Returns:
uppercase version of seq containing only A, C, G, T bases
Raises:
ValueError: If sequence contains any characters other than A, C, G, T (case insensitive)
'''
cdef:
char* seq_c = NULL
char* seq_operate_c = NULL
Py_ssize_t seq_len = len(seq)
Py_ssize_t byte_len = 0
if seq_len == 0:
return seq
seq_b = seq.encode('utf8')
seq_c = seq_b
byte_len = len(seq_b) # UTF-8 byte length, not the code-point count
# Fast path: check if sequence needs conversion (read-only)
if not ss_needs_conversion(seq_c, byte_len):
return seq # Return original if already uppercase ACGT
# Slow path: convert on a private copy rather than mutating the
# immutable bytes buffer returned by encode().
seq_operate_c = PyMem_Malloc((byte_len + 1) * sizeof(char))
if seq_operate_c == NULL:
raise OSError('malloc failure')
try:
copy_c_char_buffer(seq_c, seq_operate_c, byte_len)
seq_operate_c[byte_len] = 0 # ensure null terminated
if ss_ensure_acgt_upper(seq_operate_c, byte_len):
# Find the problematic character
for i, c in enumerate(seq):
if c.upper() not in 'ACGT':
raise ValueError(
f"Sequence contains non-ACGT base '{c}' at position {i}: {seq}"
)
return seq_operate_c[:byte_len].decode('utf8')
finally:
PyMem_Free(seq_operate_c)
seq_operate_c = NULL
cpdef bytes ensure_acgt_uppercase_b(
bytes seq,
):
'''Convert bytes sequence to uppercase and validate it contains only A, C, G, T bases.
This is stricter than sanitize_sequence_b() as it only allows A, C, G, T bases.
If the sequence is already uppercase ACGT, returns the original bytes without
any allocation or copying.
Args:
seq: sequence to convert to uppercase and validate
Returns:
uppercase version of seq containing only A, C, G, T bases
Raises:
ValueError: If sequence contains any characters other than A, C, G, T (case insensitive)
OSError: malloc failure
'''
cdef:
char* seq_c = NULL
Py_ssize_t seq_len = len(seq)
char* seq_operate_c = NULL
bytes seq_out
int needs_conversion = 0
if seq_len == 0:
return seq
# Fast path: check if sequence needs conversion
seq_c = seq
needs_conversion = ss_needs_conversion(seq_c, seq_len)
if not needs_conversion:
return seq # Return original if already uppercase ACGT
# Slow path: needs conversion
seq_operate_c = PyMem_Malloc((seq_len + 1) * sizeof(char))
if seq_operate_c == NULL:
raise OSError('malloc failure')
try:
copy_c_char_buffer(seq_c, seq_operate_c, seq_len)
seq_operate_c[seq_len] = 0 # ensure null terminated
if ss_ensure_acgt_upper(seq_operate_c, seq_len):
# Find the problematic character. Iterate raw bytes (not
# seq.decode) so a non-UTF8 byte (>= 0x80) yields a ValueError
# rather than a UnicodeDecodeError.
for i in range(seq_len):
c = chr(seq[i])
if c.upper() not in 'ACGT':
raise ValueError(
f"Sequence contains non-ACGT base '{c}' at position {i}: {seq}"
)
# Create bytes object with the correct length
seq_out = seq_operate_c[:seq_len]
return seq_out
finally:
PyMem_Free(seq_operate_c)
seq_operate_c = NULL
primer3-py-2.3.1/primer3/src/ 0000775 0000000 0000000 00000000000 15247271707 0015710 5 ustar 00root root 0000000 0000000 primer3-py-2.3.1/primer3/src/libprimer3/ 0000775 0000000 0000000 00000000000 15247271707 0017760 5 ustar 00root root 0000000 0000000 primer3-py-2.3.1/primer3/src/libprimer3/ABOUT.txt 0000664 0000000 0000000 00000000366 15247271707 0021400 0 ustar 00root root 0000000 0000000 The source files in this directory are derived from the Primer 2.6.1
source and have been modified to make the library more amenable to
Python bindings.
All modifications and related distribution are performed under the GPLv2
(see LICENSE.txt).
primer3-py-2.3.1/primer3/src/libprimer3/LICENSE.txt 0000664 0000000 0000000 00000043103 15247271707 0021604 0 ustar 00root root 0000000 0000000 GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
Copyright (C)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.
primer3-py-2.3.1/primer3/src/libprimer3/Makefile 0000664 0000000 0000000 00000026145 15247271707 0021430 0 ustar 00root root 0000000 0000000 # ======================================================================
# (c) Copyright 1996 - 2018
# Whitehead Institute for Biomedical Research, Steve Rozen,
# Andreas Untergasser and Helen Skaletsky
# All rights reserved.
#
# This file is part of primer3, the libprimer3 library, the oligotm
# library and the dpal library.
#
# Primer3 and the libraries above are free software; you can
# redistribute them and/or modify them under the terms of the GNU
# General Public License as published by the Free Software Foundation;
# either version 2 of the License, or (at your option) any later
# version.
#
# This software is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this file (file gpl-2.0.txt in the source distribution); if
# not, write to the Free Software Foundation, Inc., 51 Franklin St,
# Fifth Floor, Boston, MA 02110-1301 USA
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# ======================================================================
# ======================================================================
# CITING PRIMER3
#
# Steve Rozen and Helen J. Skaletsky (2000) Primer3 on the WWW for
# general users and for biologist programmers. In: Krawetz S, Misener S
# (eds) Bioinformatics Methods and Protocols: Methods in Molecular
# Biology. Humana Press, Totowa, NJ, pp 365-386. Source code available
# from https://github.com/primer3-org/primer3
# ======================================================================
# For VALGRIND -- see end of this makefile for testing primer3_core
# with valgrind, a leak and memory access checker.
TESTOPTS=
WINMAKE=mingw32-make
LDLIBS = -lm
AR = ar
CC = gcc
O_OPTS = -O2
CC_OPTS = -g -Wall -D__USE_FIXED_PROTOTYPES__
P_DEFINES =
CFLAGS = $(CC_OPTS) $(O_OPTS) -I klib
# CCFLAGS = $(CFLAGS) -std=c++11
LDFLAGS = -g
# Note, for profiling, use
# make O_OPTS='-pg -O0' LDFLAGS='-g -pg'
# Target installation directory
PREFIX = /usr/local
# ======================================================================
# If you have trouble with library skew when moving primer3 executables
# between systems, you might want to set LIBOPTS to -static
LIBOPTS =
ifeq ($(TESTOPTS),--windows)
PRIMER_EXE = primer3_core.exe
NTDPAL_EXE = ntdpal.exe
NTTHAL_EXE = ntthal.exe
OLIGOTM_EXE = oligotm.exe
AMPLICONTM_EXE = amplicon3_core.exe
LONG_SEQ_EXE = long_seq_tm_test.exe
else
PRIMER_EXE = primer3_core
NTDPAL_EXE = ntdpal
NTTHAL_EXE = ntthal
OLIGOTM_EXE = oligotm
AMPLICONTM_EXE = amplicon3_core
LONG_SEQ_EXE = long_seq_tm_test
MASKER_EXE = primer3_masker
endif
LIBOLIGOTM = liboligotm.a
LIBOLIGOTM_DYN = liboligotm.so.1.2.0
LIBAMPTM = libamplicontm.a
LIBAMPTM_DYN = libamplicontm.so.1.0.0
LIBDPAL = libdpal.a
LIBDPAL_DYN = libdpal.a.so.1.0.0
LIBTHAL = libthal.a
LIBTHAL_DYN = libthal.a.so.1.0.0
LIBTHALPARA = libthalpara.a
LIBTHALPARA_DYN = libthalpara.a.so.1.0.0
LIBPRIMER3 = libprimer3.a
LIBPRIMER3_DYN = libprimer3.so.1.0.0
ifeq ($(TESTOPTS),--windows)
$(info windows)
LIBRARIES = $(LIBPRIMER3) $(LIBDPAL) $(LIBTHAL) $(LIBTHALPARA) $(LIBAMPTM) $(LIBOLIGOTM)
DYNLIBS = $(LIBPRIMER3_DYN) $(LIBDPAL_DYN) $(LIBTHAL_DYN) $(LIBTHALPARA_DYN) $(LIBAMPTM_DYN) $(LIBOLIGOTM_DYN)
else
$(info no windows)
LIBMASKER = libmasker.a
LIBMASKER_DYN = libmasker.a.so.1.0.0
LIBRARIES = $(LIBPRIMER3) $(LIBDPAL) $(LIBTHAL) $(LIBTHALPARA) $(LIBOLIGOTM) $(LIBAMPTM) $(LIBMASKER)
DYNLIBS = $(LIBPRIMER3_DYN) $(LIBDPAL_DYN) $(LIBTHAL_DYN) $(LIBTHALPARA_DYN) $(LIBAMPTM_DYN) $(LIBOLIGOTM_DYN) $(LIBMASKER_DYN)
endif
RANLIB = ranlib
PRIMER_OBJECTS1=primer3_boulder_main.o\
format_output.o\
read_boulder.o\
print_boulder.o
PRIMER_OBJECTS=$(PRIMER_OBJECTS1) $(LIBRARIES)
PRIMER_DYN_OBJECTS=$(PRIMER_OBJECTS1) $(DYNLIBS)
# These are files generated by running ./primer3_core < ../example
example_files=example.for example.rev example.int
ifeq ($(TESTOPTS),--windows)
EXES=$(PRIMER_EXE) $(NTDPAL_EXE) $(NTTHAL_EXE) $(AMPLICONTM_EXE) $(OLIGOTM_EXE) $(LONG_SEQ_EXE)
else
EXES=$(PRIMER_EXE) $(NTDPAL_EXE) $(NTTHAL_EXE) $(AMPLICONTM_EXE) $(OLIGOTM_EXE) $(LONG_SEQ_EXE) $(MASKER_EXE)
endif
all: $(EXES) $(LIBRARIES)
clean_src:
ifeq ($(TESTOPTS),--windows)
del /Q /F *.o $(EXES) *~ $(LIBRARIES) $(example_files) core ../*~
else
-rm -f *.o $(EXES) *~ $(LIBRARIES) $(DYNLIBS) $(example_files) core ../*~
endif
clean: clean_src
# ifeq ($(TESTOPTS),--windows)
# cd ../test & $(WINMAKE) clean TESTOPTS=$(TESTOPTS)
# else
# cd ../test/; make clean
# endif
$(LIBOLIGOTM): oligotm.o
$(AR) rv $@ oligotm.o
$(RANLIB) $@
$(LIBOLIGOTM_LIB): oligotm.o
$(CC) -shared -W1,-soname,liboligotm.so.1 -o $(LIBOLIGOTM_DYN) oligotm.o
$(LIBAMPTM): amplicontm.o
$(AR) rv $@ amplicontm.o
$(RANLIB) $@
$(LIBAMPTM_LIB): amplicontm.o
$(CC) -shared -W1,-soname,libamplicontm.so.1 -o $(LIBAMPTM_DYN) amplicontm.o
$(LIBDPAL): dpal_primer.o
$(AR) rv $@ dpal_primer.o
$(RANLIB) $@
$(LIBDPAL_DYN): dpal_primer.o
$(CC) -shared -W1,-soname,libdpal.so.1 -o $(LIBDPAL_DYN_LIB) dpal_primer.o
$(LIBTHAL): thal_primer.o
$(AR) rv $@ thal_primer.o
$(RANLIB) $@
$(LIBTHAL_DYN): thal_primer.o
$(CC) -shared -W1,-soname,libthal.so.1 -o $(LIBTHAL_DYN_LIB) thal_primer.o
$(LIBTHALPARA): thal_parameters.o
$(AR) rv $@ thal_parameters.o
$(RANLIB) $@
$(LIBTHALPARA_DYN): thal_parameters.o
$(CC) -shared -W1,-soname,libthalpara.so.1 -o $(LIBTHALPARA_DYN_LIB) thal_parameters.o
$(LIBPRIMER3): libprimer3.o p3_seq_lib.o
$(AR) rv $@ libprimer3.o p3_seq_lib.o
$(RANLIB) $@
$(LIBPRIMER3_DYN): libprimer3.o p3_seq_lib.o
$(CC) -shared -W1,-soname,liprimer3.so.1 -o $(LIBPRIMER3_DYN) libprimer3.o p3_seq_lib.o
$(LIBMASKER): masker.o
$(AR) rv $@ masker.o
$(RANLIB) $@
$(LIBMASKER_DYN): masker.o
$(CC) -shared -W1,-soname,libmasker.so.1 -o $(LIBMASKER_DYN) masker.o
$(PRIMER_EXE): $(PRIMER_OBJECTS)
$(CC) $(LDFLAGS) -o $@ $(PRIMER_OBJECTS) $(LIBOPTS) $(LDLIBS)
libprimer3.o: libprimer3.c libprimer3.h p3_seq_lib.h dpal.h thal.h thal_parameters.h oligotm.h
$(CC) -c $(CFLAGS) -Wno-deprecated $(P_DEFINES) -o $@ libprimer3.c
$(NTDPAL_EXE): ntdpal_main.o dpal.o
$(CC) $(LDFLAGS) -o $@ ntdpal_main.o dpal.o
$(NTTHAL_EXE): thal_main.o thal.o thal_parameters.o
$(CC) $(LDFLAGS) -o $@ thal_main.o thal.o thal_parameters.o $(LDLIBS)
$(OLIGOTM_EXE): oligotm_main.c oligotm.h $(LIBOLIGOTM)
$(CC) $(CFLAGS) -o $@ oligotm_main.c $(LIBOLIGOTM) $(LIBOPTS) $(LDLIBS)
$(AMPLICONTM_EXE): amplicontm_main.c amplicontm.h $(LIBAMPTM)
$(CC) $(CFLAGS) -o $@ amplicontm_main.c $(LIBAMPTM) $(LIBOPTS) $(LDLIBS)
$(LONG_SEQ_EXE): long_seq_tm_test_main.c oligotm.o
$(CC) $(CFLAGS) -o $@ long_seq_tm_test_main.c oligotm.o $(LIBOPTS) $(LDLIBS)
$(MASKER_EXE): masker_main.c $(LIBRARIES)
$(CC) $(LDFLAGS) -o $@ masker_main.c $(LIBRARIES) $(LIBOPTS) $(LDLIBS)
read_boulder.o: read_boulder.c read_boulder.h libprimer3.h dpal.h thal.h thal_parameters.h p3_seq_lib.h
$(CC) -c $(CFLAGS) $(P_DEFINES) -o $@ read_boulder.c
print_boulder.o: print_boulder.c print_boulder.h libprimer3.h p3_seq_lib.h
$(CC) -c $(CFLAGS) $(P_DEFINES) -o $@ print_boulder.c
dpal.o: dpal.c dpal.h
$(CC) -c $(CFLAGS) -o $@ dpal.c
# We use '-ffloat-store' on windows to prevent undesirable
# precision which may lead to differences in floating point results.
thal.o: thal.c thal.h thal_parameters.h
$(CC) -c $(CFLAGS) -ffloat-store -o $@ thal.c
thal_parameters.o: thal_parameters.c thal_parameters.h thal.h
$(CC) -c $(CFLAGS) -ffloat-store $(P_DEFINES) -o $@ thal_parameters.c
p3_seq_lib.o: p3_seq_lib.c p3_seq_lib.h libprimer3.h
$(CC) -c $(CFLAGS) -o $@ p3_seq_lib.c
dpal_primer.o: dpal.c dpal.h
$(CC) -c $(CFLAGS) $(P_DEFINES) -o $@ dpal.c
thal_primer.o: thal.c thal.h thal_parameters.h
$(CC) -c $(CFLAGS) -ffloat-store $(P_DEFINES) -o $@ thal.c
format_output.o: format_output.c format_output.h libprimer3.h dpal.h thal.h p3_seq_lib.h
$(CC) -c $(CFLAGS) $(P_DEFINES) -o $@ format_output.c
ntdpal_main.o: ntdpal_main.c dpal.h
$(CC) -c $(CC_OPTS) -o $@ ntdpal_main.c
thal_main.o: thal_main.c thal.h thal_parameters.h
$(CC) -c $(CFLAGS) -o $@ thal_main.c
# We use CC_OPTS above rather than CFLAGS because
# gcc 2.7.2 crashes while compiling ntdpal_main.c with -O2
amplicontm.o: amplicontm.c amplicontm.h
oligotm.o: oligotm.c oligotm.h
primer3_boulder_main.o: primer3_boulder_main.c libprimer3.h dpal.h thal.h thal_parameters.h oligotm.h format_output.h print_boulder.h read_boulder.h
$(CC) -c $(CFLAGS) $(P_DEFINES) primer3_boulder_main.c
masker.o: masker.c masker.h libprimer3.h
$(CC) -c $(CFLAGS) $(P_DEFINES) masker.c
# primer_test: test
# test: $(PRIMER_EXE) $(NTDPAL_EXE) $(NTTHAL_EXE)
# ifeq ($(TESTOPTS),--windows)
# cd ../test & $(WINMAKE) TESTOPTS=$(TESTOPTS)
# else
# cd ../test; make test
# endif
install: $(EXES) $(LIBRARIES)
install -d "$(PREFIX)/bin"
install -m 755 $(EXES) "$(PREFIX)/bin"
# ======================================================================
#
# VALGRIND INSTRUCTIONS.
#
# These instructions work for linux, and run the 'memcheck'
# functionality of valgrind. Tests will be _much_ slower
# when running with valgrind checks.
#
# If necessary, get and install valgrind (should come with most
# Linux's, but you need valgrind >= 3.2.3)
#
# In the src directory for primer3:
#
# $ make clean
#
# Re-complile without optimization and run the normal tests, does
# _not_ valgrind them:
#
# $ make O_OPTS=-O0 test # The value of O_OPTS is Minus Oh Zero
#
# Run valgrind on a small example:
#
# $ valgrind --leak-check=yes --show-reachable=yes --log-file-exactly=p3vg ./primer3_core < ../example
#
# Check output in file p3vg
#
# Note: Valgrind is at /usr/local/bin/valgrind at WI
#
# OK, now for the real tests:
#
# $ cd ../test
#
# Check valgrind path in p3test.pl, ntdpal_test.pl, and oligotm_test.pl
# and correct if necessary. This code works under valgrind 3.2.3.
#
# $ make TESTOPTS=--valgrind # Remember, you have to be in test/
#
# When the --valgrind flag is set, the perl test scripts grep for and
# display errors and leaks, but you need to ***look at the output** to
# see these and figure out which test caused the problem, so you can
# debug it.
#
# ======================================================================
primer3-py-2.3.1/primer3/src/libprimer3/Makefile.OSX 0000664 0000000 0000000 00000022522 15247271707 0022073 0 ustar 00root root 0000000 0000000 # ======================================================================
# (c) Copyright 1996,1997,1998,1999,2000,2001,2004,2006,2007,2008,2009
# Whitehead Institute for Biomedical Research, Steve Rozen,
# Andreas Untergasser and Helen Skaletsky
# All rights reserved.
#
# This file is part of primer3, the libprimer3 library, the oligotm
# library and the dpal library.
#
# Primer3 and the libraries above are free software; you can
# redistribute them and/or modify them under the terms of the GNU
# General Public License as published by the Free Software Foundation;
# either version 2 of the License, or (at your option) any later
# version.
#
# This software is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this file (file gpl-2.0.txt in the source distribution); if
# not, write to the Free Software Foundation, Inc., 51 Franklin St,
# Fifth Floor, Boston, MA 02110-1301 USA
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# ======================================================================
# ======================================================================
# CITING PRIMER3
#
# Steve Rozen and Helen J. Skaletsky (2000) Primer3 on the WWW for
# general users and for biologist programmers. In: Krawetz S, Misener S
# (eds) Bioinformatics Methods and Protocols: Methods in Molecular
# Biology. Humana Press, Totowa, NJ, pp 365-386. Source code available
# from https://sourceforge.net/projects/primer3/
# ======================================================================
# For VALGRIND -- see end of this makefile for testing primer3_core
# with valgrind, a leak and memory access checker.
TESTOPTS=
WINMAKE=mingw32-make
DEVELOPER=`xcode-select -print-path`
# this is clumsy, but deals with the moving compilers on OSX
ifndef SDKROOT
SDKROOT=$(DEVELOPER)/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.6.sdk
endif
ifneq (exists, $(shell [ -d $(SDKROOT) ] && echo exists))
SDKROOT=$(DEVELOPER)/SDKs/MacOSX10.6.sdk
endif
ifndef MACOSX_DEPLOYMENT_TARGET
MACOSX_DEPLOYMENT_TARGET=10.6
endif
ifndef ARCHS
ARCHS=i386 x86_64
endif
LDLIBS = -lm
CC = gcc
LIBTOOL = libtool
O_OPTS = -O2
CC_OPTS = -g -Wall -D__USE_FIXED_PROTOTYPES__ -isysroot $(SDKROOT) -mmacosx-version-min=$(MACOSX_DEPLOYMENT_TARGET) $(foreach ARCH,$(ARCHS),-arch $(ARCH))
P_DEFINES =
CFLAGS = $(CC_OPTS) $(O_OPTS) -I klib
LDFLAGS = -g $(foreach ARCH,$(ARCHS),-arch $(ARCH))
# ======================================================================
# If you have trouble with library skew when moving primer3 executables
# between systems, you might want to set LIBOPTS to -static
LIBOPTS =
ifeq ($(TESTOPTS),--windows)
PRIMER_EXE = primer3_core.exe
NTDPAL_EXE = ntdpal.exe
NTTHAL_EXE = ntthal.exe
OLIGOTM_EXE = oligotm.exe
LONG_SEQ_EXE = long_seq_tm_test.exe
else
PRIMER_EXE = primer3_core
NTDPAL_EXE = ntdpal
NTTHAL_EXE = ntthal
OLIGOTM_EXE = oligotm
LONG_SEQ_EXE = long_seq_tm_test
endif
LIBOLIGOTM = liboligotm.a
LIBOLIGOTM_DYN = liboligotm.so.1.2.0
LIBDPAL = libdpal.a
LIBDPAL_DYN = libdpal.a.so.1.0.0
LIBTHAL = libthal.a
LIBTHAL_DYN = libthal.a.so.1.0.0
LIBPRIMER3 = libprimer3.a
LIBPRIMER3_DYN = libprimer3.so.1.0.0
LIBRARIES = $(LIBPRIMER3) $(LIBDPAL) $(LIBTHAL) $(LIBOLIGOTM)
DYNLIBS = $(LIBPRIMER3_DYN) $(LIBDPAL_DYN) $(LIBTHAL_DYN) $(LIBOLIGOTM_DYN)
PRIMER_OBJECTS1=print_boulder.o\
format_output.o\
read_boulder.o\
primer3_boulder_main.o
PRIMER_OBJECTS=$(PRIMER_OBJECTS1) $(LIBRARIES)
PRIMER_DYN_OBJECTS=$(PRIMER_OBJECTS1) $(DYNLIBS)
# These are files generated by running ./primer3_core < ../example
example_files=example.for example.rev example.int
EXES=$(PRIMER_EXE) $(NTDPAL_EXE) $(NTTHAL_EXE) $(OLIGOTM_EXE) $(LONG_SEQ_EXE)
all: $(EXES) $(LIBRARIES)
clean_src:
ifeq ($(TESTOPTS),--windows)
del /Q /F *.o $(EXES) *~ $(LIBRARIES) $(example_files) core ..\*~
else
-rm -f *.o $(EXES) *~ $(LIBRARIES) $(DYNLIBS) $(example_files) core ../*~
endif
clean: clean_src
# ifeq ($(TESTOPTS),--windows)
# cd ..\test & $(WINMAKE) clean TESTOPTS=$(TESTOPTS)
# else
# cd ../test/; make clean
# endif
$(LIBOLIGOTM): oligotm.o
$(LIBTOOL) -static -o $@ oligotm.o
$(LIBOLIGOTM_LIB): oligotm.o
$(CC) -shared -W1,-soname,liboligotm.so.1 -o $(LIBOLIGOTM_DYN) oligotm.o
$(LIBDPAL): dpal_primer.o
$(LIBTOOL) -static -o $@ dpal_primer.o
$(LIBDPAL_DYN): dpal_primer.o
$(CC) -shared -W1,-soname,libdpal.so.1 -o $(LIBDPAL_DYN_LIB) dpal_primer.o
$(LIBTHAL): thal_primer.o
$(LIBTOOL) -static -o $@ thal_primer.o
$(LIBTHAL_DYN): thal_primer.o
$(CC) -shared -W1,-soname,libthal.so.1 -o $(LIBTHAL_DYN_LIB) thal_primer.o
$(LIBPRIMER3): libprimer3.o p3_seq_lib.o
$(LIBTOOL) -static -o $@ libprimer3.o p3_seq_lib.o
$(LIBPRIMER3_DYN): libprimer3.o p3_seq_lib.o
$(CC) -shared -W1,-soname,liprimer3.so.1 -o $(LIBPRIMER3_DYN) libprimer3.o p3_seq_lib.o
$(PRIMER_EXE): $(PRIMER_OBJECTS)
$(CC) $(LDFLAGS) -o $@ $(PRIMER_OBJECTS) $(LIBOPTS) $(LDLIBS)
libprimer3.o: libprimer3.c libprimer3.h p3_seq_lib.h dpal.h thal.h oligotm.h
$(CC) -c $(CFLAGS) -Wno-deprecated $(P_DEFINES) -o $@ libprimer3.c
$(NTDPAL_EXE): ntdpal_main.o dpal.o
$(CC) $(LDFLAGS) -o $@ ntdpal_main.o dpal.o
$(NTTHAL_EXE): thal_main.o thal.o
$(CC) $(LDFLAGS) -o $@ thal_main.o thal.o $(LDLIBS)
$(OLIGOTM_EXE): oligotm_main.c oligotm.h $(LIBOLIGOTM)
$(CC) $(CFLAGS) -o $@ oligotm_main.c $(LIBOLIGOTM) $(LIBOPTS) $(LDLIBS)
$(LONG_SEQ_EXE): long_seq_tm_test_main.c oligotm.o
$(CC) $(CFLAGS) -o $@ long_seq_tm_test_main.c oligotm.o $(LIBOPTS) $(LDLIBS)
read_boulder.o: read_boulder.c read_boulder.h libprimer3.h dpal.h thal.h p3_seq_lib.h
$(CC) -c $(CFLAGS) $(P_DEFINES) -o $@ read_boulder.c
print_boulder.o: print_boulder.c print_boulder.h libprimer3.h p3_seq_lib.h
$(CC) -c $(CFLAGS) $(P_DEFINES) -o $@ print_boulder.c
dpal.o: dpal.c dpal.h
$(CC) -c $(CFLAGS) -o $@ dpal.c
# We use '-ffloat-store' on windows to prevent undesirable
# precision which may lead to differences in floating point results.
thal.o: thal.c thal.h
$(CC) -c $(CFLAGS) -ffloat-store -o $@ thal.c
p3_seq_lib.o: p3_seq_lib.c p3_seq_lib.h libprimer3.h
$(CC) -c $(CFLAGS) -o $@ p3_seq_lib.c
dpal_primer.o: dpal.c dpal.h
$(CC) -c $(CFLAGS) $(P_DEFINES) -o $@ dpal.c
thal_primer.o: thal.c thal.h
$(CC) -c $(CFLAGS) -ffloat-store $(P_DEFINES) -o $@ thal.c
format_output.o: format_output.c format_output.h libprimer3.h dpal.h thal.h p3_seq_lib.h
$(CC) -c $(CFLAGS) $(P_DEFINES) -o $@ format_output.c
ntdpal_main.o: ntdpal_main.c dpal.h
$(CC) -c $(CC_OPTS) -o $@ ntdpal_main.c
thal_main.o: thal_main.c thal.h
$(CC) -c $(CFLAGS) -o $@ thal_main.c
# We use CC_OPTS above rather than CFLAGS because
# gcc 2.7.2 crashes while compiling ntdpal_main.c with -O2
oligotm.o: oligotm.c oligotm.h
primer3_boulder_main.o: primer3_boulder_main.c libprimer3.h dpal.h thal.h oligotm.h format_output.h print_boulder.h read_boulder.h
$(CC) -c $(CFLAGS) $(P_DEFINES) primer3_boulder_main.c
# primer_test: test
# test: $(PRIMER_EXE) $(NTDPAL_EXE) $(NTTHAL_EXE)
# ifeq ($(TESTOPTS),--windows)
# cd ..\test & $(WINMAKE) TESTOPTS=$(TESTOPTS)
# else
# cd ../test; make test
# endif
# ======================================================================
#
# VALGRIND INSTRUCTIONS.
#
# These instructions work for linux, and run the 'memcheck'
# functionality of valgrind. Tests will be _much_ slower
# when running with valgrind checks.
#
# If necessary, get and install valgrind (should come with most
# Linux's, but you need valgrind >= 3.2.3)
#
# In the src directory for primer3:
#
# $ make clean
#
# Re-complile without optimization and run the normal tests, does
# _not_ valgrind them:
#
# $ make O_OPTS=-O0 test # The value of O_OPTS is Minus Oh Zero
#
# Run valgrind on a small example:
#
# $ valgrind --leak-check=yes --show-reachable=yes --log-file-exactly=p3vg ./primer3_core < ../example
#
# Check output in file p3vg
#
# Note: Valgrind is at /usr/local/bin/valgrind at WI
#
# OK, now for the real tests:
#
# $ cd ../test
#
# Check valgrind path in p3test.pl, ntdpal_test.pl, and oligotm_test.pl
# and correct if necessary. This code works under valgrind 3.2.3.
#
# $ make TESTOPTS=--valgrind # Remember, you have to be in test/
#
# When the --valgrind flag is set, the perl test scripts grep for and
# display errors and leaks, but you need to ***look at the output** to
# see these and figure out which test caused the problem, so you can
# debug it.
#
# ======================================================================
primer3-py-2.3.1/primer3/src/libprimer3/amplicontm.c 0000664 0000000 0000000 00000064402 15247271707 0022275 0 ustar 00root root 0000000 0000000 /*
Amplicon3 calculates melting temperatures for amplicons.
Copyright (c) 2021 Andreas Untergasser
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
----------------------------------------------------------------
Amplicon3 is based on MeltPolymer.c from the DECIPHER package
created by Erik Wright. DECIPHER is GPL-3 licensed.
*/
#include
#include
#include
#include
#include
#include "amplicontm.h"
#include
void free_amplicon_result(amplicon_result *res) {
if (res->seq != NULL) {
free(res->seq);
}
if (res->temp != NULL) {
free(res->temp);
}
if (res->pos_prob != NULL) {
free(res->pos_prob);
}
if (res->melt != NULL) {
free(res->melt);
}
if (res->deriv != NULL) {
free(res->deriv);
}
}
void amp_init_all(void **alloc_box, int max_count) {
for (int i = 0 ; i < max_count ; i++) {
alloc_box[i] = NULL;
}
}
void *amp_malloc(void **alloc_box, int *alloc_count, size_t size) {
*alloc_count = (*alloc_count) + 1;
alloc_box[*alloc_count] = malloc(size);
return alloc_box[*alloc_count];
}
void amp_free_all(void **alloc_box, int alloc_count) {
for (int i = 0 ; i < alloc_count ; i++) {
free(alloc_box[i + 1]);
}
}
void amp_zero_int(int *arr, int element_count) {
if (arr == NULL) {
return;
}
for(int i = 0 ; i < element_count ; i++) {
arr[i] = 0;
}
}
void amp_zero_double(double *arr, int element_count) {
if (arr == NULL) {
return;
}
for(int i = 0 ; i < element_count ; i++) {
arr[i] = 0.0;
}
}
/* Calculate the melting temperature of amplicon s. See
amplicontm.h and oligotm.h for documentation of arguments.
*/
amplicon_result amplicontm(const char *inseq,
double mv,
double dv,
double dntp,
double dmso,
double dmso_fact,
double formamid,
amp_tm_parameters_type tm_parameters,
amp_salt_correction_type salt_corrections,
amp_tm_method_type tm_formula,
int output) {
int i, j;
int max_count = 15;
int alloc_count = 0;
double schildkraut_corr = 0.0;
double last_min = 0.0;
void *alloc_box[max_count];
amp_init_all(alloc_box, max_count);
// Initialize return structure
amplicon_result ret;
ret.error = 0;
ret.mv = mv;
ret.dv = dv;
ret.dntp = dntp;
ret.dmso = dmso;
ret.dmso_fact = dmso_fact;
ret.formamid = formamid;
ret.seq_len = 0;
ret.seq = NULL;
ret.seq_gc = 0.0;
ret.temp_len = 0;
ret.temp = NULL;
ret.pos_prob = NULL;
ret.melt = NULL;
ret.deriv = NULL;
ret.melt_len = 0;
for (i = 0; i < 10; i++) {
ret.melt_points[i] = -10.0;
}
mv /= 1000.0;
dv /= 1000.0;
dntp /= 1000.0;
// Check Input
if (tm_parameters != breslauer_amp && tm_parameters != santalucia_amp) {
ret.error = 2;
return ret;
}
if (tm_parameters == breslauer_amp) {
ret.error = 5;
return ret;
}
if (salt_corrections != schildkraut_amps && salt_corrections != santalucia_amps && salt_corrections != owczarzy_amps) {
ret.error = 2;
return ret;
}
if (salt_corrections == owczarzy_amps) {
ret.error = 4;
return ret;
}
if (mv < 0.01 || dv < 0.0) {
ret.error = 2;
return ret;
}
int orilen = strlen(inseq);
int gc_count = 0;
ret.seq = (char *) malloc(sizeof(char) * (orilen + 1));
for (i = 0 ; i < orilen ; i++) {
ret.seq[ret.seq_len]=toupper(inseq[i]);
switch(ret.seq[ret.seq_len]) {
case 'C':
case 'G':
gc_count++;
case 'A':
case 'T':
ret.seq_len++;
break;
}
}
ret.seq[ret.seq_len] = '\0';
ret.seq_gc = 100.0 * gc_count / ret.seq_len;
if (tm_formula == bolton_amp) {
ret.melt_points[0] = 81.5 - ret.dmso * ret.dmso_fact
+ (0.453 * ret.seq_gc / 100.0 - 2.88) * ret.formamid
+ 16.6 * (log10(mv + sqrt(dv) * 3.795))
+ 0.41 * ret.seq_gc
- 600 / ret.seq_len;
ret.melt_len = 1;
return ret;
}
// Translate sequence to array positions
int *seq = (int *) amp_malloc(alloc_box, &alloc_count, sizeof(int) * ret.seq_len);
if (seq == NULL) {
ret.error = 1;
amp_free_all(alloc_box, alloc_count);
return ret;
}
for (i = 0; i < ret.seq_len; i++) {
switch(ret.seq[i]) {
case 'A':
seq[i] = 0;
break;
case 'C':
seq[i] = 1;
break;
case 'G':
seq[i] = 2;
break;
case 'T':
seq[i] = 3;
break;
}
}
ret.temp_len = 950 - 600 + 1; // Max Temp, Min Temp, incl. last
ret.temp = (double *) malloc(sizeof(double) * ret.temp_len);
if ((ret.seq == NULL) || (ret.temp == NULL)) {
ret.error = 1;
amp_free_all(alloc_box, alloc_count);
return ret;
}
for (i = 0; i < ret.temp_len; i++) {
ret.temp[i] = (600.0 + i) / 10; // Min Temp
}
double *t = ret.temp;
double *rans = NULL;
if (output == 0) {
// list element for each temperature * sequence position
ret.pos_prob = (double *) malloc(sizeof(double) * ret.temp_len * ret.seq_len);
if (ret.pos_prob == NULL) {
ret.error = 1;
amp_free_all(alloc_box, alloc_count);
return ret;
}
amp_zero_double(ret.pos_prob, ret.temp_len * ret.seq_len);
rans = ret.pos_prob;
} else {
// list element for each temperature
ret.melt = (double *) malloc(sizeof(double) * ret.temp_len);
ret.deriv = (double *) malloc(sizeof(double) * ret.temp_len);
if ((ret.melt == NULL) || (ret.deriv == NULL)) {
ret.error = 1;
amp_free_all(alloc_box, alloc_count);
return ret;
}
amp_zero_double(ret.melt, ret.temp_len);
amp_zero_double(ret.deriv, ret.temp_len);
rans = ret.melt;
}
// constants
double alpha = 2.15; // Blossey & Carlon, 2003
double sigma = 1.26e-4; // Blossey & Carlon, 2003
double Beta = 1e-7; // between 10^-6 and 10^-8
double rescale_G = 1e1; // rescaling threshold
double rescale_F = 1e-1; // rescaling factor
double rF1 = 1e1;
// [A C G T]
// [0 1 2 3]
double dH[4][4];
double dHini[4];
double dH_010[4];
double dS[4][4];
double dSini[4];
double dS_010[4];
if (tm_parameters == breslauer_amp) {
// NN parameters (Breslauer, 1986)
dH[0][0] = -9.1; // AA
dH[0][1] = -6.5; // AC
dH[0][2] = -7.8; // AG
dH[0][3] = -8.6; // AT
dH[1][0] = -5.8; // CA
dH[1][1] = -11.0; // CC
dH[1][2] = -11.9; // CG
dH[1][3] = -7.8; // CT
dH[2][0] = -5.6; // GA
dH[2][1] = -11.1; // GC
dH[2][2] = -11.0; // GG
dH[2][3] = -6.5; // GT
dH[3][0] = -6.0; // TA
dH[3][1] = -5.6; // TC
dH[3][2] = -5.8; // TG
dH[3][3] = -9.1; // TT
dHini[0] = 2.3; // A
dHini[1] = 0.1; // C
dHini[2] = 0.1; // G
dHini[3] = 2.3; // T
dH_010[0] = -4.54; // A
dH_010[1] = -4.54; // C
dH_010[2] = -4.54; // G
dH_010[3] = -4.54; // T
dS[0][0] = -24.0; // AA
dS[0][1] = -17.3; // AC
dS[0][2] = -20.8; // AG
dS[0][3] = -23.9; // AT
dS[1][0] = -12.9; // CA
dS[1][1] = -26.6; // CC
dS[1][2] = -27.8; // CG
dS[1][3] = -20.8; // CT
dS[2][0] = -13.5; // GA
dS[2][1] = -26.7; // GC
dS[2][2] = -26.6; // GG
dS[2][3] = -17.3; // GT
dS[3][0] = -16.9; // TA
dS[3][1] = -13.5; // TC
dS[3][2] = -12.9; // TG
dS[3][3] = -24.0; // TT
dSini[0] = 4.1; // A
dSini[1] = -2.8; // C
dSini[2] = -2.8; // G
dSini[3] = 4.1; // T
dS_010[0] = -20.2; // A
dS_010[1] = -20.2; // C
dS_010[2] = -20.2; // G
dS_010[3] = -20.2; // T
} else { // default santalucia_auto */
// Unified NN parameters (SantaLucia, 1998)
dH[0][0] = -7.9; // AA
dH[0][1] = -8.4; // AC
dH[0][2] = -7.8; // AG
dH[0][3] = -7.2; // AT
dH[1][0] = -8.5; // CA
dH[1][1] = -8.0; // CC
dH[1][2] = -10.6; // CG
dH[1][3] = -7.8; // CT
dH[2][0] = -8.2; // GA
dH[2][1] = -9.8; // GC
dH[2][2] = -8.0; // GG
dH[2][3] = -8.4; // GT
dH[3][0] = -7.2; // TA
dH[3][1] = -8.2; // TC
dH[3][2] = -8.5; // TG
dH[3][3] = -7.9; // TT
dHini[0] = 2.3; // A
dHini[1] = 0.1; // C
dHini[2] = 0.1; // G
dHini[3] = 2.3; // T
dH_010[0] = -4.54; // A
dH_010[1] = -4.54; // C
dH_010[2] = -4.54; // G
dH_010[3] = -4.54; // T
dS[0][0] = -22.2; // AA
dS[0][1] = -22.4; // AC
dS[0][2] = -21.0; // AG
dS[0][3] = -20.4; // AT
dS[1][0] = -22.7; // CA
dS[1][1] = -19.9; // CC
dS[1][2] = -27.2; // CG
dS[1][3] = -21.0; // CT
dS[2][0] = -22.2; // GA
dS[2][1] = -24.4; // GC
dS[2][2] = -19.9; // GG
dS[2][3] = -22.4; // GT
dS[3][0] = -21.3; // TA
dS[3][1] = -22.2; // TC
dS[3][2] = -22.7; // TG
dS[3][3] = -22.2; // TT
dSini[0] = 4.1; // A
dSini[1] = -2.8; // C
dSini[2] = -2.8; // G
dSini[3] = 4.1; // T
dS_010[0] = -20.2; // A
dS_010[1] = -20.2; // C
dS_010[2] = -20.2; // G
dS_010[3] = -20.2; // T
}
if (salt_corrections != owczarzy_amps) {
if ((dv > 0.0) && (dntp >= 0.0) && (dv > dntp)) {
mv += sqrt(dv - dntp) * 3.795;
}
}
double RT, s_11[4][4], s_end[4], s_010[4], Q_tot;
double avg;
double LEP = pow(5, -alpha);
double ratio = pow(7, -alpha)/LEP;
int rescale_i, seq_length, exp1;
seq_length = ret.seq_len;
// variables for interpolating plateaus when output!=0
double slope;
int *stack = (int *) amp_malloc(alloc_box, &alloc_count, sizeof(int) * ret.temp_len);
amp_zero_int(stack, ret.temp_len);
double *V_10_LR = (double *) amp_malloc(alloc_box, &alloc_count, sizeof(double) * (seq_length + 1));
double *U_01_LR = (double *) amp_malloc(alloc_box, &alloc_count, sizeof(double) * seq_length);
double *U_11_LR = (double *) amp_malloc(alloc_box, &alloc_count, sizeof(double) * seq_length);
int *rescale = (int *) amp_malloc(alloc_box, &alloc_count, sizeof(int) * seq_length);
double *V_10_RL = (double *) amp_malloc(alloc_box, &alloc_count, sizeof(double) * (seq_length + 1));
double *U_01_RL = (double *) amp_malloc(alloc_box, &alloc_count, sizeof(double) * seq_length);
double *U_11_RL = (double *) amp_malloc(alloc_box, &alloc_count, sizeof(double) * seq_length);
if (stack == NULL || V_10_LR == NULL || U_01_LR == NULL || U_11_LR == NULL ||
rescale == NULL || V_10_RL == NULL || U_01_RL == NULL || U_11_RL == NULL) {
ret.error = 1;
amp_free_all(alloc_box, alloc_count);
return ret;
}
int pos = 2, k = 0, it = 0;
while (pos > 1) { // each temperature
if (output==0) {
if (k == ret.temp_len)
break;
} else { // stack-based iteration
if (it < 2) { // initialize values
if (it!=0) { // second temp
if (ret.temp_len ==1 ) // only one temp
break;
k = ret.temp_len - 1; // last temp
}
it++;
} else {
if (it==2) {
if (ret.temp_len == 2) // only two temps
break;
// initialize values
stack[0] = 0;
stack[1] = ret.temp_len - 1;
it++;
}
stack[pos] = (stack[pos - 1] - stack[0])/2 + stack[0];
if (stack[pos]==stack[0]) {
stack[0] = stack[pos - 1];
pos = pos - 1;
continue;
}
k = stack[pos];
}
}
if (salt_corrections == schildkraut_amps) {
schildkraut_corr = 16.6 * log10(mv);
mv = 1.0;
}
RT = 1.9871*(273.15 + ret.dmso * ret.dmso_fact - schildkraut_corr
- (0.453 * ret.seq_gc / 100.0 - 2.88) * ret.formamid
+ t[k]);
// statistical weights
for (i = 0; i < 4; i++) {
for (j = 0; j < 4; j++) {
// statistical weight = exp(-dG/RT)
s_11[i][j] = exp((-1000*dH[i][j] +
(273.15 + ret.dmso * ret.dmso_fact - schildkraut_corr
- (0.453 * ret.seq_gc / 100.0 - 2.88) * ret.formamid + t[k])
* (dS[i][j] + 0.368*log(mv))) / RT);
}
}
for (i = 0; i < 4; i++) {
s_end[i] = exp((-1000*dHini[i] +
(273.15 + ret.dmso * ret.dmso_fact - schildkraut_corr
- (0.453 * ret.seq_gc / 100.0 - 2.88) * ret.formamid + t[k])
* (dSini[i] + 0.368*log(mv))) / RT);
s_010[i] = exp((-1000*dH_010[i] +
(273.15 + ret.dmso * ret.dmso_fact - schildkraut_corr
- (0.453 * ret.seq_gc / 100.0 - 2.88) * ret.formamid + t[k])
* (dS_010[i] + 0.368*log(mv))) / RT);
}
// initialize to zero
amp_zero_double(V_10_LR, seq_length + 1);
amp_zero_double(U_01_LR, seq_length);
amp_zero_double(U_11_LR, seq_length);
amp_zero_int(rescale, seq_length);
// initialize according to Tostesen (2003)
rescale_i = 0; // current rescaling exponent
V_10_LR[0] = 1;
V_10_LR[1] = Beta*s_010[seq[0]];
U_01_LR[1] = Beta;
U_11_LR[1] = Beta*s_end[seq[0]]*s_11[seq[0]][seq[1]];
V_10_LR[2] = s_010[seq[1]]*U_01_LR[1] + s_end[seq[1]]*U_11_LR[1];
Q_tot = V_10_LR[0] + V_10_LR[1] + V_10_LR[2];
// recursive loop according to Tostesen (2003)
for (i = 2; i < seq_length; i++) {
U_01_LR[i] = Beta*V_10_LR[0];
// loop entropy = SUM(sigma*(N + stiffness)^-alpha)
if (i > 2)
U_01_LR[i] += ratio*(U_01_LR[i - 1] - U_01_LR[i]);
exp1 = rescale_i - rescale[i - 2];
switch (exp1) {
case 0:
U_01_LR[i] += V_10_LR[i - 1]*sigma*LEP;
break;
case -1:
U_01_LR[i] += V_10_LR[i - 1]*rF1*sigma*LEP;
break;
default:
U_01_LR[i] += V_10_LR[i - 1]*pow(rescale_F, exp1)*sigma*LEP;
break;
}
U_11_LR[i] = s_11[seq[i - 1]][seq[i]]*(U_01_LR[i - 1]*s_end[seq[i - 1]] + U_11_LR[i - 1]);
V_10_LR[i + 1] = s_010[seq[i]]*U_01_LR[i] + s_end[seq[i]]*U_11_LR[i];
Q_tot += V_10_LR[i + 1];
// if the numbers are getting too large
// then rescale current elements
if (Q_tot > rescale_G && i < seq_length - 3) {
rescale_i++;
rescale[i] = rescale_i;
Q_tot *= rescale_F;
V_10_LR[i + 1] *= rescale_F;
U_01_LR[i] *= rescale_F;
U_11_LR[i] *= rescale_F;
V_10_LR[0] *= rescale_F;
} else {
rescale[i] = rescale_i;
}
}
// repeat the recursion from right-to-left
// NOTE: sequence complementation is unnecessary
// initialize to zero
amp_zero_double(V_10_RL, seq_length + 1);
amp_zero_double(U_01_RL, seq_length);
amp_zero_double(U_11_RL, seq_length);
// initialize according to Tostesen (2003)
V_10_RL[0] = 1;
V_10_RL[1] = Beta*s_010[seq[seq_length - 1]];
U_01_RL[1] = Beta;
U_11_RL[1] = Beta*s_end[seq[seq_length - 1]]*s_11[seq[seq_length - 2]][seq[seq_length - 1]];
V_10_RL[2] = s_010[seq[seq_length - 2]]*U_01_RL[1] + s_end[seq[seq_length - 2]]*U_11_RL[1];
// NOTE: Q_tot is only calculated one direction
// recursive loop according to Tostesen (2003)
for (i = 2; i < seq_length; i++) {
U_01_RL[i] = Beta*V_10_RL[0];
// loop entropy = SUM(sigma*(N + stiffness)^-alpha)
if (i > 2)
U_01_RL[i] += ratio*(U_01_RL[i - 1] - U_01_RL[i]);
exp1 = rescale[seq_length - i - 1] - rescale[seq_length - i];
switch (exp1) {
case 0:
U_01_RL[i] += V_10_RL[i - 1]*sigma*LEP;
break;
case -1:
U_01_RL[i] += V_10_RL[i - 1]*rF1*sigma*LEP;
break;
default:
U_01_RL[i] += V_10_RL[i - 1]*pow(rescale_F, exp1)*sigma*LEP;
break;
}
U_11_RL[i] = s_11[seq[seq_length - i - 1]][seq[seq_length - i]]*(U_01_RL[i - 1]*s_end[seq[seq_length - i]] + U_11_RL[i - 1]);
V_10_RL[i + 1] = s_010[seq[seq_length - i - 1]]*U_01_RL[i] + s_end[seq[seq_length - i - 1]]*U_11_RL[i];
// rescale at the opposite indicies as LR
if (rescale[seq_length - i - 1]!=rescale[seq_length - i]) {
V_10_RL[i + 1] *= rescale_F;
U_01_RL[i] *= rescale_F;
U_11_RL[i] *= rescale_F;
V_10_RL[0] *= rescale_F;
}
}
// return ret;
// calculate p(i) = closed
// (Tostesen, 2003) Eq. 11
if (output==0) {
for (i = 1; i < seq_length - 1; i++) {
*(rans + k + i*ret.temp_len) = (U_01_LR[i]*s_010[seq[i]]*U_01_RL[seq_length - i - 1] + U_01_LR[i]*s_end[seq[i]]*U_11_RL[seq_length - i - 1] + U_11_LR[i]*s_end[seq[i]]*U_01_RL[seq_length - i - 1] + U_11_LR[i]*U_11_RL[seq_length - i - 1])/(Beta*Q_tot);
// there is a minor approximation error LR vs. RL
// which sometimes results in p(i) slightly > 1
if (*(rans + k + i*ret.temp_len) > 1)
*(rans + k + i*ret.temp_len) = 1;
}
*(rans + k) = V_10_RL[seq_length]/Q_tot;
if (*(rans + k) > 1)
*(rans + k) = 1;
*(rans + k + (seq_length - 1)*ret.temp_len) = V_10_LR[seq_length]/Q_tot;
if (*(rans + k + (seq_length - 1)*ret.temp_len) > 1)
*(rans + k + (seq_length - 1)*ret.temp_len) = 1;
k++;
} else {
for (i = 1; i < seq_length - 1; i++) {
avg = (U_01_LR[i]*s_010[seq[i]]*U_01_RL[seq_length - i - 1] + U_01_LR[i]*s_end[seq[i]]*U_11_RL[seq_length - i - 1] + U_11_LR[i]*s_end[seq[i]]*U_01_RL[seq_length - i - 1] + U_11_LR[i]*U_11_RL[seq_length - i - 1])/(Beta*Q_tot);
// there is a minor approximation error LR vs. RL
// which sometimes results in p(i) slightly > 1
if (avg > 1) {
*(rans + k) += 1;
} else {
*(rans + k) += avg;
}
}
avg = V_10_RL[seq_length]/Q_tot;
if (avg > 1) {
*(rans + k) += 1;
} else {
*(rans + k) += avg;
}
avg = V_10_LR[seq_length]/Q_tot;
if (avg > 1) {
*(rans + k) += 1;
} else {
*(rans + k) += avg;
}
*(rans + k) /= seq_length; // average helicity
if (it > 2) {
// calculate slope
slope = (*(rans + stack[0]) - *(rans + stack[pos]))/(t[stack[0]] - t[stack[pos]]);
if (-1*slope < 1e-3) { // linearly interpolate points
for (i = stack[0] + 1; i < stack[pos]; i++)
*(rans + i) = slope*(t[i] - t[stack[0]]) + *(rans + stack[0]);
stack[0] = stack[pos];
stack[0] = stack[pos];
while ((stack[pos - 1] + 1L)==stack[pos]) {
stack[0] = stack[pos - 1];
pos--;
}
} else {
pos++; // iterate
}
}
}
}
if (output!=0) {
// negative derivative
// cubic spline interpolation
double a_11, a_12, a_22, a_23, a_33;
double b_1, b_2, b_3;
double k1, temp;
for (k = 1; k < ret.temp_len - 1; k++) {
a_12 = 1/(t[k] - t[k - 1]);
a_11 = 2*a_12;
a_23 = 1/(t[k + 1] - t[k]);
a_22 = 2*(a_12 + a_23);
a_33 = 2*a_23;
b_1 = 3*(*(rans + k) - *(rans + k - 1))/((t[k] - t[k - 1])*(t[k] - t[k - 1]));
b_3 = 3*(*(rans + k + 1) - *(rans + k))/((t[k + 1] - t[k])*(t[k + 1] - t[k]));
b_2 = b_1 + b_3;
k1 = (a_33*(a_11*b_2 - a_12*b_1) - b_3*a_23*a_11)/(a_33*(a_11*a_22 - a_12*a_12) - a_23*a_11*a_23);
if (k==1) {
*(ret.deriv + k - 1) = -1*(b_1 - a_12*k1)/a_11; // -k0
} else {
*(ret.deriv + k - 1) = -1*temp; // previous -k1
}
if (k==(ret.temp_len - 2)) {
*(ret.deriv + k) = -1*k1; // current -k1
*(ret.deriv + k + 1) = -1*(b_3 - a_23*k1)/a_33; // -k2
if (*(ret.deriv + k + 1) < 0) // sometimes k2 is positive
*(ret.deriv + k + 1) = 0;
}
temp = k1;
}
// Find the peaks
last_min = *ret.deriv;
for (k = ret.temp_len - 2; k > 0; k--) {
if ((*(ret.deriv + k) - *(ret.deriv + k - 1) < 0.0000000001) &&
(*(ret.deriv + k) - *(ret.deriv + k + 1) < 0.0000000001)) {
last_min = *(ret.deriv + k);
}
if ((*(ret.deriv + k) - *(ret.deriv + k - 1) > 0.0000000001) &&
(*(ret.deriv + k) - *(ret.deriv + k + 1) > 0.0000000001) &&
(*(ret.deriv + k) - last_min > 0.001)) {
if (ret.melt_len < 10) {
ret.melt_points[ret.melt_len] = *(t + k);
ret.melt_len++;
}
}
}
}
amp_free_all(alloc_box, alloc_count);
return ret;
}
amplicon_result ampliconfindsalt(const char *inseq,
double fs_temp,
double dmso,
double dmso_fact,
double formamid,
amp_tm_parameters_type tm_parameters,
amp_salt_correction_type salt_corrections,
amp_tm_method_type tm_formula,
int output) {
int i = 0;
int cont = 1;
double mv = 10.0;
double mv_min = 10.0;
double mv_max = 10.0;
double step = 10.0;
amplicon_result ret;
fs_temp = ((int) (fs_temp * 10.0 + 0.5)) / 10.0;
while ((cont == 1) && (i < 100)) {
i++;
ret = amplicontm(inseq, mv, 0.0, 0.0, dmso, dmso_fact, formamid,
tm_parameters, salt_corrections, tm_formula, 1);
if (ret.error > 0) {
free_amplicon_result(&ret);
return ret;
}
if (ret.melt_len == 0) {
ret.error = 3;
free_amplicon_result(&ret);
return ret;
}
if (fabs(ret.melt_points[0] - fs_temp) < 0.01) {
break;
}
if (ret.melt_points[0] < fs_temp) {
mv += step;
} else {
mv -= step;
step /= 10.0;
if (step < 0.5) {
break;
}
}
free_amplicon_result(&ret);
}
mv_min = mv;
while (mv_min > 10) {
mv_min -= 1.0;
ret = amplicontm(inseq, mv_min, 0.0, 0.0, dmso, dmso_fact, formamid,
tm_parameters, salt_corrections, tm_formula, 1);
if (ret.error > 0) {
free_amplicon_result(&ret);
return ret;
}
if (ret.melt_len == 0) {
ret.error = 3;
free_amplicon_result(&ret);
return ret;
}
if (fabs(ret.melt_points[0] - fs_temp) > 0.01) {
mv_min += 1.0;
break;
}
free_amplicon_result(&ret);
}
mv_max = mv;
while (mv_max < 1000) {
mv_max += 1.0;
ret = amplicontm(inseq, mv_max, 0.0, 0.0, dmso, dmso_fact, formamid,
tm_parameters, salt_corrections, tm_formula, 1);
if (ret.error > 0) {
free_amplicon_result(&ret);
return ret;
}
if (ret.melt_len == 0) {
ret.error = 3;
free_amplicon_result(&ret);
return ret;
}
if (fabs(ret.melt_points[0] - fs_temp) > 0.01) {
mv_max -= 1.0;
break;
}
free_amplicon_result(&ret);
}
mv = (mv_max + mv_min) / 2.0;
return amplicontm(inseq, mv, 0.0, 0.0, dmso, dmso_fact, formamid,
tm_parameters, salt_corrections, tm_formula, output);
}
primer3-py-2.3.1/primer3/src/libprimer3/amplicontm.h 0000664 0000000 0000000 00000017427 15247271707 0022307 0 ustar 00root root 0000000 0000000 /*
Amplicon3 calculates melting temperatures for amplicons.
Copyright (c) 2021 Andreas Untergasser
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
----------------------------------------------------------------
Amplicon3 is based on MeltPolymer.c from the DECIPHER package
created by Erik Wright. DECIPHER is GPL-3 licensed.
*/
#ifndef _AMPLICON_TM
#define _AMPLICON_TM 1
#ifdef __cplusplus
extern "C" {
#endif
/* error codes: 0 - no errors
1 - out of memory
*/
typedef struct amplicon_result {
int error; /* See description above. */
double mv; /* Salt concentration (millimolar). */
double dv; /* Concentration of divalent cations (millimolar) */
double dntp; /* Concentration of dNTPs (millimolar) */
double dmso; /* Concentration of DMSO (%) */
double dmso_fact; /* DMSO correction factor (default 0.6) */
double formamid; /* Concentration of formamid (millimolar) */
int seq_len; /* Length of the sequence. */
char *seq; /* Sequence with ATCG only and in upper case. */
double seq_gc; /* GC content of the sequence in % . */
int temp_len; /* Number of temperatures. */
double *temp; /* The list of temperatures. */
double *pos_prob; /* The table of positional probabilities [temp_len][seq_len]. */
double *melt; /* The melt curve as list [temp_len]. */
double *deriv; /* The derivative of the melt curve as list [temp_len]. */
int melt_len; /* Number of melting points found. */
double melt_points[10]; /* The list of temperatures. */
} amplicon_result;
void free_amplicon_result(amplicon_result *res);
void amp_init_all(void **alloc_box, int max_count);
void *amp_malloc(void **alloc_box, int *alloc_count, size_t size);
void amp_free_all(void **alloc_box, int alloc_count);
void amp_zero_int(int *arr, int element_count);
void amp_zero_double(double *arr, int element_count);
typedef enum amp_tm_parameters_type {
breslauer_amp = 0,
santalucia_amp = 1,
} amp_tm_parameters_type;
typedef enum amp_salt_correction_type {
schildkraut_amps = 0,
santalucia_amps = 1,
owczarzy_amps = 2,
} amp_salt_correction_type;
/*
If tm_parameters==santalucia_amp, then the table of
nearest-neighbor thermodynamic parameters and method for Tm
calculation in the paper [SantaLucia JR (1998) "A unified view of
polymer, dumbbell and oligonucleotide DNA nearest-neighbor
thermodynamics", Proc Natl Acad Sci 95:1460-65
http://dx.doi.org/10.1073/pnas.95.4.1460] is used.
*THIS IS THE RECOMMENDED VALUE*.
If tm_parameters==breslauer_amp, then method for Tm
calculations in the paper [Rychlik W, Spencer WJ and Rhoads RE
(1990) "Optimization of the annealing temperature for DNA
amplification in vitro", Nucleic Acids Res 18:6409-12
http://www.pubmedcentral.nih.gov/articlerender.fcgi?tool=pubmed&pubmedid=2243783].
and the thermodynamic parameters in the paper [Breslauer KJ, Frank
R, Bl?cker H and Marky LA (1986) "Predicting DNA duplex stability
from the base sequence" Proc Natl Acad Sci 83:4746-50
http://dx.doi.org/10.1073/pnas.83.11.3746], are is used. This is
the method and the table that primer3 used up to and including
version 1.0.1
If salt_corrections==schildkraut_amp, then formula for
salt correction in the paper [Schildkraut, C, and Lifson, S (1965)
"Dependence of the melting temperature of DNA on salt
concentration", Biopolymers 3:195-208 (not available on-line)] is
used. This is the formula that primer3 used up to and including
version 1.0.1.
If salt_corrections==santalucia_amp, then formula for
salt correction suggested by the paper [SantaLucia JR (1998) "A
unified view of polymer, dumbbell and oligonucleotide DNA
nearest-neighbor thermodynamics", Proc Natl Acad Sci 95:1460-65
http://dx.doi.org/10.1073/pnas.95.4.1460] is used.
*THIS IS THE RECOMMENDED VALUE*.
The salt_corrections==owczarzy_amp, according to formula for
salt correction in the paper [Owczarzy, R., Moreira, B.G., You, Y.,
Behlke, M.A., and Walder, J.A. (2008) "Predicting stability of DNA
duplexes in solutions containing magnesium and monovalent cations",
Biochemistry 47:5336-53 http://dx.doi.org/10.1021/bi702363u] is not
supported.
*/
typedef enum amp_tm_method_type {
bolton_amp = 0,
wright_amp = 1,
} amp_tm_method_type;
/*
If tm_parameters==bolton_amp, then the the formula from Bolton and McCarthy,
PNAS 84:1390 (1962) as presented in Sambrook, Fritsch and Maniatis,
Molecular Cloning, p 11.46 (1989, CSHL Press).
Tm = 81.5 + 16.6*(log10([Na+] + sqrt([Mg++])*3.795)) + 0.41*(%GC) - 600/length
Where [Na+] is the molar sodium concentration, [Mg++] is the molar
magnesium concentration, (%GC) is the percent of Gs and Cs in the
sequence, and length is the length of the sequence. Be aware that
the tm_parameters and salt_corrections are ignored using this
formula.
If tm_parameters==wright_amp, then the the formula from Wright and
Vetsigian (2016) "DesignSignatures: a tool for designing primers
that yields amplicons with distinct signatures.", Bioinformatics,
32:1565-7 http://doi.org/10.1093/bioinformatics/btw047 is used.
*THIS IS THE RECOMMENDED VALUE*.
*/
amplicon_result amplicontm(const char *inseq, /* The sequence. */
double monovalent_conc, /* Salt concentration (millimolar). */
double divalent_conc, /* Concentration of divalent cations (millimolar) */
double dntp_conc, /* Concentration of dNTPs (millimolar) */
double dmso, /* Concentration of DMSO (%) */
double dmso_fact, /* DMSO correction factor (default 0.6) */
double formamid, /* Concentration of formamid (millimolar) */
amp_tm_parameters_type tm_parameters, /* See description above. */
amp_salt_correction_type salt_corrections, /* See description above. */
amp_tm_method_type tm_formula, /* See description above. */
int output /* 0 calc positional probabilities, 1 calc values, 2 calc 1 + curves */
);
amplicon_result ampliconfindsalt(const char *inseq, /* The sequence. */
double fs_temp, /* Desired melting temperature. */
double dmso, /* Concentration of DMSO (%) */
double dmso_fact, /* DMSO correction factor (default 0.6) */
double formamid, /* Concentration of formamid (millimolar) */
amp_tm_parameters_type tm_parameters, /* See description above. */
amp_salt_correction_type salt_corrections, /* See description above. */
amp_tm_method_type tm_formula, /* See description above. */
int output /* See description above. */
);
#ifdef __cplusplus
}
#endif
#endif
primer3-py-2.3.1/primer3/src/libprimer3/amplicontm_main.c 0000664 0000000 0000000 00000034677 15247271707 0023314 0 ustar 00root root 0000000 0000000 /*
Amplicon3 calculates melting temperatures for amplicons.
Copyright (c) 2021 Andreas Untergasser
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
a
----------------------------------------------------------------
Amplicon3 is based on MeltPolymer.c from the DECIPHER package
created by Erik Wright. DECIPHER is GPL-3 licensed.
*/
#include
#include
#include
#include
#include "amplicontm.h"
/* Print the melting temperature of an amplicon on stdout. */
/* This program provides a command line interface to
the function amplicontm() in amplicontm.c
*/
int
main(int argc, char **argv)
{
amplicon_result ret;
const char *msg = "USAGE: %s OPTIONS oligo\n"
"\n"
"where amplicon is a DNA sequence of > 36 bases\n"
"\n"
"and\n"
"\n"
"OPTIONS can include any of the the following:\n"
"\n"
"-mv monovalent_conc - concentration of monovalent cations in mM, by default 50mM\n"
"\n"
"-dv divalent_conc - concentration of divalent cations in mM, by default 1.5mM\n"
"\n"
"-n dNTP_conc - concentration of deoxynycleotide triphosphate in mM, by default 0.6mM\n"
"\n"
"-dmso dmso_conc - concentration of DMSO in percent, by default 0%\n"
"\n"
"-dmso_fact dmso_fact - DMSO correction factor, by default 0.6\n"
"\n"
"-formamid formamid_conc - concentration of formamid in mM, by default 0\n"
"\n"
"-fs find_salt_conc - provide a measured Tm and obtain a suitable salt concentration (experimental)\n"
"\n"
"-tp [0|1] - Specifies the table of thermodynamic parameters and\n"
" the method of melting temperature calculation:\n"
" 0 Breslauer et al., 1986 and Rychlik et al., 1990\n"
" (used by primer3 up to and including release 1.1.0).\n"
" 1 Use nearest neighbor parameters from SantaLucia 1998\n"
" *This is the default and recommended value*\n"
"\n"
"-sc [0..2] - Specifies salt correction formula for the melting \n"
" temperature calculation\n"
" 0 Schildkraut and Lifson 1965, used by primer3 up to \n"
" and including release 1.1.0.\n"
" 1 SantaLucia 1998\n"
" *This is the default and recommended value*\n"
" 2 Owczarzy et al., 2004\n"
"\n"
"-mf [0..1] - Specifies the formula for the melting temperature\n"
" calculation\n"
" 0 Bolton and McCarthy 1962, used by primer3 up to \n"
" and including release 2.4.2.\n"
" 1 Wright and Vetsigian 2016\n"
" *This is the default and recommended value*\n"
"\n"
"-o [0..2] - Specifies the output format on stdout\n"
" 0 A table of helicities.\n"
" 1 A short list of the calculated parameters \n"
" *This is the default*\n"
" 2 A long list of the calculated parameters including \n"
" the melting curve and the derivative curve \n"
"\n";
const char *copyright =
" Amplicon3 calculates melting temperatures for amplicons.\n"
" Copyright (c) 2021 Andreas Untergasser\n"
"\n"
" This program is free software: you can redistribute it and/or modify\n"
" it under the terms of the GNU General Public License as published by\n"
" the Free Software Foundation, either version 3 of the License, or\n"
" (at your option) any later version.\n"
"\n"
" This program is distributed in the hope that it will be useful,\n"
" but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
" GNU General Public License for more details.\n"
"\n"
" You should have received a copy of the GNU General Public License\n"
" along with this program. If not, see .\n"
"\n"
" ----------------------------------------------------------------\n"
"\n"
" Amplicon3 is based on MeltPolymer.c from the DECIPHER package\n"
" created by Erik Wright. DECIPHER is GPL-3 licensed.\n"
"\n";
char *endptr, *seq;
double mv = 50.0, dv = 1.5, dntp = 0.6, fs_temp = -10.0;
double dmso = 0.0, dmso_fact = 0.6, formamid = 0.0;
int tm_parameters=1, salt_corrections=1, tm_formula=1, output=1;
int i, j, k;
if (argc < 2 || argc > 24) {
fprintf(stderr, msg, argv[0]);
fprintf(stderr, "%s", copyright);
return -1;
}
for (i=1; i < argc; ++i) {
if (!strncmp("-mv", argv[i], 3)) { /* conc of monovalent cations */
if (i+1 >= argc) {
/* Missing value */
fprintf(stderr, msg, argv[0]);
exit(-1);
}
mv = strtod(argv[i+1], &endptr);
if ('\0' != *endptr) {
fprintf(stderr, msg, argv[0]);
exit(-1);
}
i++;
} else if (!strncmp("-dv", argv[i], 3)) { /* conc of divalent cations */
if (i+1 >= argc) {
/* Missing value */
fprintf(stderr, msg, argv[0]);
exit(-1);
}
dv = strtod(argv[i+1], &endptr);
if('\0' != *endptr) {
fprintf(stderr, msg, argv[0]);
exit(-1);
}
i++;
} else if (!strncmp("-n", argv[i], 3)) { /* conc of dNTP */
if (i+1 >= argc) {
/* Missing value */
fprintf(stderr, msg, argv[0]);
exit(-1);
}
dntp = strtod(argv[i+1], &endptr);
if('\0' != *endptr) {
fprintf(stderr, msg, argv[0]);
exit(-1);
}
i++;
} else if (!strncmp("-dmso", argv[i], 5)) { /* primer3-py bug-fix block need to parse 5 characters instead of 3 concentration of DMSO */
if (i+1 >= argc) {
/* Missing value */
fprintf(stderr, msg, argv[0]);
exit(-1);
}
dmso = strtod(argv[i+1], &endptr);
if('\0' != *endptr) {
fprintf(stderr, msg, argv[0]);
exit(-1);
}
i++;
} else if (!strncmp("-dmso_fact", argv[i], 10)) { /* primer3-py bug-fix block need to parse 10 characters instead of 3 DMSO correction factor */
if (i+1 >= argc) {
/* Missing value */
fprintf(stderr, msg, argv[0]);
exit(-1);
}
dmso_fact = strtod(argv[i+1], &endptr);
if('\0' != *endptr) {
fprintf(stderr, msg, argv[0]);
exit(-1);
}
i++;
} else if (!strncmp("-formamid", argv[i], 9)) { /* primer3-py bug-fix block need to parse 9 characters instead of 3 concentration of formamid */
if (i+1 >= argc) {
/* Missing value */
fprintf(stderr, msg, argv[0]);
exit(-1);
}
formamid = strtod(argv[i+1], &endptr);
if('\0' != *endptr) {
fprintf(stderr, msg, argv[0]);
exit(-1);
}
i++;
} else if (!strncmp("-tp", argv[i], 3)) { /* parameters for melting temperature calculation */
if (i+1 >= argc) {
/* Missing value */
fprintf(stderr, msg, argv[0]);
exit(-1);
}
tm_parameters = (int)strtol(argv[i+1], &endptr, 10);
if ('\0' != *endptr || tm_parameters<0 || tm_parameters>1) {
fprintf(stderr, msg, argv[0]);
exit(-1);
}
i++;
} else if (!strncmp("-sc", argv[i], 3)) { /* method of salt correction */
if (i+1 >= argc) {
/* Missing value */
fprintf(stderr, msg, argv[0]);
exit(-1);
}
salt_corrections = (int)strtol(argv[i+1], &endptr, 10);
if ('\0' != *endptr || salt_corrections<0 || salt_corrections>2) {
fprintf(stderr, msg, argv[0]);
exit(-1);
}
i++;
} else if (!strncmp("-mf", argv[i], 3)) { /* formula for melting temperature calculation */
if (i+1 >= argc) {
/* Missing value */
fprintf(stderr, msg, argv[0]);
exit(-1);
}
tm_formula = (int)strtol(argv[i+1], &endptr, 10);
if ('\0' != *endptr || tm_formula<0 || tm_formula>1) {
fprintf(stderr, msg, argv[0]);
exit(-1);
}
i++;
} else if (!strncmp("-fs", argv[i], 3)) { /* find salt concentation */
if (i+1 >= argc) {
/* Missing value */
fprintf(stderr, msg, argv[0]);
exit(-1);
}
fs_temp = strtod(argv[i+1], &endptr);
if('\0' != *endptr) {
fprintf(stderr, msg, argv[0]);
exit(-1);
}
i++;
} else if (!strncmp("-o", argv[i], 3)) { /* output helicities table or list */
if (i+1 >= argc) {
/* Missing value */
fprintf(stderr, msg, argv[0]);
exit(-1);
}
output = (int)strtol(argv[i+1], &endptr, 10);
if ('\0' != *endptr || output<0 || output>2) {
fprintf(stderr, msg, argv[0]);
exit(-1);
}
i++;
} else if (!strncmp("-", argv[i], 1)) {
/* Unknown option. */
fprintf(stderr, msg, argv[0]);
exit(-1);
} else
break; /* all args processed. go on to sequences. */
}
if(!argv[i]) { /* if no oligonucleotide sequence is specified */
fprintf(stderr, msg, argv[0]);
exit(-1);
}
/* input sequence to uppercase */
seq = argv[i];
if (fs_temp < 0.0) {
ret = amplicontm(seq,
mv,
dv,
dntp,
dmso,
dmso_fact,
formamid,
(amp_tm_parameters_type) tm_parameters,
(amp_salt_correction_type) salt_corrections,
(amp_tm_method_type) tm_formula,
output);
} else {
ret = ampliconfindsalt(seq,
fs_temp,
dmso,
dmso_fact,
formamid,
(amp_tm_parameters_type) tm_parameters,
(amp_salt_correction_type) salt_corrections,
(amp_tm_method_type) tm_formula,
output);
}
if (ret.error == 1) {
fprintf(stderr, "%s ERROR: out of memory\n", argv[0]);
return -1;
} else if (ret.error == 2) {
fprintf(stderr, "%s ERROR: input is corrupted. Sodium equivalent concentration must be at least 0.01M.\n", argv[0]);
return -1;
} else if (ret.error == 3) {
fprintf(stderr, "%s ERROR: no melting temperature found.\n", argv[0]);
return -1;
} else if (ret.error == 4) {
fprintf(stderr, "%s ERROR: -sc 2 salt_corrections==owczarzy is not supported.\n", argv[0]);
return -1;
} else if (ret.error == 5) {
fprintf(stderr, "%s ERROR: -tp 0 breslauer parameters for melting temperature calculation are not supported.\n", argv[0]);
return -1;
} else if ((output != 1) && (tm_formula == 0)) {
fprintf(stderr, "%s ERROR: -mf 0 requires -o 1.\n", argv[0]);
return -1;
} else {
if (output == 0) {
printf("\t");
for (j = 0; j < ret.seq_len; j++) {
if (j == ret.seq_len - 1) {
printf("%d\n", j + 1);
} else {
printf("%d\t", j + 1);
}
}
printf("\t");
for (j = 0; j < ret.seq_len; j++) {
if (j == ret.seq_len - 1) {
printf("%c\n", ret.seq[j]);
} else {
printf("%c\t", ret.seq[j]);
}
}
for (j = 0; j < ret.temp_len; j++) {
printf("%.1f\t", ret.temp[j]);
for (k = 0; k < ret.seq_len; k++) {
if (k == ret.seq_len - 1) {
printf("%.6f\n", *(ret.pos_prob + j + k * ret.temp_len));
} else {
printf("%.6f\t", *(ret.pos_prob + j + k * ret.temp_len));
}
}
}
} else {
printf("AMPLICON_MONOVALENT=%.1f\n", ret.mv);
printf("AMPLICON_DIVALENT=%.1f\n", ret.dv);
printf("AMPLICON_DNTPS=%.1f\n", ret.dntp);
printf("AMPLICON_DMSO=%.1f\n", ret.dmso);
printf("AMPLICON_DMSO_CORRECTION=%.1f\n", ret.dmso_fact);
printf("AMPLICON_FORMAMID=%.1f\n", ret.formamid);
printf("AMPLICON_PRODUCT_SIZE=%d\n", ret.seq_len);
if (output == 2) {
printf("AMPLICON_SEQUENCE=%s\n", ret.seq);
}
printf("AMPLICON_GC_PERCENT=%.1f\n", ret.seq_gc);
printf("AMPLICON_MELTPOINTS=");
for (j = 0; j < ret.melt_len; j++) {
if (j == ret.melt_len - 1) {
printf("%.1f\n", ret.melt_points[j]);
} else {
printf("%.1f,", ret.melt_points[j]);
}
}
if (ret.melt_len == 0) {
printf("-10.0\n");
}
if (output == 2) {
printf("AMPLICON_TEMPERATURES=");
for (j = 0; j < ret.temp_len; j++) {
if (j == ret.temp_len - 1) {
printf("%.1f\n", ret.temp[j]);
} else {
printf("%.1f,", ret.temp[j]);
}
}
printf("AMPLICON_MELT_CURVE=");
for (j = 0; j < ret.temp_len; j++) {
if (j == ret.temp_len - 1) {
printf("%.6e\n", ret.melt[j]);
} else {
printf("%.6e,", ret.melt[j]);
}
}
printf("AMPLICON_DERIVATIVE_CURVE=");
for (j = 0; j < ret.temp_len; j++) {
if (j == ret.temp_len - 1) {
printf("%.6e\n", ret.deriv[j]);
} else {
printf("%.6e,", ret.deriv[j]);
}
}
}
}
}
free_amplicon_result(&ret);
return 0;
}
primer3-py-2.3.1/primer3/src/libprimer3/dpal.c 0000664 0000000 0000000 00000112342 15247271707 0021047 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 1996,1997,1998,1999,2000,2001,2004,2006,2007,2008
Whitehead Institute for Biomedical Research, Steve Rozen
(http://purl.com/STEVEROZEN/), Andreas Untergasser and Helen Skaletsky
All rights reserved.
This file is part of primer3 software suite.
This software suite is is free software;
you can redistribute it and/or modify it under the terms
of the GNU General Public License as published by the Free
Software Foundation; either version 2 of the License, or (at
your option) any later version.
This software is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this software (file gpl-2.0.txt in the source
distribution); if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include
#include
#include
#include
#include
#include "dpal.h"
/*
* We should probably remove the DPAL_FORGET_PATH compile-time option.
* Efficiency now derives primarily from specialized versions of _dpal* for
* particular parameter values.
*/
#ifndef DPAL_FORGET_PATH
/*
* Print an alignment on stderr, given the 2 aligned sequences, the "trace"
* matrix, and the coordinate of the end point of the alignment to print.
*/
static char *print_align(const unsigned char *, const unsigned char *,
int[DPAL_MAX_ALIGN][DPAL_MAX_ALIGN][3], int, int,
const dpal_args*, const dpal_mode mode, dpal_results *);
#endif
/*
* Return 1 if there is an illegal character in the first argument, and place
* the illegal character in the address contained in the last argument.
*/
static int illegal_char(const unsigned char *, const dpal_ssm, char *);
static const unsigned char *xlate_ambiguity_code(char);
/*
* The next function headers are for various versions of the
* dynamic-programming alignment code optimized for particular input argument
* values.
*/
static void _dpal_generic(const unsigned char *,
const unsigned char *,
const int,
const int,
const dpal_args *,
const dpal_mode mode,
dpal_results *);
static void _dpal_long_nopath_maxgap1_local_end(const unsigned char *,
const unsigned char *,
const int,
const int,
const dpal_args *,
dpal_results *);
static void _dpal_long_nopath_generic(const unsigned char *,
const unsigned char *,
const int,
const int,
const dpal_args *,
dpal_results *);
static void _dpal_long_nopath_maxgap1_local(const unsigned char *,
const unsigned char *,
const int,
const int,
const dpal_args *,
dpal_results *);
static void _dpal_long_nopath_maxgap1_global_end(const unsigned char *,
const unsigned char *,
const int,
const int,
const dpal_args *,
dpal_results *);
/* Set dpal args to appropriate values for primer picking. */
/* IMPORTANT -- if the scoring system changes, then
the value returned by align() for short target sequences
must be adjusted. */
void
set_dpal_args(dpal_args *a) {
unsigned int i, j;
memset(a, 0, sizeof(*a));
for (i = 0; i <= UCHAR_MAX; i++)
for (j = 0; j <= UCHAR_MAX; j++)
if (('A' == i || 'C' == i || 'G' == i || 'T' == i || 'N' == i)
&& ('A' == j || 'C' == j || 'G' == j || 'T' == j
|| 'N' == j)) {
if (i == 'N' || j == 'N')
a->ssm[i][j] = -25;
else if (i == j)
a->ssm[i][j] = 100;
else
a->ssm[i][j] = -100;
} else
a->ssm[i][j] = INT_MIN;
a->gap = -200;
a->gapl = -200;
a->flag = DPAL_LOCAL;
a->max_gap = 1;
a->fail_stop = 1;
a->check_chars = 0;
a->force_generic = 0;
a->force_long_generic = 0;
a->force_long_maxgap1 = 0;
}
void
dpal_set_default_nt_args(dpal_args *a) {
set_dpal_args(a);
a->check_chars = 1;
a->fail_stop = DPAL_EXIT_ON_ERROR;
a->gap = -100;
a->gapl = -100;
a->max_gap = 3;
}
void
dpal_set_h_nt_matrix(dpal_args *a) {
unsigned int i, j;
for (i = 0; i <= UCHAR_MAX; i++)
for (j = 0; j <= UCHAR_MAX; j++)
if (('A' == i || 'C' == i || 'G' == i || 'T' == i || 'N' == i)
&& ('A' == j || 'C' == j || 'G' == j || 'T' == j
|| 'N' == j)) {
if (i == 'N' || j == 'N')
a->ssm[i][j] = -50;
else if (i == j) {
if ('C' == i || 'G' == i)
a->ssm[i][j] = 300;
else
a->ssm[i][j] = 200;
}
else
a->ssm[i][j] = -50;
} else
a->ssm[i][j] = INT_MIN;
}
/* The argument a must be a DNA scoring matrix.
Modify a so that it for a match between
any two ambiguity codes (or between ambiguity code and base),
e.g. B and S, the score will be the maximum of
score between any base in B and any base in S,
in the example between any pair in {C, G, T} X {C, G}.
*/
int
dpal_set_ambiguity_code_matrix(dpal_args *a)
{
const unsigned char *c1, *c2;
const unsigned char *amb_codes = (unsigned char *) "BDHVRYKMSWN";
const unsigned char *all_bases = (unsigned char *) "ACGT";
const unsigned char *bases1, *bases2, *b1, *b2;
int extreme;
for (c1 = amb_codes; *c1; c1++) {
bases1 = xlate_ambiguity_code(*c1);
if (!bases1) return 0;
/* Do matches between c1 and all other
ambiguity codes. */
for (c2 = amb_codes; *c2; c2++) {
bases2 = xlate_ambiguity_code(*c2);
if (!bases2) return 0;
extreme = INT_MIN;
for (b1 = bases1; *b1; b1++) {
for (b2 = bases2; *b2; b2++) {
if (a->ssm[*b1][*b2] > extreme) {
extreme = a->ssm[*b1][*b2];
}
}
}
/* extreme is now the maximum score
for a match between any 2 bases
represented *c1, *c2. */
a->ssm[*c1][*c2] = extreme;
}
/* Do matches between c1 and all bases. */
for (b2 = all_bases; *b2; b2++) {
extreme = INT_MIN;
for (b1 = bases1; *b1; b1++) {
if (a->ssm[*b1][*b2] > extreme) {
extreme = a->ssm[*b1][*b2];
}
}
a->ssm[*c1][*b2] = extreme;
a->ssm[*b2][*c1] = extreme;
}
}
return 1;
}
static const unsigned char *
xlate_ambiguity_code(char c)
{
if ('N' == c) return (unsigned char *) "ACGT";
else if ('B' == c) return (unsigned char *) "CGT";
else if ('D' == c) return (unsigned char *) "AGT";
else if ('H' == c) return (unsigned char*) "ACT";
else if ('V' == c) return (unsigned char*) "ACG";
else if ('R' == c) return (unsigned char*) "AG";
else if ('Y' == c) return (unsigned char*) "CT";
else if ('K' == c) return (unsigned char*) "GT";
else if ('M' == c) return (unsigned char*) "AC";
else if ('S' == c) return (unsigned char*) "CG";
else if ('W' == c) return (unsigned char*) "AT";
else return NULL; /* Error condition */
}
/*
The next two macros require that the output argument is always
called 'out'.
*/
#define CHECK_ERROR(COND,MSG) if (COND) { out->msg = MSG; goto FAIL; }
/* If fail_stop is set, the code at FAIL: will use fprintf, otherwise
will return with msg set. */
#define DPAL_OOM_ERROR {out->msg = "Out of memory", errno=ENOMEM; goto FAIL; }
static void
fail_action(const dpal_args *in, dpal_results *out) {
if (in->fail_stop) {
fprintf(stderr, "\n%s\n", out->msg);
exit(-1);
}
out->score=DPAL_ERROR_SCORE;
}
void
dpal(const unsigned char *X,
const unsigned char *Y,
const dpal_args *in,
const dpal_mode mode,
dpal_results *out)
{
int xlen, ylen;
char msg[] = "Illegal character in input: ?";
out->score = DPAL_ERROR_SCORE;
out->path_length = 0;
out->msg = NULL;
out->sec_struct = NULL;
CHECK_ERROR(NULL == X, "NULL first sequence");
CHECK_ERROR(NULL == Y, "NULL second sequence");
CHECK_ERROR(NULL == in, "NULL 'in' pointer");
if (NULL == out) return; /* Leave it to the caller to
crash */
CHECK_ERROR(in->flag != DPAL_GLOBAL
&& in->flag != DPAL_GLOBAL_END
&& in->flag != DPAL_LOCAL_END
&& in->flag != DPAL_LOCAL,
"Illegal flag");
if (in->check_chars) {
CHECK_ERROR(illegal_char(X, in->ssm, &msg[28]), msg);
CHECK_ERROR(illegal_char(Y, in->ssm, &msg[28]), msg);
}
xlen = strlen((char *) X);
ylen = strlen((char *) Y);
out->align_end_1 = -1;
out->align_end_2 = -1;
if ('\0' == *X) {
out->msg = "Empty first sequence";
out->score = 0;
return;
}
if ('\0' == *Y) {
out->msg = "Empty second sequence";
out->score = 0;
return;
}
if (1 == in->force_generic || mode != 0 ) {
/*
* A true value of in->mode really means "print alignment on stderr"
* and implies 0 == a.score_only.
*/
CHECK_ERROR(xlen > DPAL_MAX_ALIGN,
"Sequence 1 longer than DPAL_MAX_ALIGN and alignment is requested");
CHECK_ERROR(ylen > DPAL_MAX_ALIGN,
"Sequence 2 longer than DPAL_MAX_ALIGN and alignment is requested");
_dpal_generic(X, Y, xlen, ylen, in, mode, out);
} else if (1 == in->force_long_generic) {
_dpal_long_nopath_generic(X, Y, xlen, ylen, in, out);
} else if (1 == in->max_gap ) {
if (DPAL_LOCAL == in->flag)
_dpal_long_nopath_maxgap1_local(X, Y, xlen, ylen, in, out);
else if (DPAL_GLOBAL_END == in->flag)
_dpal_long_nopath_maxgap1_global_end(X, Y, xlen, ylen, in, out);
else if (DPAL_LOCAL_END == in->flag)
_dpal_long_nopath_maxgap1_local_end(X, Y, xlen, ylen, in, out);
else if (xlen <= DPAL_MAX_ALIGN && ylen <= DPAL_MAX_ALIGN)
_dpal_generic(X, Y, xlen, ylen, in, mode, out);
else _dpal_long_nopath_generic(X, Y, xlen, ylen, in, out);
}
else if (xlen < DPAL_MAX_ALIGN && ylen < DPAL_MAX_ALIGN)
_dpal_generic(X, Y, xlen, ylen, in, mode, out);
else
_dpal_long_nopath_generic(X, Y, xlen, ylen, in, out);
return;
FAIL:
fail_action(in, out);
}
static void
_dpal_generic(const unsigned char *X,
const unsigned char *Y,
const int xlen,
const int ylen,
const dpal_args *in,
const dpal_mode mode,
dpal_results *out)
{
/* The "score matrix" (matrix of best scores). */
static int S[DPAL_MAX_ALIGN][DPAL_MAX_ALIGN];
#ifndef DPAL_FORGET_PATH
/* The matrix of "trace" pointers */
static int P[DPAL_MAX_ALIGN][DPAL_MAX_ALIGN][3];
#endif
register int i, j, k, mg, c;
register int gap = in->gap, gapl = in->gapl, max_gap = in->max_gap;
#ifndef DPAL_FORGET_PATH
int i0 = -99, j0 = -99;
int saved_k;
#endif
int I = -99, J = -99; /* Coordinates of the maximum score. */
int smax; /* The optimum score. */
int score = -99; /* Current score. */
int a,b,max;
#ifdef DPAL_PRINT_COVERAGE
fprintf(stderr, "_dpal_generic called\n");
#endif
CHECK_ERROR(xlen > DPAL_MAX_ALIGN,
"First sequence too long for _dpal_generic");
CHECK_ERROR(ylen > DPAL_MAX_ALIGN,
"Second sequence too long for _dpal_generic");
/* Initialize the 0th column of the score matrix. */
smax = INT_MIN;
for(i=0; i < xlen; i++) {
score = in->ssm[X[i]][Y[0]];
if (DPAL_LOCAL == in->flag) {
if (score < 0) score = 0;
if(score > smax) {
smax = score;
I=i; J=0;
}
}
else if (DPAL_LOCAL_END == in->flag) {if (score < 0) score = 0;}
S[i][0] = score;
}
/* Move code for find global-alignment and end-anchored
alignment below? */
if (DPAL_LOCAL != in->flag) {
/*
* For a non-local alignment we restrict our search for the maximum
* score to the last row.
*/
smax = S[xlen-1][0]; I=xlen-1; J=0;
}
/* Initialize the 0th row of the score matrix. */
for(j=0; jssm[X[0]][Y[j]];
if(DPAL_LOCAL == in->flag){
if (score < 0) score = 0;
if(score > smax){
smax = score;
I=0; J=j;
}
}
else if (DPAL_LOCAL_END == in->flag) {if (score < 0) score = 0;}
S[0][j] = score;
}
if(DPAL_GLOBAL == in->flag&&S[0][ylen-1]>smax){
smax = S[0][ylen-1];
I=0; J=ylen-1;
}
/* Further is the solution for dynamic programming problem. */
for(i=1; i 1) {
b = S[i-2][j-1] + gap;
#ifndef DPAL_FORGET_PATH
i0 = i - 2;
#endif
}
if (j > 1) {
c = S[i-1][j-2] + gap;
#ifndef DPAL_FORGET_PATH
j0 = j - 2;
#endif
}
} else if (max_gap > 1) {
max=INT_MIN;
mg=(max_gap+1>i||max_gap<0)?i:max_gap+1;
for(k=2; k<=mg; k++) {
c = S[i-k][j-1] + gap + gapl*(k-2);
if(c>max){
max=c;
#ifndef DPAL_FORGET_PATH
i0 = i-k;
#endif
}
}
b=max;
max=INT_MIN;
mg=(max_gap+1>j||max_gap<0)?j:max_gap+1;
for(k=2;k<=mg;k++) {
c = S[i-1][j-k] + gap + gapl*(k-2);
if(c>max){
max=c;
#ifndef DPAL_FORGET_PATH
j0 = j-k;
#endif
}
}
c=max;
}
if(a>=b && a>=c) {
score = a + in->ssm[X[i]][Y[j]];
#ifndef DPAL_FORGET_PATH
P[i][j][1] = i-1;
P[i][j][2] = j-1;
#endif
} else if (b > a && b >= c) {
score = b + in->ssm[X[i]][Y[j]];
#ifndef DPAL_FORGET_PATH
P[i][j][1] = i0;
P[i][j][2] = j-1;
#endif
} else if (c > a && c > b) {
score = c + in->ssm[X[i]][Y[j]];
#ifndef DPAL_FORGET_PATH
P[i][j][1] = i-1;
P[i][j][2] = j0;
#endif
}
if (score >= smax)
/*
* Because of comparison '>=' immediately above, dpal reports
* ungapped (i.e. diagonal) alignments if there is a choice
* of more than one optimum alignment.
*/
/* Move code to get 'g' and 'e' maxima to a separate loop ? */
if (DPAL_LOCAL == in->flag
|| (DPAL_GLOBAL_END == in->flag && i == xlen-1)
|| (DPAL_LOCAL_END == in->flag && i == xlen-1)
|| (DPAL_GLOBAL == in->flag&& (i==xlen-1||j==ylen-1))) {
/*
* If in->flag is DPAL_LOCAL, then a cell anywhere within
* S may be the endpoint of the alignment. If in->flag is
* DPAL_GLOBAL_END, then only cells in the last row may be
* the endpoint. If in->flag is DPAL_GLOBAL cells in the
* last row _or_ the last column may be the endpoint.
*/
smax = score;
I = i;
J = j;
} /* put else here ? */
if (score < 0 && (DPAL_LOCAL == in->flag
|| DPAL_LOCAL_END == in->flag))
/*
* For a local alignment, 0 is the lowest score that we record
* in S.
*/
score = 0;
S[i][j]=score;
}
}
/* I and J now specify the last pair of an optimum alignment. */
#ifndef DPAL_FORGET_PATH
k = (I > J) ? I+1 : J+1;
saved_k=k;
out->path[k][0]=I; out->path[k][1]=J;
while(out->path[k][0]!=0&&out->path[k][1]!=0) {
if ((in->flag== DPAL_LOCAL || in->flag == DPAL_LOCAL_END)
&&S[out->path[k][0]][out->path[k][1]]==0) {
k++; break;
}
out->path[k-1][0] = P[out->path[k][0]][out->path[k][1]][1];
out->path[k-1][1] = P[out->path[k][0]][out->path[k][1]][2];
k--;
}
if (k>0) {
for (i=0;i<=saved_k-k;i++) {
out->path[i][0] = out->path[i+k][0];
out->path[i][1] = out->path[i+k][1];
}
}
#endif
if ((DPAL_LOCAL == in->flag
|| DPAL_LOCAL_END == in->flag)&& S[I][J] <= 0) {
/* There is no alignment at all. */
out->score = 0;
out->path_length = 0;
} else {
out->score = smax;
out->align_end_1 = I;
out->align_end_2 = J;
#ifndef DPAL_FORGET_PATH
out->path_length = saved_k - k + 1;
#else
out->path_length = 0;
#endif
}
#ifndef DPAL_FORGET_PATH
if (mode > 1) {
out->sec_struct = print_align(X,Y,P,I,J,in,mode,out);
}
#endif
return;
FAIL:
fail_action(in, out);
} /* _dpal_generic */
/* Linear space, no path, for any value of maxgap and for any alignment. */
static void
_dpal_long_nopath_generic(const unsigned char *X,
const unsigned char *Y,
const int xlen,
const int ylen,
const dpal_args *in,
dpal_results *out)
{
/* The "score matrix" (matrix of best scores). */
int **S, *SI, **P;
register int i, j, k, mg, mgy, c;
register int gap = in->gap, gapl = in->gapl, max_gap = in->max_gap;
int I = -99, J = -99; /* Coordinates of the maximum score. */
int smax; /* The optimum score. */
int score; /* Current score. */
#ifdef DPAL_PRINT_COVERAGE
fprintf(stderr, "_dpal_long_nopath_generic called\n");
#endif
out->score = DPAL_ERROR_SCORE;
out->path_length = 0;
out->msg = NULL;
P = (int **) malloc(sizeof(*S)*(max_gap+2));
if (!P) { DPAL_OOM_ERROR; }
S = (int **) malloc(sizeof(*S)*(max_gap+2));
if (!S) { DPAL_OOM_ERROR; }
for(i=0; issm[X[i]][Y[0]];
if (DPAL_LOCAL == in->flag) {
if (score < 0) score = 0;
if(score > smax) {
smax = score;
I=i; J=0;
}
}
else if (DPAL_LOCAL_END == in->flag) {if (score < 0) score = 0;}
S[0][i] = score;
}
/* Move code for find global-alignment and end-anchored
alignment below? */
if (DPAL_LOCAL != in->flag) {
/*
* For a non-local alignment we restrict our search for the maximum
* score to the last row.
*/
smax = S[0][xlen-1]; I=xlen-1; J=0;
}
/* Initialize the 0th row of the score matrix.
for(j=0; jssm[X[0]][Y[j]];
if(DPAL_LOCAL == in->flag){
if (score < 0) score = 0;
if(score > smax){
smax = score;
I=0; J=j;
}
}
S[0][j] = score;
}
if(DPAL_GLOBAL == in->flag&&S[0][ylen-1]>smax){
smax = S[0][ylen-1];
I=0; J=ylen-1;
}
*/
/* Further is the solution for dynamic programming problem. */
for(j=1; jj||max_gap<0)?j:max_gap+1;
score = in->ssm[X[0]][Y[j]];
if (DPAL_LOCAL == in->flag) {
if (score < 0) score = 0;
if(score > smax) smax = score;
}
else if (DPAL_LOCAL_END == in->flag) { if (score < 0) score = 0;}
else if (DPAL_GLOBAL == in->flag && j == ylen-1 && score > smax)
smax = score;
S[mgy][0] = score;
for(i=1; ii||max_gap<0)?i:max_gap+1;
for(k=2; k<=mg; k++)
if((c = S[mgy-1][i-k] + gap + gapl*(k-2)) > score)score = c;
for(k=2;k<=mgy;k++)
if((c = S[mgy-k][i-1] + gap + gapl*(k-2)) > score)score=c;
score += in->ssm[X[i]][Y[j]];
if (score >= smax)
/*
* Because of comparison '>=' immediately above, dpal reports
* ungapped (i.e. diagonal) alignments if there is a choice
* of more than one optimum alignment.
*/
/* Move code to get 'g' and 'e' maxima to a separate loop ? */
if (DPAL_LOCAL == in->flag
|| ((DPAL_GLOBAL_END == in->flag
|| DPAL_LOCAL_END == in->flag)
&& i == xlen-1)
|| (DPAL_GLOBAL == in->flag&& (i==xlen-1||j==ylen-1))) {
/*
* If in->flag is DPAL_LOCAL, then a cell anywhere within
* S may be the endpoint of the alignment. If in->flag is
* DPAL_GLOBAL_END, then only cells in the last row may be
* the endpoint. If in->flag is DPAL_GLOBAL cells in the
* last row _or_ the last column may be the endpoint.
*/
smax = score;
I = i;
J = j;
} /* put else here ? */
if (score < 0 && (DPAL_LOCAL == in->flag
|| DPAL_LOCAL_END == in->flag))
/*
* For a local alignment, 0 is the lowest score that we record
* in S.
*/
score = 0;
S[mgy][i]=score;
}
if(mgy == max_gap + 1){
SI = S[0];
for(i=0; iflag && smax <= 0) {
/* There is no alignment at all. */
out->score = 0;
out->path_length = 0;
} else {
out->score = smax;
out->align_end_1 = I;
out->align_end_2 = J;
}
for(i=0; i< max_gap + 2; i++) free(P[i]);
free(S);
free(P);
return;
FAIL:
fail_action(in, out);
} /* _dpal_long_nopath_generic */
static void
_dpal_long_nopath_maxgap1_local(const unsigned char *X,
const unsigned char *Y,
const int xlen,
const int ylen,
const dpal_args *in,
dpal_results *out)
{
/* The "score matrix" (matrix of best scores). */
int *S0, *S1, *S2;
int *P0, *P1, *P2;
int *S;
register int i, j;
register int gap = in->gap;
register int smax; /* The optimum score. */
register int score; /* Current score. */
register int a;
#ifdef DPAL_PRINT_COVERAGE
fprintf(stderr, "_dpal_long_nopath_maxgap1_local called\n");
#endif
CHECK_ERROR(ylen < 3,
"_dpal_long_nopath_maxgap1_local requires ylen >= 3\n");
/* Note: S2[0] and S2[1] do not get initialized in this case. */
P0 = (int *) malloc(sizeof(int)*ylen);
if (!P0) { DPAL_OOM_ERROR; }
P1 = (int *) malloc(sizeof(int)*ylen);
if (!P1) { DPAL_OOM_ERROR; }
P2 = (int *) malloc(sizeof(int)*ylen);
if (!P2) { DPAL_OOM_ERROR; }
S0 = P0; S1 = P1; S2 = P2;
smax = 0; /* For local alignment score can never be less than 0. */
/* Initialize the 0th row of the score matrix. */
for(j=0; j < ylen; j++) {
score = in->ssm[X[0]][Y[j]];
if (score < 0) score = 0;
else if (score > smax) smax = score;
/*S[0][j] = score;*/
S0[j] = score;
}
/* Set the 1st row of the score matrix. */
score = in->ssm[X[1]][Y[0]];
if(score < 0) score = 0;
else if (score > smax) smax = score;
S1[0] = score;
for(j=1; j < ylen; j++) {
score = S0[j-1];
if(j>1 && (a=S0[j-2] + gap) > score)score = a;
score += in->ssm[X[1]][Y[j]];
if (score < 0) score = 0;
else if(score > smax) smax = score;
S1[j] = score;
}
for(i=2; i < xlen; i++) {
score = in->ssm[X[i]][Y[0]];
if (score < 0) score = 0;
else if (score > smax) smax = score;
S2[0] = score;
score = S1[0];
if((a=S0[0] + gap) > score) score = a;
score += in->ssm[X[i]][Y[1]];
if(score < 0) score = 0;
else if (score > smax) smax = score;
S2[1] = score;
for(j=2; j < ylen; j++) {
score = S0[j-1];
if((a=S1[j-2])>score) score = a;
score +=gap;
if((a=S1[j-1]) >score) score = a;
score += in->ssm[X[i]][Y[j]];
if (score < 0 ) score = 0;
else if (score > smax) smax = score;
S2[j]=score;
}
S = S0; S0 = S1; S1 = S2; S2 = S;
}
out->score = smax;
out->path_length=0;
free(P0); free(P1); free(P2);
return;
FAIL:
fail_action(in, out);
} /* _dpal_long_nopath_maxgap1_local */
static void
_dpal_long_nopath_maxgap1_global_end(const unsigned char *X,
const unsigned char *Y,
const int xlen,
const int ylen,
const dpal_args *in,
dpal_results *out)
{
/* The "score matrix" (matrix of best scores). */
int *S0, *S1, *S2, *S;
int *P0, *P1, *P2;
register int i, j, k;
register int gap = in->gap;
register int smax; /* The optimum score. */
register int score; /* Current score. */
register int a, t;
#ifdef DPAL_PRINT_COVERAGE
fprintf(stderr, "_dpal_long_nopath_maxgap1_global_end called\n");
#endif
P0 = (int *) malloc(sizeof(int)*xlen);
if (!P0) { DPAL_OOM_ERROR; }
P1 = (int *) malloc(sizeof(int)*xlen);
if (!P1) { DPAL_OOM_ERROR; }
P2 = (int *) malloc(sizeof(int)*xlen);
if (!P2) { DPAL_OOM_ERROR; }
S0 = P0; S1 = P1; S2 = P2;
smax = in->ssm[X[xlen-1]][Y[0]];
/* Set the 0th row of the score matrix. */
for(j=0; jssm[X[j]][Y[0]];
/* Set the 1st row of the score matrix. */
S1[0] = in->ssm[X[0]][Y[1]];
for(j=1; j < xlen; j++){
score = S0[j-1];
if(j>1 && (a=S0[j-2] + gap)> score)score = a;
score += in->ssm[X[j]][Y[1]];
if(score > smax && j == xlen-1) smax = score;
S1[j] = score;
}
k = ylen - (int)(xlen / 2) + 1;
if (k<1) k = 1;
/* Set the rectangular part of almost the remainder of the matrix. */
for(j=2; jssm[X[0]][Y[j]];
score = S1[0];
if((a=S0[0]+gap) > score) score = a;
score += in->ssm[X[1]][Y[j]];
S2[1] = score;
for(i=2; i score)score = a;
score += gap;
if((a=S1[i-1]) > score)score = a;
score += in->ssm[X[i]][Y[j]];
S2[i] = score;
}
score = S1[xlen-3];
if((a=S0[xlen-2]) > score)score = a;
score += gap;
if((a=S1[xlen-2]) > score)score = a;
score += in->ssm[X[xlen-1]][Y[j]];
S2[xlen-1] = score;
if(score > smax) smax = score;
S = S0; S0 = S1; S1 = S2; S2 = S;
}
/* Set the triangular part of almost the remainder of the matrix. */
t = 2;
for(j=k+1; j score) score = a;
score += gap;
if((a=S1[i-1]) > score) score = a;
score += in->ssm[X[i]][Y[j]];
S2[i] = score;
}
t += 2;
score = S1[xlen-3];
if((a=S0[xlen-2]) > score)score = a;
score += gap;
if((a=S1[xlen-2]) > score)score = a;
score += in->ssm[X[xlen-1]][Y[j]];
S2[xlen-1] = score;
if(score > smax) smax = score;
S = S0; S0 = S1; S1 = S2; S2 = S;
}
free(P0); free(P1); free(P2);
out->score = smax;
out->path_length=0;
return;
FAIL:
fail_action(in, out);
} /* _dpal_long_nopath_maxgap_global_end */
#ifndef DPAL_FORGET_PATH
/* Reconstruct the best path and print the alignment. */
char *
print_align(const unsigned char *X,
const unsigned char *Y,
int P[DPAL_MAX_ALIGN][DPAL_MAX_ALIGN][3],
int I,
int J,
const dpal_args *dargs,
const dpal_mode mode,
dpal_results *out)
{
int JX[DPAL_MAX_ALIGN],JY[DPAL_MAX_ALIGN];
int k,i,j,n,m,ret_nr,ret_pr_once;
char sx[3*DPAL_MAX_ALIGN],sy[3*DPAL_MAX_ALIGN],sxy[3*DPAL_MAX_ALIGN];
char ret_str[9*(DPAL_MAX_ALIGN + 10)];
char *ret_ptr = NULL;
for (i=0; i < 3*DPAL_MAX_ALIGN; i++) {
sx[i] = ' '; sy[i] = ' '; sxy[i] = ' ';
}
if(I>J)k=I+1;
else k=J+1;
n=k;
JX[k] = I;
JY[k] = J;
while(JX[k]!=0&&JY[k]!=0){
JX[k-1] = P[JX[k]][JY[k]][1];
JY[k-1] = P[JX[k]][JY[k]][2];
k--;
}
if(JX[k]>JY[k]){
for(i=0;issm[(unsigned char)sx[m]][(unsigned char)sy[m]] > 0)
sxy[m] = '|';
else sxy[m]=' ';
if(JX[i+1]-JX[i]>JY[i+1]-JY[i]){
for(j=1;jJX[i+1]-JX[i]){
for(j=1;jssm[(unsigned char)sx[m]][(unsigned char)sy[m]] > 0)
sxy[m] = '|';
else sxy[m]=' ';
m++;
if (strlen((char *) X) - I > strlen((char *) Y)-J) {
k = m + strlen((char *) X) - I;
} else {
k = m + strlen((char *) Y) - J;
}
if (mode == DPM_DEBUG) {
j=0;
while(j 0 && ret_str[ret_nr - 1] == ' ') {
ret_nr--;
}
strcpy(ret_str + ret_nr, " 3\'\\n ");
ret_nr += 8;
for(i=j;i 0 && ret_str[ret_nr - 1] == ' ') {
ret_nr--;
}
strcpy(ret_str + ret_nr, "\\n ");
ret_nr += 5;
ret_pr_once = -1;
for(i=j;i 0 && ret_str[ret_nr - 1] == ' ') {
ret_nr--;
}
strcpy(ret_str + ret_nr, " 5\'\\n");
ret_nr += 5;
j +=70;
}
ret_str[ret_nr++] = '\0';
ret_ptr = (char *) malloc(strlen(ret_str) + 1);
if (!ret_ptr) {
out->msg = "Out of memory";
errno=ENOMEM;
return NULL;
}
strcpy(ret_ptr, ret_str);
return ret_ptr;
}
return NULL;
} /* print_align(X,Y,P,I,J, dargs) */
#endif
static int
illegal_char(const unsigned char *X,
const dpal_ssm ssm,
char *out)
{
register const unsigned char *p;
for (p = X; *p != '\0' && ssm[*p][*p] != INT_MIN; p++);
if (*p == '\0')
return 0;
else {
*out = *p;
return 1;
}
}
static void
_dpal_long_nopath_maxgap1_local_end(const unsigned char *X,
const unsigned char *Y,
const int xlen,
const int ylen,
const dpal_args *in,
dpal_results *out)
{
/* The "score matrix" (matrix of best scores). */
int *S0, *S1, *S2;
int *P0, *P1, *P2;
int *S;
register int i, j;
register int gap = in->gap;
register int smax; /* The optimum score. */
register int score; /* Current score. */
register int a;
#ifdef DPAL_PRINT_COVERAGE
fprintf(stderr, "_dpal_long_nopath_maxgap1_local_end called\n");
#endif
CHECK_ERROR(ylen < 3,
"_dpal_long_nopath_maxgap1_local_end requires ylen >= 3\n");
/* Note: S2[0] and S2[1] do not get initialized in this case. */
P0 = (int *) malloc(sizeof(int)*ylen);
if (!P0) { DPAL_OOM_ERROR; }
P1 = (int *) malloc(sizeof(int)*ylen);
if (!P1) { DPAL_OOM_ERROR; }
P2 = (int *) malloc(sizeof(int)*ylen);
if (!P2) { DPAL_OOM_ERROR; }
S0 = P0; S1 = P1; S2 = P2;
smax = 0; /* For local alignment score can never be less than 0. */
/* Initialize the 0th row of the score matrix. */
for(j=0; j < ylen; j++) {
score = in->ssm[X[0]][Y[j]];
if (score < 0) score = 0;
/*S[0][j] = score;*/
S0[j] = score;
}
/* Set the 1st row of the score matrix. */
score = in->ssm[X[1]][Y[0]];
if(score < 0) score = 0;
S1[0] = score;
for(j=1; j < ylen; j++) {
score = S0[j-1];
if(j>1 && (a=S0[j-2] + gap) > score)score = a;
score += in->ssm[X[1]][Y[j]];
if (score < 0) score = 0;
S1[j] = score;
}
for(i=2; i < xlen - 1; i++) {
score = in->ssm[X[i]][Y[0]];
if (score < 0) score = 0;
S2[0] = score;
score = S1[0];
if((a=S0[0] + gap) > score) score = a;
score += in->ssm[X[i]][Y[1]];
if(score < 0) score = 0;
S2[1] = score;
for(j=2; j < ylen; j++) {
score = S0[j-1];
if((a=S1[j-2])>score) score = a;
score +=gap;
if((a=S1[j-1]) >score) score = a;
score += in->ssm[X[i]][Y[j]];
if (score < 0 ) score = 0;
S2[j]=score;
}
S = S0; S0 = S1; S1 = S2; S2 = S;
}
/* Calculate scores for last row (i = xlen-1) and find smax */
i = xlen - 1;
score = in->ssm[X[i]][Y[0]];
if (score < 0) score = 0;
else if (score > smax) smax = score;
S2[0] = score;
score = S1[0];
if((a=S0[0] + gap) > score) score = a;
score += in->ssm[X[i]][Y[1]];
if(score < 0) score = 0;
else if (score > smax) smax = score;
S2[1] = score;
for(j=2; j < ylen; j++) {
score = S0[j-1];
if((a=S1[j-2])>score) score = a;
score +=gap;
if((a=S1[j-1]) >score) score = a;
score += in->ssm[X[i]][Y[j]];
if (score < 0 ) score = 0;
else if (score > smax) smax = score;
S2[j]=score;
}
out->score = smax;
out->path_length=0;
free(P0); free(P1); free(P2);
return;
FAIL:
fail_action(in, out);
} /* _dpal_long_nopath_maxgap1_local */
primer3-py-2.3.1/primer3/src/libprimer3/dpal.h 0000664 0000000 0000000 00000015601 15247271707 0021054 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 1996,1997,1998,1999,2000,2001,2004,2006,2007,2008
Whitehead Institute for Biomedical Research, Steve Rozen
(http://purl.com/STEVEROZEN/), Andreas Untergasser and Helen Skaletsky
All rights reserved.
This file is part the primer3 software suite.
This software suite is free software;
you can redistribute is and/or modify it under the terms
of the GNU General Public License as published by the Free
Software Foundation; either version 2 of the License, or (at
your option) any later version.
This software is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this file (file gpl-2.0.txt in the source
distribution); if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _DPAL_H
#define _DPAL_H
#include /* INT_MIN */
#ifdef __cplusplus
extern "C" {
#endif
#define DPAL_ERROR_SCORE INT_MIN
#define DPAL_EXIT_ON_ERROR 0
/* 0 means do not exit on error. */
#ifndef DPAL_MAX_ALIGN
#define DPAL_MAX_ALIGN 1600 /*
* The maximum size of a string that can be
* aligned with with generic dpal and for which
* we can return a "path". Several arrays of
* size DPAL_MAX_ALIGN X DPAL_MAX_ALIGN are
* statically allocated in dpal.o
*/
#endif
#define DPAL_LOCAL 0 /* Return a local alignment. */
#define DPAL_GLOBAL_END 1 /*
* Return a global alignment _anchored at the end
* of the first sequence_.
*/
#define DPAL_GLOBAL 2 /*
* Return an arbitrary global alignment, that is
* one anchored at the end of either the first or
* the second sequence.
*/
#define DPAL_LOCAL_END 3 /*
* Return a local alignment that includes the
* end (but not necessarily the beginning) of
* the first sequence.
*/
/*
* It is not possible to specify end-gap penalties for the DPAL_GLOBAL_END
* and DPLAL_GLOBAL flags.
*/
/*
* The data structure that stores the "scoring system matrix". (The socring
* system matrix data structure is of size UCHAR_MAX + 1 by UCHAR_MAX + 1.)
*/
typedef int dpal_ssm[UCHAR_MAX + 1][UCHAR_MAX + 1];
/* Structure for passing in arguments to the main function, dpal. */
typedef struct dpal_args {
int check_chars; /*
* If non-0, check for and raise an error on an
* illegal character in the input strings.
*/
int fail_stop; /* Exit with -1 on error. */
int flag; /*
* One of DPAL_GLOBAL, DPAL_LOCAL,
* DPAL_GLOBAL_END, DPAL_LOCAL_END
*/
int force_generic; /* Force the use of the generic function. */
int force_long_generic; /*
* Force the use of the long generic no-path
* function.
*/
int force_long_maxgap1; /* Force the use of the long maxgap 1 functions. */
int gap; /* The "gap opening" penalty. */
int gapl; /* The "gap extension" penalty. */
int max_gap; /*
* The maximum allowable size for a gap. -1
* indicates that the gap can be of any size.
*/
int score_max; /* If greater than 0 stop search as soon as
* score > score_max.
*/
dpal_ssm ssm; /* The scoring system matrix. */
} dpal_args;
/* Structure for receiving results from the main function, dpal. */
typedef struct dpal_results {
const char *msg;
int path[DPAL_MAX_ALIGN][2];
int path_length;
int align_end_1; /* Last alignment position in the 1st sequence. */
int align_end_2; /* Last alignment position in the 2nd sequence. */
double score;
char *sec_struct;
} dpal_results;
/*
* DPM_FAST = 0 - score only with optimized functions (fast)
* DPM_GENERAL = 1 - use general function without debug (slow)
* DPM_DEBUG = 2 - debug mode print alignments on STDERR
* DPM_STRUCT = 3 - calculate secondary structures as string
*/
typedef enum dpal_mode {
DPM_FAST = 0,
DPM_GENERAL = 1,
DPM_DEBUG = 2,
DPM_STRUCT = 3
} dpal_mode;
/* Initialize the argument to the default matrix for nucleotide matches. */
void dpal_set_default_nt_args(dpal_args *);
/* Routine primarily for testing: sets CC & GG matches to 3, AA & TT
matches to 2. */
void dpal_set_h_nt_matrix(dpal_args *a);
/* The argument, a, must be a DNA scoring matrix. Modifies a so that it for a
match between any two ambiguity codes (or between ambiguity code and base),
e.g. B and S, the score will be the maximum of score between any base in B
and any base in S, in the example between any pair in {C, G, T} X {C, G}.
This function overwrites any scores already associated with pairs of
ambiguity codes. Return 0 on error, 1 on success.
*/
int dpal_set_ambiguity_code_matrix(dpal_args *);
/*
* Align the first 2 arguments, using the scoring
* matix and other arguments supplied in the dpal_args
* argument. Return results in argument 'out'.
* On error, sets out->score to DPAL_ERROR_SCORE
* and puts additional information in out->msg.
*/
void dpal(const unsigned char *, const unsigned char*,
const dpal_args *, const dpal_mode mode, dpal_results *out);
void set_dpal_args(dpal_args *);
#ifdef __cplusplus
}
#endif
#endif
primer3-py-2.3.1/primer3/src/libprimer3/format_output.c 0000664 0000000 0000000 00000103164 15247271707 0023041 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 1996,1997,1998,1999,2000,2001,2004,2006,2007,2008,2009,2010
Whitehead Institute for Biomedical Research, Steve Rozen
(http://purl.com/STEVEROZEN), Andreas Untergasser and Helen Skaletsky
All rights reserved.
This file is part of primer3 and the libprimer3 library.
Primer3 and the libprimer3 library are free software;
you can redistribute them and/or modify them under the terms
of the GNU General Public License as published by the Free
Software Foundation; either version 2 of the License, or (at
your option) any later version.
This software is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this software (file gpl-2.0.txt in the source
distribution); if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANYT
HEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include
#include
#include "format_output.h"
#include "libprimer3.h"
#define FORWARD 1
#define REVERSE -1
static const char *pr_program_name = "Program name is probably primer3_core";
static void format_pairs(FILE *f,
const p3_global_settings *pa,
const seq_args_t* sa,
const p3retval *retval,
const pair_array_t *best_pairs,
const char *pr_release,
const pr_append_str *combined_retval_err,
int explain_flag);
static void format_oligos(FILE *,
const p3_global_settings *,
const seq_args_t* ,
const p3retval *retval,
const char*,
const pr_append_str *combined_retval_err,
int explain_flag);
static int lib_sim_specified(const p3_global_settings *);
static void print_explain(FILE *, const p3_global_settings *, const seq_args_t* ,
const p3retval *retval, int, const char *);
static void print_pair_info(FILE *, const primer_pair *,
const p3_global_settings *);
static void print_oligo(FILE *, const char *, const seq_args_t* ,
const primer_rec *, int, const p3_global_settings *,
const seq_lib*, int);
static void print_oligo_header(FILE *, const char *, const int, const int);
static void print_pair_array(FILE *, const char*, int,
const interval_array_t,
const p3_global_settings*, const seq_args_t*);
static void print_2_pair_array(FILE *, const char*, int,
const interval_array_t,
const interval_array_t,
const p3_global_settings*, const seq_args_t*);
static void print_rest(FILE *, const p3_global_settings *,
const seq_args_t* , const pair_array_t *);
static int print_seq(FILE *, const p3_global_settings *, const seq_args_t* ,
const p3retval *retval, primer_rec *h,
const pair_array_t *, int);
static void print_seq_lines(FILE *, const char *s, const char *n, int, int,
int, const p3_global_settings *);
static void print_stat_line(FILE *, const char *, oligo_stats s, int, int, int);
static void print_summary(FILE *, const p3_global_settings *,
const seq_args_t* , const pair_array_t *, int);
void
print_format_output(FILE *f,
const int *io_version,
const p3_global_settings *pa,
const seq_args_t* sa,
const p3retval *retval,
const char *pr_release,
int explain_flag)
{
/* A place to put a string containing all error messages */
pr_append_str *combined_retval_err = NULL;
combined_retval_err = create_pr_append_str();
if (NULL == combined_retval_err) exit(-2); /* Out of memory */
if (pr_append_new_chunk_external(combined_retval_err,
retval->glob_err.data))
exit(-2);
if (pr_append_new_chunk_external(combined_retval_err,
retval->per_sequence_err.data))
exit(-2);
/* Print as primer pairs */
if (retval->output_type == primer_pairs) {
format_pairs(f, pa, sa, retval, &retval->best_pairs,
pr_release, combined_retval_err, explain_flag);
/* Print as primer list */
} else {
format_oligos(stdout, pa, sa, retval, pr_release,
combined_retval_err, explain_flag);
}
destroy_pr_append_str(combined_retval_err);
}
static void
format_pairs(FILE *f,
const p3_global_settings *pa,
const seq_args_t* sa,
const p3retval *retval,
const pair_array_t *best_pairs,
const char *pr_release,
const pr_append_str *combined_retval_err,
int explain_flag)
{
char *warning;
int print_lib_sim = lib_sim_specified(pa);
primer_rec *h = NULL;
PR_ASSERT(NULL != f);
PR_ASSERT(NULL != pa);
PR_ASSERT(NULL != sa);
/* If there are errors, print them and return */
if (!pr_is_empty(combined_retval_err)) {
format_error(f, sa->sequence_name,
pr_append_str_chars(combined_retval_err));
return;
}
/* Print the sequence name if it is provided */
if (NULL != sa->sequence_name)
fprintf(f, "PRIMER PICKING RESULTS FOR %s\n\n", sa->sequence_name);
/* Print if a mispriming libraby was used and which one */
if (pa->p_args.repeat_lib != NULL)
fprintf(f, "Using mispriming library %s\n",
pa->p_args.repeat_lib->repeat_file);
else
fprintf(f, "No mispriming library specified\n");
/* Print if a mispriming libraby for the internal oligo
* was used and which one */
if ( pa->pick_internal_oligo == 1 ) {
if (pa->o_args.repeat_lib != NULL)
fprintf(f, "Using internal oligo mishyb library %s\n",
pa->o_args.repeat_lib->repeat_file);
else
fprintf(f, "No internal oligo mishyb library specified\n");
}
/* Does the sequence start at position 0 or 1 ? */
fprintf(f, "Using %d-based sequence positions\n",
pa->first_base_index);
/* Complain if no primers are in the array */
if (best_pairs->num_pairs == 0) fprintf(f, "NO PRIMERS FOUND\n\n");
/* Print out the warings */
if ((warning = p3_get_rv_and_gs_warnings(retval, pa)) != NULL) {
fprintf(f, "WARNING: %s\n\n", warning);
free(warning);
}
/* Print the results for the best pair */
print_summary(f, pa, sa, best_pairs, 0);
fprintf(f, "\n");
/* Print nicely out the sequence with the best pair */
if (print_seq(f, pa, sa, retval, h, best_pairs, 0)) exit(-2); /* ENOMEM */
/* Print out the alternative pairs */
if (best_pairs->num_pairs > 1 ) print_rest(f, pa, sa, best_pairs);
/* Print the primer picking statistics */
if (explain_flag)
print_explain(f, pa, sa, retval, print_lib_sim, pr_release);
/* Flush the buffers and return */
fprintf(f, "\n\n");
if (fflush(f) == EOF) {
perror("fflush(f) failed");
exit(-1);
}
}
/* Prints out the results of a primer pair */
static void
print_summary(FILE *f, const p3_global_settings *pa,
const seq_args_t* sa, const pair_array_t *best_pairs,
int num)
{
int seq_len = strlen(sa->sequence);
int print_lib_sim = lib_sim_specified(pa);
primer_pair *p;
p = best_pairs->pairs + num;
if (best_pairs->num_pairs > 0) {
/*
* If the following format changes, also change the format in
* print_oligo.
*/
print_oligo_header(f, "OLIGO", print_lib_sim, pa->thermodynamic_oligo_alignment);
print_oligo(f, "LEFT PRIMER", sa, p->left, FORWARD, pa,
pa->p_args.repeat_lib,
print_lib_sim);
print_oligo(f, "RIGHT PRIMER", sa, p->right, REVERSE, pa,
pa->p_args.repeat_lib,
print_lib_sim);
if ( pa->pick_internal_oligo == 1 )
print_oligo(f, "INTERNAL OLIGO", sa, p->intl, FORWARD,
pa, pa->o_args.repeat_lib,
print_lib_sim);
}
fprintf(f, "SEQUENCE SIZE: %d\n", seq_len);
fprintf(f, "INCLUDED REGION SIZE: %d\n\n", sa->incl_l);
if (best_pairs->num_pairs > 0) print_pair_info(f, p, pa);
print_pair_array(f, "TARGETS", sa->tar2.count, sa->tar2.pairs, pa, sa);
print_pair_array(f, "EXCLUDED REGIONS", sa->excl2.count, sa->excl2.pairs, pa, sa);
print_pair_array(f, "INTERNAL OLIGO EXCLUDED REGIONS",
sa->excl_internal2.count, sa->excl_internal2.pairs, pa, sa);
print_2_pair_array(f, "PAIR_OK_REGIONS", sa->ok_regions.count, sa->ok_regions.left_pairs,
sa->ok_regions.right_pairs, pa, sa);
}
/* Print column headers for lines printed by print_oligo(). */
static void
print_oligo_header(FILE *f, const char *s, const int print_lib_sim,
const int thermodynamic_oligo_alignment)
{
if(thermodynamic_oligo_alignment==0)
fprintf(f,
"%-16s start len tm gc%% any 3' %sseq\n",
s, print_lib_sim ? " rep " : "");
else
fprintf(f,
"%-16s start len tm gc%% any_th 3'_th hairpin %sseq\n",
s, print_lib_sim ? " rep " : "");
}
/* Print the line with the parameters */
static void
print_oligo(FILE *f,
const char *title,
const seq_args_t* sa,
const primer_rec *o,
int dir,
const p3_global_settings *pa,
const seq_lib *seqlib,
int print_lib_sim)
{
const char *format1;
char *seq = (FORWARD == dir)
? pr_oligo_sequence(sa, o) : pr_oligo_rev_c_sequence(sa, o);
if(pa->thermodynamic_oligo_alignment==1) {
format1 = "%-16s %5d %4d %7.2f %7.2f %5.2f %5.2f ";
fprintf(f, format1,
title, o->start + sa->incl_s + pa->first_base_index,
o->length, o->temp, o->gc_content, o->self_any,
o->self_end);
fprintf(f, " %5.2f ", o->hairpin_th);
} else {
format1 = "%-16s %5d %4d %7.2f %7.2f %5.2f %5.2f ";
fprintf(f, format1,
title, o->start + sa->incl_s + pa->first_base_index,
o->length, o->temp, o->gc_content, o->self_any,
o->self_end);
}
if (print_lib_sim) {
if (seqlib != NULL)
fprintf(f, "%5.2f ", o->repeat_sim.score[o->repeat_sim.max]);
else
fprintf(f, "%5s ", "");
}
fprintf(f, "%s\n", seq);
if (PR_DEFAULT_INSIDE_PENALTY != pa->inside_penalty
|| PR_DEFAULT_OUTSIDE_PENALTY != pa->outside_penalty)
fprintf(f, "POSITION PENALTY, QUALITY: %f, %f\n",
o->position_penalty, o->quality);
}
static void
print_pair_array(FILE *f, const char* title, int num,
const interval_array_t array,
const p3_global_settings *pa,
const seq_args_t* sa)
{
int j;
if (num > 0) {
fprintf(f, "%s (start, len)*:", title);
for (j = 0; j < num; j++)
fprintf(f, " %d,%d",
array[j][0] + pa->first_base_index + sa->incl_s,
array[j][1]);
fprintf(f, "\n");
}
}
static void
print_2_pair_array(FILE *f, const char* title, int num,
const interval_array_t left_array,
const interval_array_t right_array,
const p3_global_settings *pa,
const seq_args_t* sa)
{
int j;
if (num > 0) {
fprintf(f, "%s (left_start, left_len, right_start, right_len)*:", title);
for (j = 0; j < num; j++) {
if ((left_array[j][0] == -1) && (left_array[j][1] == -1))
fprintf(f, " ,,");
else fprintf(f, " %d,%d,",
left_array[j][0] + pa->first_base_index + sa->incl_s,
left_array[j][1]);
if ((right_array[j][0] == -1) && (right_array[j][1] == -1))
fprintf(f, ",");
else fprintf(f, "%d,%d",
right_array[j][0] + pa->first_base_index + sa->incl_s,
right_array[j][1]);
}
fprintf(f, "\n");
}
}
#define VECTOR (1<<0)
#define LEFT_OLIGO (1<<1)
#define RIGHT_OLIGO (1<<2)
#define INTL_OLIGO (1<<3)
#define TARGET (1<<4)
#define EXCL_REGION (1<<5)
#define INTL_EXCL_REGION (1<<6)
/* Prints out the asci picture of the sequence */
/* Return 1 on ENOMEM. Otherwise return 0. */
static int
print_seq(FILE *f,
const p3_global_settings *pa,
const seq_args_t* sa,
const p3retval *retval,
primer_rec *h,
const pair_array_t *best_pairs,
int num) /* The number of primer pair to print. */
{
primer_rec *h2 = NULL;
primer_rec *h3 = NULL;
int len, i, j, start;
int something_found = 0, vector_found = 0;
int *notes;
char *notestr;
primer_pair *p;
p = NULL;
if(retval->output_type == primer_pairs) {
p = best_pairs->pairs + num;
}
len = strlen(sa->sequence);
if (!(notes = (int*) malloc(sizeof(int) * len))) return 1;
memset(notes, 0, sizeof(int) * len);
if (!(notestr = (char*) malloc(len + 1))) { free(notes); return 1; }
memset(notestr, ' ', len);
notestr[len] = '\0';
for (i = 0; i < len; i++) {
if (i < sa->incl_s || i >= sa->incl_s + sa->incl_l)
notes[i] |= VECTOR;
if (retval->output_type == primer_pairs &&
best_pairs->num_pairs > 0) {
if (i >= p->left->start + sa->incl_s
&& i < p->left->start + p->left->length + sa->incl_s)
notes[i] |= LEFT_OLIGO;
if (i >= p->right->start - p->right->length + 1 + sa->incl_s
&& i <= p->right->start + sa->incl_s)
notes[i] |= RIGHT_OLIGO;
if ( pa->pick_internal_oligo == 1
&& i >= p->intl->start + sa->incl_s
&& i < p->intl->start + p->intl->length + sa->incl_s)
notes[i] |= INTL_OLIGO;
}
else if (h != NULL) {
if(pa->pick_left_primer == 1 &&
i < h->start + h->length + sa->incl_s &&
i >= h->start + sa->incl_s)
notes[i] |= LEFT_OLIGO;
else if(pa->pick_right_primer == 1 &&
i >= h->start - h->length + 1 + sa->incl_s
&& i <= h->start + sa->incl_s)
notes[i] |= RIGHT_OLIGO;
else if(pa->pick_internal_oligo == 1 &&
i >= h->start + sa->incl_s &&
i < h->start + h->length + sa->incl_s)
notes[i] |= INTL_OLIGO;
} else if (pa->primer_task == pick_sequencing_primers) {
if (pa->pick_right_primer && (retval->rev.oligo != NULL)
&& (retval->rev.num_elem > 0) ){
h2 = retval->rev.oligo;
for (j = 0; j < pa->num_return; j++) {
if(j > retval->rev.num_elem -1) break;
h3 = h2 + j;
if(i >= h3->start - h3->length + 1 + sa->incl_s
&& i <= h3->start + sa->incl_s) {
notes[i] |= RIGHT_OLIGO;
}
}
}
if (pa->pick_left_primer && (retval->fwd.oligo != NULL)
&& (retval->fwd.num_elem > 0) ) {
h2 = retval->fwd.oligo;
for (j = 0; j < pa->num_return; j++) {
if(j > retval->fwd.num_elem -1) break;
h3 = h2 + j;
if(i < h3->start + h3->length + sa->incl_s &&
i >= h3->start + sa->incl_s) {
notes[i] |= LEFT_OLIGO;
}
}
}
}
for (j = 0; j < sa->tar2.count; j++) {
start = sa->tar2.pairs[j][0] + sa->incl_s;
if (i >= start && i < start + sa->tar2.pairs[j][1])
notes[i] |= TARGET;
}
for (j = 0; j < sa->excl2.count; j++) {
start = sa->excl2.pairs[j][0] + sa->incl_s;
if (i >= start && i < start + sa->excl2.pairs[j][1])
notes[i] |= EXCL_REGION;
}
for (j = 0; j < sa->excl_internal2.count; j++) {
start = sa->excl_internal2.pairs[j][0] + sa->incl_s;
if (i >= start && i < start + sa->excl_internal2.pairs[j][1])
notes[i] |= INTL_EXCL_REGION;
}
}
for (i = 0; i < len; i++) {
if (notes[i] & VECTOR) {
vector_found = 1;
notestr[i] = '.';
}
else if (notes[i] & EXCL_REGION)
notestr[i] = 'X';
else if (notes[i] & INTL_EXCL_REGION)
notestr[i] = 'x';
else if ((pa->primer_task == pick_sequencing_primers)
&& (notes[i] & LEFT_OLIGO)
&& (notes[i] & RIGHT_OLIGO))
notestr[i] = '^';
else if ((pa->primer_task == pick_sequencing_primers)
&& (notes[i] & LEFT_OLIGO))
notestr[i] = '>';
else if ((pa->primer_task == pick_sequencing_primers)
&& (notes[i] & RIGHT_OLIGO))
notestr[i] = '<';
else if ((notes[i] & TARGET) && (notes[i] & LEFT_OLIGO))
notestr[i] = ')';
else if ((notes[i] & TARGET) && (notes[i] & RIGHT_OLIGO))
notestr[i] = '(';
else if (notes[i] & TARGET)
notestr[i] = '*';
else if (notes[i] & LEFT_OLIGO)
notestr[i] = '>';
else if (notes[i] & RIGHT_OLIGO)
notestr[i] = '<';
else if (notes[i] & INTL_OLIGO)
notestr[i] = '^';
if (notes[i] != 0) something_found = 1;
}
print_seq_lines(f, sa->sequence, notestr, len, 60, something_found, pa);
if (something_found)
fprintf(f, "KEYS (in order of precedence):\n");
if (vector_found)
fprintf(f, "...... vector sequence\n");
if (sa->excl2.count > 0)
fprintf(f, "XXXXXX excluded region\n");
if (pa->pick_internal_oligo ==1 && sa->excl_internal2.count > 0)
fprintf(f, "xxxxxx excluded region for internal oligo\n");
if (sa->tar2.count > 0)
fprintf(f, "****** target\n");
if (retval->output_type == primer_pairs &&
best_pairs->num_pairs > 0) {
fprintf(f, ">>>>>> left primer\n");
fprintf(f, "<<<<<< right primer\n");
if ( pa->pick_internal_oligo == 1 )
fprintf(f, "^^^^^^ internal oligo\n");
} else if (pa->primer_task == pick_sequencing_primers) {
fprintf(f, ">>>>>> left primer\n");
fprintf(f, "<<<<<< right primer\n");
fprintf(f, "^^^^^^ left primer / right primer overlap\n");
}
else if (pa->pick_left_primer == 1 && h != NULL)
fprintf(f, ">>>>>> left primer\n");
else if (pa->pick_right_primer == 1 && h != NULL)
fprintf(f, "<<<<<< right primer\n");
else if (pa->pick_internal_oligo == 1 && h != NULL)
fprintf(f, "^^^^^^ internal oligo\n");
if (something_found) fputc('\n', f);
free(notes);
free(notestr);
return 0;
}
static void
print_seq_lines(FILE *f, const char *s, const char *n, int seq_size,
int line_size, int something_found,
const p3_global_settings *pa)
{
int i = 0;
while (seq_size > line_size) {
fprintf(f, "%5d ", i + pa->first_base_index);
fwrite(s, sizeof(char), line_size, f);
fputc('\n', f);
if (something_found) {
fprintf(f, " ");
fwrite(n, sizeof(char), line_size, f);
fprintf(f, "\n\n");
}
seq_size -= line_size;
s += line_size;
n += line_size;
i += line_size;
}
if (something_found)
fprintf(f, "%5d %s\n %s\n\n", i + pa->first_base_index, s, n);
else
fprintf(f, "%5d %s\n\n", i + pa->first_base_index, s);
}
static void
print_pair_info(FILE *f, const primer_pair *p, const p3_global_settings *pa)
{
fprintf(f, "PRODUCT SIZE: %d, ", p->product_size);
if(pa->thermodynamic_oligo_alignment==0)
fprintf(f, "PAIR ANY COMPL: %.2f, PAIR 3' COMPL: %.2f\n",
p->compl_any, p->compl_end);
else
fprintf(f, "PAIR ANY_TH COMPL: %.2f, PAIR 3'_TH COMPL: %.2f\n",
p->compl_any, p->compl_end);
if (pa->product_max_tm != PR_DEFAULT_PRODUCT_MAX_TM
|| pa->product_min_tm != PR_DEFAULT_PRODUCT_MIN_TM) {
printf("PRODUCT Tm: %.4f, ", p->product_tm);
printf("PRODUCT Tm - min(OLIGO Tm): %.4f\n",
p->product_tm_oligo_tm_diff);
}
}
static void
print_rest(FILE *f, const p3_global_settings *pa,
const seq_args_t* sa,
const pair_array_t *best_pairs)
{
int i;
int print_lib_sim = lib_sim_specified(pa);
fprintf(f, "ADDITIONAL OLIGOS\n");
fprintf(f, " "); print_oligo_header(f, "", print_lib_sim, pa->thermodynamic_oligo_alignment);
for (i = 1; i < best_pairs->num_pairs; i++) {
fprintf(f, "\n%2d ", i);
print_oligo(f, "LEFT PRIMER", sa, best_pairs->pairs[i].left, FORWARD,
pa, pa->p_args.repeat_lib, print_lib_sim);
fprintf(f, " ");
print_oligo(f, "RIGHT PRIMER", sa, best_pairs->pairs[i].right, REVERSE,
pa, pa->p_args.repeat_lib, print_lib_sim);
if ( pa->pick_internal_oligo == 1) {
fprintf(f, " ");
print_oligo(f, "INTERNAL OLIGO", sa, best_pairs->pairs[i].intl,
FORWARD, pa, pa->o_args.repeat_lib, print_lib_sim);
}
if (best_pairs->pairs[i].product_size > 0) {
fprintf(f, " ");
print_pair_info(f, &best_pairs->pairs[i], pa);
}
}
}
/* Print out the statistics of primer picking */
/* This function does _not_ print out the no_orf statistic. */
static void
print_explain(FILE *f,
const p3_global_settings *pa,
const seq_args_t* sa,
const p3retval *retval,
int print_lib_sim,
const char *pr_release)
{
const char *format; /* Format string for the table headers */
if(pa->thermodynamic_oligo_alignment==0)
format = "%6s%6s%6s%6s%6s%6s%6s%6s%6s%6s%6s%6s";
else format = "%6s%6s%6s%6s%6s%6s%6s%6s%6s%6s%7s%6s";
fprintf(f, "\nStatistics\n");
if (!pa->pick_anyway || !(
(pa->pick_left_primer == 1 && pa->pick_internal_oligo == 0
&& pa->pick_right_primer == 1
&& sa->left_input && sa->right_input)
|| (pa->pick_left_primer == 1 && pa->pick_internal_oligo == 1
&& pa->pick_right_primer == 1
&& sa->left_input && sa->right_input && sa->internal_input)
|| (pa->pick_left_primer == 1 && pa->pick_internal_oligo == 0
&& pa->pick_right_primer == 0
&& sa->left_input)
|| (pa->pick_left_primer == 0 && pa->pick_internal_oligo == 0
&& pa->pick_right_primer == 1
&& sa->right_input)
|| (pa->pick_left_primer == 0 && pa->pick_internal_oligo == 1
&& pa->pick_right_primer == 0
&& sa->internal_input))) {
/* print first row of header */
if(pa->thermodynamic_oligo_alignment==0)
fprintf(f, format, "", "con", "too", "in", "in", "not", "", "no",
"tm", "tm", " high", "high");
else
fprintf(f, format, "", "con", "too", "in", "in", "not", "", "no",
"tm", "tm", " high", "high");
if(pa->thermodynamic_oligo_alignment==1)
fprintf(f, "%6s", "high");
if(print_lib_sim)
fprintf(f, "%6s", "high");
fprintf(f, "%6s%6s", "", "high");
if(pa->lowercase_masking)
fprintf(f, "%6s", "lower");
fprintf(f, "%6s\n", "");
/* print second row of header */
if(pa->thermodynamic_oligo_alignment==0) {
fprintf(f, format, "", "sid", "many", "tar", "excl", "ok", "bad","GC",
"too", "too", "any", "3'");
} else {
fprintf(f, format, "", "sid", "many", "tar", "excl", "ok", "bad","GC",
"too", "too", " any_th", "3'_th");
fprintf(f, "%6s", "hair-");
}
if(print_lib_sim)
fprintf(f, "%6s", "lib");
fprintf(f, "%6s%6s", "poly", "end");
if(pa->lowercase_masking)
fprintf(f, "%6s", " case");
fprintf(f, "%6s\n", "");
/* print third row of header */
if(pa->thermodynamic_oligo_alignment==0)
fprintf(f, format, "", "ered","Ns", "get", "reg", "reg", "GC%", "clamp",
"low", "high"," compl", "compl");
else
fprintf(f, format, "", "ered","Ns", "get", "reg", "reg", "GC%", "clamp",
"low", "high"," compl", "compl");
if(pa->thermodynamic_oligo_alignment==1)
fprintf(f, "%6s", " pin");
if(print_lib_sim)
fprintf(f, "%6s", "sim");
fprintf(f, "%6s%6s", "X", "stab");
if(pa->lowercase_masking)
fprintf(f, "%6s", " end");
if(pa->lowercase_masking)
fprintf(f, "%6s\n", "ok ");
else
fprintf(f, "%6s\n", "ok");
}
if (pa->pick_left_primer == 1
&& !(pa->pick_anyway && sa->left_input))
print_stat_line(f, "Left", retval->fwd.expl,
print_lib_sim, pa->lowercase_masking, pa->thermodynamic_oligo_alignment);
if (pa->pick_right_primer == 1
&& !(pa->pick_anyway && sa->right_input))
print_stat_line(f, "Right", retval->rev.expl,
print_lib_sim, pa->lowercase_masking, pa->thermodynamic_oligo_alignment);
if (pa->pick_internal_oligo == 1
&& !(pa->pick_anyway && sa->internal_input))
print_stat_line(f, "Intl", retval->intl.expl,
print_lib_sim, pa->lowercase_masking, pa->thermodynamic_oligo_alignment);
if (pa->pick_left_primer == 1 && pa->pick_right_primer == 1) {
fprintf(f, "Pair Stats:\n%s\n",
p3_get_pair_array_explain_string(p3_get_rv_best_pairs(retval)));
}
fprintf(f, "%s\n", pr_release);
}
static void
print_stat_line(FILE *f, const char *t, oligo_stats s,
int print_lib_sim, int lowercase_masking,
int thermodynamic_oligo_alignment)
{
const char *format = "%-6s%6d%6d%6d%6d%6d%6d%6d%6d%6d";
if (!strcmp(t, "Left"))
fprintf(f,format, t, s.considered, s.ns, s.target, s.excluded,
s.not_in_any_left_ok_region, s.gc, s.gc_clamp, s.temp_min, s.temp_max);
else if (!strcmp(t, "Right"))
fprintf(f,format, t, s.considered, s.ns, s.target, s.excluded,
s.not_in_any_right_ok_region, s.gc, s.gc_clamp, s.temp_min, s.temp_max);
else fprintf(f,format, t, s.considered, s.ns, s.target, s.excluded,
0, s.gc, s.gc_clamp, s.temp_min, s.temp_max);
if(thermodynamic_oligo_alignment) {
fprintf(f, " %6d%6d%6d", s.compl_any, s.compl_end, s.hairpin_th);
} else {
fprintf(f, "%6d%6d", s.compl_any, s.compl_end);
}
if (print_lib_sim) fprintf(f, "%6d",s.repeat_score);
fprintf(f, "%6d%6d",s.poly_x, s.stability);
if (lowercase_masking) fprintf(f, "%6d",s.gmasked);
fprintf(f, "%6d\n", s.ok);
}
/*
* Return true iff a check for library similarity has been specified for
* either the primer pair or the internal oligo.
*/
static int
lib_sim_specified(const p3_global_settings *pa) {
return (pa->p_args.repeat_lib || pa->o_args.repeat_lib);
}
void
format_error(FILE *f, const char* seq_name, const char *err)
{
if (NULL != seq_name)
fprintf(f, "PRIMER PICKING RESULTS FOR %s\n\n", seq_name);
if (err != NULL)
fprintf(f, "INPUT PROBLEM: %s\n\n", err);
}
void
format_warning(FILE *f, const char* seq_name, const char *err)
{
if (NULL != seq_name)
fprintf(f, "WARNINGS FOR %s\n\n", seq_name);
if (err != NULL)
fprintf(f, "INPUT PROBLEM: %s\n\n", err);
}
/* Format and print out one oligo */
static void
format_oligos(FILE *f,
const p3_global_settings *pa,
const seq_args_t* sa,
const p3retval *retval,
const char* pr_release,
const pr_append_str *combined_retval_err,
int explain_flag)
{
char *warning;
int print_lib_sim = lib_sim_specified(pa);
int i;
int print_primers = 0;
primer_rec *h = NULL;
pair_array_t *best_pairs;
primer_rec *p;
int rest_count = 0;
PR_ASSERT(NULL != f);
PR_ASSERT(NULL != pa);
PR_ASSERT(NULL != sa);
best_pairs = NULL;
if (!pr_is_empty(combined_retval_err)) {
format_error(f, sa->sequence_name, pr_append_str_chars(combined_retval_err));
return;
}
if (NULL != sa->sequence_name)
fprintf(f, "PRIMER PICKING RESULTS FOR %s\n\n", sa->sequence_name);
if (pa->pick_left_primer || pa->pick_right_primer) {
if (pa->p_args.repeat_lib != NULL)
fprintf(f, "Using mispriming library %s\n",
pa->p_args.repeat_lib->repeat_file);
else
fprintf(f, "No mispriming library specified\n");
}
if (pa->pick_internal_oligo) {
if (pa->o_args.repeat_lib != NULL)
fprintf(f, "Using internal oligo mishyb library %s\n",
pa->o_args.repeat_lib->repeat_file);
else
fprintf(f, "No internal oligo mishyb library specified\n");
}
fprintf(f, "Using %d-based sequence positions\n",
pa->first_base_index);
if (pa->pick_left_primer) {
if (retval->fwd.num_elem == 0){
fprintf(f, "NO LEFT PRIMER FOUND\n\n");
} else {
print_primers = 1;
}
}
if (pa->pick_internal_oligo) {
if (retval->intl.num_elem == 0){
fprintf(f, "NO INTERNAL OLIGO FOUND\n\n");
} else {
print_primers = 1;
}
}
if (pa->pick_right_primer) {
if (retval->rev.num_elem == 0){
fprintf(f, "NO RIGHT PRIMER FOUND\n\n");
} else {
print_primers = 1;
}
}
if ((warning = p3_get_rv_and_gs_warnings(retval, pa)) != NULL) {
fprintf(f, "WARNING: %s\n\n", warning);
free(warning);
}
if ((pa->primer_task != pick_primer_list )
&& (pa->primer_task != pick_sequencing_primers) ) {
if (print_primers == 1) {
print_oligo_header(f, "OLIGO", print_lib_sim, pa->thermodynamic_oligo_alignment);
}
/* Print out the first line with the best primers */
if ((pa->pick_left_primer) && (retval->fwd.oligo != NULL )
&& (retval->fwd.num_elem > 0) ) {
print_oligo(f, "LEFT_PRIMER", sa, retval->fwd.oligo, FORWARD,
pa, pa->p_args.repeat_lib, print_lib_sim);
h = retval->fwd.oligo;
rest_count = 1;
}
if ((pa->pick_internal_oligo) && (retval->intl.oligo != NULL)
&& (retval->intl.num_elem > 0) ) {
print_oligo(f, "INTERNAL_OLIGO", sa, retval->intl.oligo, FORWARD,
pa, pa->p_args.repeat_lib, print_lib_sim);
h = retval->intl.oligo;
rest_count = 1;
}
if ((pa->pick_right_primer) && (retval->rev.oligo != NULL)
&& (retval->rev.num_elem > 0) ) {
print_oligo(f, "RIGHT_PRIMER", sa, retval->rev.oligo, REVERSE,
pa, pa->p_args.repeat_lib, print_lib_sim);
h = retval->rev.oligo;
rest_count = 1;
}
}
if(print_primers == 1) {
fprintf(f, "SEQUENCE SIZE: %ld\n", (long int) strlen(sa->sequence));
fprintf(f, "INCLUDED REGION SIZE: %d\n\n", sa->incl_l);
print_pair_array(f, "TARGETS", sa->tar2.count, sa->tar2.pairs, pa, sa);
print_pair_array(f, "EXCLUDED REGIONS", sa->excl2.count, sa->excl2.pairs, pa, sa);
print_pair_array(f, "INTERNAL OLIGO EXCLUDED REGIONS",
sa->excl_internal2.count, sa->excl_internal2.pairs, pa, sa);
print_2_pair_array(f, "PAIR_OK_REGIONS", sa->ok_regions.count, sa->ok_regions.left_pairs,
sa->ok_regions.right_pairs, pa, sa);
}
if (pa->primer_task != pick_primer_list ) {
if (print_seq(f, pa, sa, retval, h, best_pairs, 0)) exit(-2); /* ENOMEM */
}
fprintf(f, "\n");
/* Print out the other primers */
if ((pa->pick_left_primer) && (retval->fwd.oligo != NULL)
&& (retval->fwd.num_elem > rest_count) ) {
int n = retval->fwd.num_elem;
h = retval->fwd.oligo;
if (rest_count == 1) {
fprintf(f, "ADDITIONAL OLIGOS\n");
}
fprintf(f, " "); print_oligo_header(f, "", print_lib_sim, pa->thermodynamic_oligo_alignment);
for (i = rest_count; i < pa->num_return; i++) {
if(i > n-1) break;
p = h + i;
fprintf(f, "%2d ", i + 1 - rest_count);
print_oligo(f, "LEFT_PRIMER", sa, p, FORWARD, pa,
pa->p_args.repeat_lib, print_lib_sim);
}
if (rest_count == 0) {
fprintf(f, "\n ");
}
}
if ((pa->pick_internal_oligo) && (retval->intl.oligo != NULL )
&& (retval->intl.num_elem > rest_count) ) {
int n = retval->intl.num_elem;
h = retval->intl.oligo;
if (rest_count == 1) {
fprintf(f, "ADDITIONAL OLIGOS\n");
}
fprintf(f, " "); print_oligo_header(f, "", print_lib_sim, pa->thermodynamic_oligo_alignment);
for (i = rest_count; i < pa->num_return; i++) {
if(i > n-1) break;
p = h + i;
fprintf(f, "%2d ", i + 1 - rest_count);
print_oligo(f, "INTERNAL_OLIGO", sa, p, FORWARD, pa,
pa->p_args.repeat_lib, print_lib_sim);
}
if (rest_count == 0) {
fprintf(f, "\n ");
}
}
if ((pa->pick_right_primer) && (retval->rev.oligo != NULL)
&& (retval->rev.num_elem > rest_count) ) {
int n = retval->rev.num_elem;
h = retval->rev.oligo;
if (rest_count == 1) {
fprintf(f, "ADDITIONAL OLIGOS\n");
}
fprintf(f, " "); print_oligo_header(f, "", print_lib_sim, pa->thermodynamic_oligo_alignment);
for (i = rest_count; i < pa->num_return; i++) {
if(i > n-1) break;
p = h + i;
fprintf(f, "%2d ", i + 1 - rest_count);
print_oligo(f, "RIGHT_PRIMER", sa, p, REVERSE, pa,
pa->p_args.repeat_lib, print_lib_sim);
}
}
if (explain_flag)
print_explain(f, pa, sa, retval, print_lib_sim, pr_release);
fprintf(f, "\n\n");
if (fflush(f) == EOF) {
perror("fflush(f) failed");
exit(-1);
}
}
primer3-py-2.3.1/primer3/src/libprimer3/format_output.h 0000664 0000000 0000000 00000005004 15247271707 0023040 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 1996,1997,1998,1999,2000,2001,2004,2006,2007
Whitehead Institute for Biomedical Research, Steve Rozen
(http://purl.com/STEVEROZEN/), Andreas Untergasser and Helen Skaletsky
All rights reserved.
This file is part of primer3.
Primer3 and the libprimer3 library are free software;
you can redistribute them and/or modify them under the terms
of the GNU General Public License as published by the Free
Software Foundation; either version 2 of the License, or (at
your option) any later version.
This software is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this file (file gpl-2.0.txt in the source
distribution); if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef PR_FORMAT_OUTPUT_H
#define PR_FORMAT_OUTPUT_H 1
#include "libprimer3.h"
/*
* Format the pair in p (plus the middle oligo if appropriate)
* on f. If p->product_size = 0 then primer choice failed.
* Both functions may exit on error, using the conventions
* in primer3_boulder_main.c
*/
void print_format_output(FILE *f,
const int *io_version,
const p3_global_settings *pa,
const seq_args_t* sa,
const p3retval *,
const char *,
int explain_flag);
void format_error(FILE *f, const char* seq_name, const char *err);
void format_warning(FILE *f, const char* seq_name, const char *err);
#endif
primer3-py-2.3.1/primer3/src/libprimer3/gpl-2.0.txt 0000664 0000000 0000000 00000043103 15247271707 0021601 0 ustar 00root root 0000000 0000000 GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
Copyright (C)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.
primer3-py-2.3.1/primer3/src/libprimer3/humrep_and_simple.txt 0000664 0000000 0000000 00000307047 15247271707 0024227 0 ustar 00root root 0000000 0000000 >ALU Human ALU interspersed repetitive sequence - a consensus
GGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAAAA
>MIR mammalian-wide interspersed repeat (MIR) - a consensus
ACAGYAYAGCATAGTGGTTAAGAGCACGGRCTCTGGAGCCAGACTGCCTGGGTTCGAATCCCGGCTCTGCCACTTACTAGCTGTGTGACCTTGGGCAAGTTACTTAACCTCTCTGTGCCTCAGTTTCCTCATCTGTAAAATGGGGATAATAATAGTACCTACCTCATAGGGTTGTTGTGAGGATTAAATGAGTTAATAYATGTAAAGCGCTTAGAACAGTGCCTGGCACATAGTAAGCGCTCAATAAATGTTRGYTATTATT
>MIR2 Repetitive element - a consensus
TTNTTTATTGTCTGTCTCCTCCACTAGANTGTAAGCTCCATGAGGGCAGGGATTTTGTCTGTYTTGTTCACTGCTGTATCCCCAGCGCCTAGAACAGTGCCTGGCACATAGTAGGCGCTCAATAAATATTTGTTGAATGAATGAATGAAT
>L1 Human L1 interspersed repetitive sequence - full length copy
GGCGGTGGAGCCAAGATGACCGAATAGGAACAGCTCCAGTCTATAGCTCCCATCGTGAGTGACGCAGAAGACGGGTGATTTCTGCATTTCCAACTGAGGTACCAGGTTCATCTCACAGGGAAGTGCCAGGCAGTGGGTGCAGGACAGTAGTGCAGTGCACTGTGCATGAGCCGAAGCAGGGCGAGGCATCACCTCACCCGGGAAGCACAAGGGGTCAGGGAATTCCCTTTCCTAGTCAAAGAAAAGGGTGACAGATGGCACCTGGAAAATCGGGTCACTCCCGCCCTAATACTGCGCTCTTCCAACAAGCTTAACAAATGGCACACCAGGAGATTATATCCCATGCCTGGCTCAGAGGGTCCTACGCCCATGGAGCCTCGCTCATTGCTAGCACAGCAGTCTGAGGTCAAACTGCAAGGTGGCAGTGAGGCTGGGGGAGGGGTGCCCACCATTGTCCAGGCTTGAGCAGGTAAACAAAGCCGCCTGGAAGCTCGAACTGGGTGGAGCCCACCACAGCTCAAGGAGGCCTGCCTGCCTCTGTAGGCTCCACCTCTAGGGGCAGGGCACAGACAAACAAAAGACAACAAGAACCTCTGCAGACTTAAATGTCCCTGTCTGACAGCTTTGAAGAGAGTAGTGGTTCTCCCAGCACATAGCTTCAGATCTGAGAACAGGCAGACTGCCTCCTCAAGTGGGTCCCTGACCCCCGAGTAGCCTAACTGGGAGGCATCCCCCAGTAGGGCGGACTGACACCTCACATGGCTGGTACTCCTCTAAGACAAAACTTCCAGAGGAATGATCAGGCAGCAGCATTTGCGGTTCACCAATATCCACTGTTCTGCAGCCACCGCTGCTGATACCCAGGAAAACAGCATCTGGAGTGGACCTCCAGTAAACTCCAACAGACCTGCAGCTGAGGGTCCTGACTGTTAGAAGGAAAACTAACAAACAGAAAGGACATCCACACCAAAAACCCATCTGTACATCACCATCATCAAAGACCAAAGGTAGATAAAACCATAAAGATGGGGAAAAAGCAGAGCAGAAAAACTGGACACTCTAAAAATGAGAGTGCCTCTCCTTCTCCAAAGTAACGCAGCTCCTCACCAGCAATGGAACAAAGCTGGGCAGAGAATGACTTTGACGAGTTGAGAGAGGAAGGCTTCAGAAGATCAAACTACTCCAAGCTAAAGGAGGAAGTTCGAACAAACGGCAAAGAAGTAAAAAACTTTGAAAAAAAATTAGATGAATGGATAACTAGAATAACCAATGCACAGAAGTCCTTAAAGGACCTGATGGAGCTGAAAACCAAGGCAGGAGAACTACGTGACAAATACACAAGCCTCAGTAACCGATGAGATCAACTGGAAGAAAGGGTATCAATGACGGAAGATGAAATGAATGAAATGAAGCATGAAGAGAAGTTTAGAGAAAAAAGAATAAAAAGAAACGAACAAAGCCTCCAAGAAATATGGGACTATGTGAAAAGACCAAATCTACATCTAATTGGTGTAGCTGAAAGTGATGGGGAGAATGGAACCAAGTTGGAAAACACTCTGCAGGATATTATCCAGGAGAACTTCCCCAATCTAGCAAGGCAGCCCAAATTCACATTCAGGAAATACAGAGAACGCCACAAAGATACTCCTAGAGAAAAGCAACTCCAAGACACATAACTGACAGATTCACCAAAGTTGAAATGAAGGAAAAAATGTTAAGGGCAGCCAGAGAGAAAGGTCGGGTTACCCACAAAGGGAAGCCCATCAGACTAACAGCTGATCTATCGGCAGAAACTCTACAAGCCAGAAGAAAGTGGGGGCCAATATTCAACATTGTTAAAGAAAAGAATTTTCGGCCCAGAATTTCATATCCAGCCAAACTAAGCTTCATAAGCATTGGAGAAATAAAATCCTTTACAGACAAGCAAATGCTGAGAGATTTTGTCACCACCAGGCCTGCCCTACAAGAGCTCCTGAAGGAAGCACTAAACATGGAAAGGAACAACTAGTATCAGCCACTGCAAAAACATGCCAAATTGTAAACGACCATCAAGGCTAGGAAGAAACTGCATCAAGGAGCAAAATAACCAGCTAACATCATAATGACAGGATCAAATTCATACATAACAATACTCACCTTAAATGTAAATAGGCTAAATGCTCCAATTAAAAGACACAGACTGGCAAATTGGATAAGGAGTCAAGACCCATCTGTCGTTATGTATTCAGGAAACCCATCTCACGTGCAGAGACACACATAGGCTCGAAATAAAAGGATGGAGGAATATCTACCAAGCAAATGGAAAACAAAAAAAGGCAGGGGTTGCAATCCTAGTCTCTGATAAAACAGATTTTAAACCAACAAAGATCAAAAGAGACAAAGAAGGCCATTACATAATGGCAAAGGGATCTATTCAAGAAGAAGAACTAACTATACTAAATATATATGCACCCAATACAGGAGCACCCAGATTCATAAAACAAGTCCTGAGTGACCTACAAAGAGACTTAGATGCCCACACAATAATAATGGGAGACTTTAACACCCCACTGTCAACATTAGACAGATCAACGAGACAGAAAGTTAACAAGGATATCCAGGAATTGGACTCAGCTCTGCACCAAGCAGACCTAATAGACATCTACAGAACTCTCCACCCCAAATCAACAGAATATACATTCTTTTCAGCACCACACCACACCTATTCCAAAACTGACCACATAGTTGGAAGTAAAGCTCTCCTCAGCAAATGTAAAAGAACAGAAACTATAACAAACTGTCTCTCAGACCACAGTGCAATCAAACTAGAACTCAGGATTAAGAAACTCACTCAAAACCACTCAGCTACATGGAAACTGAACAGCCTGCTCCTGAATGACTACTGGGTACATAACAAAATGAAGGCAGAAATAAAGATGTTCTTTGAAACAACGAGAACAAAGACACAACACACCAGAATCTCTGAGACACATTCAAAGCAGTGTGTAGAGGGAAATTTATAGCACTAAATGCCCACAAGGGAAAGCAGGAAAGATCTAAAATTGACACCCTAACATCACAATTAAAAAACTAGAGAAGCAGGAGCAAACACATTCAAAAGCTAACAGAAGACAAGAAATAACTAAGATCAGAGCAGAAGTGAAGAAGATAGAGACACAAAAAACCCTTCAAAAAAATCAATGAATCCAGAAGCTGTTTTTTTGAAAAGATCAACAAAATTGATAGACTGCTAGCAAGACTAATAAAGAAGAAAGGGGAGAAGAATCAAATAGACGCAATAAAAAATGACACGGGGTATCACCACTGATCCCACAGAAATACAAACTACCGTCAGAGAATACTATAAACACCTCTACGCAAATAAACTAGAAAATCTAGAAGAAATGGATAAATTCCTCGACACATACACTCTGCCAAGACTAAACCAGGAAGAAGTTGTATCTCTGAATAGACCAATAACAGGCTCTGAAATTGAGGCAATAATTAATAGCTTATCAACCAAAAAAAGTCCGGGACCAGTAGGATTCATAGCCGAATTCTACCAGAGGTACAAGGAGGAGCTGGTACCATTCCTTCTGAAACTATTCCAATCAATAGAAAAAGAGGGAATCCTCCCTAACTCATTTTATGAGGCCAGCATCATCCTGATACCAAAGCCTGACAGAGACACAACAAAAAAAGAGAATGTTACACCAATATCCTTGATGAACATCGATGCAAAAATCCTCAATAAAATACTGGCAAACTGAATCCAGCAGCACATCAAAAAGCTTATCCTCCATGATCAAGTGGGCTTCATCCCTGCCATGCAAGGCTGGTTCAACATACGAAATCAATAAACATAATCCAGCATATAAACAGAACCAAAGACACAAACCATATGATTATCTCAATAGATGCAGAAAAGGCCTTTGACAAAATTCAACAATGCTTCATGCTAAAAACTCTCAATAAATTAGGTATTGATGGGACATATCTCAAAATAATAAGAGCTATCTATGACAAACCCACAGCCAATATCATACTGAGTGGACAAAAACTGGAAGCATTCCCTTTGAAAACTGGCACAAGGCAGGGATGCCCTCTCTCACCACTCCTATTCAACATAGTGTTGGAAGTTCTGGCCAGGGCAATCAGGCAGGAGAAGGAAATAAAGGGCATTCAATTAGGAAAAGAGGAAGGTGAAATTGTCCCTGTTTGCAGATGACATGATTGTATATCTAGAAAACCCCATTGTCTCAGCCCAAAATCTCCTTAAGCTGATAAGCAACTTCAGCAAAGTCTCAGGATATAAAATCAGTGTGCAAAAATCACAAGTATTCCTATGCACCAATAACAGACAAACAGAGAGCCAAATCATGAGTGAACTCCCATTCACAATTGCTTCAAAGAGAATAAAATACCTAGGAATCCAACTTACAAGGGATGTGAAGGACCTCTTCAAGGAGAACTACAAACCACTGCTCAATGAAATAAAAGAGGATACAAACAAATGGAAGAACATTCCATGCTTATGGGTAGGAAGAATCATATCGTGAAAATGGTCATACTGCCCAAGGTAATTTATAGATTCAATGCCATCCCCATCAAGCTACCAATGACTTTCTTCACAGAACTGGAAAAAACTACTTTAAAGTTCATATGGAATCAAAAAAGAGCCCACATCACCAAGGCAATCCTAAGCCAAAAGAACAAAGCTGGAGGCATCACGCTACCTGACTTCAAACTATACTACAATGCTACGGTAACCAAAACAGCATGGTACTGGTACCAAAACAGAGATCTAGACCAATGGAACAGAACAGAGCCCTCAGAAATAATGCCGCATATCTACAACTATCCGATCTTTGACAAACCTGAGAGAAACAAGCAATGGGGAAAGGATTCCCTATTTAATAAATGGTGCTGGGAAAACTGGCTAGCCATATGTAGAAAGCTGAAACTGGATCCTTCCTTACACCTTATACAAAAATTAATTCAAGATGGATTAAAGACTTAAACATTAGACCTAAAACCATAAAAACCCTAGAAAAAAACCTAGGCAATACCATTCAGGACATAGGCATGGGCAAGGACTTCATGTCTAAAACACCAAAACGAATGGCAACAAAAGACAAAATGGACAAACGGGATCTAATTAAACTAAAGAGCTTCTGCACAGCTAAAGAAACTACCATCAGAGTGAACAGGCAACCTACAAAATGGGAGAAAATTTTTGCAATCTACTCATCTGACAAAGGGCTAATATCCAGAATCTACAATGAACTCAAACAAATTTACAAGAAAAAACAAACAACCCCATCAAAAAGTGGGCAAAGGATATGAACAGACACTTCTCAAAAGAAGACATTTATGTAATCAAAAAACACATGAAAAAATGCTCATCATCACTAGCCATCAGAGAAATGCAAATCAAAACCACAATGAGATACCATCTCACACCAGTTAGAATGGCGATCATTAAAAAGTCAGGAAACAACAGGTGCTGGAGAGGATGTGGAGAAACAGGAACAACTTTTACACTGTTGGTGGGACTGTAAACTAGTTCAACCATTGCGGAAGTCAGTGTGGCAATTCCTCAGGAATCTAGAACTAGAAATACCATTTGACCCAGCCATCCCATTACTGGGTAGATACCCAAAGGATTATAAATCATGCTGCTATAAAGACACATGCACACGTATGTTTATTGCAGCACTATTCACAATAGCAAAGACTTGGAACCAACCCAAATGTCCAACAACGATAGATTGGATTAAGAAAATGTGGCACATATACACCATGGAATACTATGCAGCCATAAAAAATGATGAGTTCATGTCCTTTGTAGGGACATGGATGAAGCTGGAAACTATCATTCTCAGCAAACTATCACAAGGACAATAAACCAAACACCGCATGTTCTCACTCATAGGTGGGAATTGAACAATGAGAACACATGGACACATGAAGAGGAACATCACACTCTGGGGACTGTTATGGGGTGGGGGGCAGGGGCAGGGATAGCACTAGGAGATATACCTAATGCTAAATGACGAGTTAATGGGTGCAGCACACCAACATGGCACATGTATACATATATAACAAACCTGCCGTTGTGCACATGTACCCTAAAACTTGAAGTATAATAATAAAAAAAA
>L1PA2 3'-end of L1 repeat (subfamily L1PA2) - a consensus sequence
CTAATATCCAGAATCTACAATGAACTCAAACAAATTTACAAGAAAAAAACAAACAACCCCATCAAAAAGTGGGCGAAGGACATGAACAGACACTTCTCAAAAGAAGACATTTATGCAGCCAAAAAACACATGAAGAAATGCTCATCATCACTGGCCATCAGAGAAATGCAAATCAAAACCACTATGAGATATCATCTCACACCAGTTAGAATGGCAATCATTAAAAAGTCAGGAAACAACAGGTGCTGGAGAGGATGTGGAGAAATAGGAACACTTTTACACTGTTGGTGGGACTGTAAACTAGTTCAACCATTGTGGAAGTCAGTGTGGCGATTCCTCAGGGATCTAGAACTAGAAATACCATTTGACCCAGCCATCCCATTACTGGGTATATACCCAAAGGACTATAAATCATGCTGCTATAAAGACACATGCACACGTATGTTTATTGCGGCACTATTCACAATAGCAAAGACTTGGAACCAACCCAAATGTCCAACAATGATAGACTGGATTAAGAAAATGTGGCACATATACACCATGGAATACTATGCAGCCATAAAAAATGATGAGTTCATGTCCTTTGTAGGGACATGGATGAAATTGGAAATCATCATTCTCAGTAAACTATCGCAAGAACAAAAAACCAAACACCGCATATTCTCACTCATAGGTGGGAATTGAACAATGAGATCACATGGACACAGGAAGGGGAATATCACACTCTGGGGACTGTGGTGGGGTGGGGGGAGGGGGGAGGGATAGCATTGGGAGATATACCTAATGCTAGATGACGAGTTAGTGGGTGCAGCGCACCAGCATGGCACATGTATACATATGTAACTAACCTGCACAATGTGCACATGTACCCTAAAACTTAAAGTATAATAAAA
>L1PA7 3'-end of L1 repeat (subfamily L1PA7) - a consensus sequence
CTAATATCCAGAATCTACAAGGAACTTAAACAAATTTACAAGAAAAAAACAAACAACCCCATCAAAAAGTGGGCAAAGGATATGAACAGACACTTCTCAAAAGAAGACATTTATGYAGCCAACAAACAYATGAAAAAAAGCTCATCATCACTGGTCATTAGAGAAATGCAAATCAAAACCACAATGAGATACCATCTCAYGCCAGTTAGAATGGCGATCATTAAAAAGTCAGGAAACAACAGATGCTGGAGAGGATGTGGAGAAATAGGAATGCTTTTACACTGTTGGTGGGAGTGTAAATTAGTTCAACCATTGTGGAAGACAGTGTGGCGATTCCTCAAGGATCTAGAACCAGAAATACCATTTGACCCAGCAATCCCATTACTGGGTATATACCCAAAGGATTATAAATCATTCTRCTATAAAGACACATGCACACGTATGTTTATTGCAGCACTATTCACAATAGCAAAGACTTGGAACCAACCCAAATGCCCATCAATGATAGACTGGATAAAGAAAATGTGGCACATATACACCATGGAATACTATGCAGCCATAAAAAAGGATGAGTTCATGTCCTTTGCAGGGACATGGATGAAGCTGGAAACCATCATTCTCAGCAAACTAACACAGGAACAGAAAACCAAACACCGCATGTTCTCACTCATAAGTGGGAGTTGAACAATGAGAACACATGGACACAGGGAGGGGAACATCACACACCGGGGCCTGTCGGGGGGTGGGGGGCTAGGGGAGGGATAGCATTAGGAGAAATACCTAATGTAGATGACGGGTTGATGGGTGCAGCAAACCACCATGGCACATGTATACCTATGTAACAAACCTGCACGTTCTGCACATGTATCCCAGAACTTAAAGTATAATAATA
>L1PA11 3'-end of L1 repeat (subfamily L1PA11) - a consensus sequence
CTAATATCCAGAATSTACAARGAACTTAAACAAATTTACAAGAAAAAAACAAAMAACCCCATCAAAAAGTGGGCAAAGGACATGAACAGACACTTCTCAAAAGAAGACATWTATGTGGCCAATAAGCACATGAAAAAAAGCTCAACATCACTGATCATTAGAGAAATGCAAATCAAAACCACAATGAGATACCATCTCAYRCCAGTCAGAATGGCAATTATTAAAAAGTCAAGAAACAACAGATGCTGGYGAGGCTGTGGAGAAATAGGAATGCTTTTACACTGTTGGTGGGAATGTAAATTAGTTCAACCATTGTGGAAGACAGTGTGGCGATTCCTCAAGGATCTAGAACCAGAAATACCATTTGACCCAGCAATCCCATTACTGRGTATATACCCAAAGGAATATAAATCATTCTATTATAAAGACACATGCAYGTGTATGTTYATTGCAGCACTATTCACAATAGCAAAGACATGGAATCAACCYAAATGCCCATCAATGATAGACTGGATAAAGAAAATGTGGTACATATACACCATGGAATACTATGCAGCCATAAAAAAGAATGAGATCATGTCCTTTGCAGGAACATGGATGGAGCTGGAGGCCATTATCCTTAGCAAACTAAYGCAGGAACAGAAAACCAAATACCGCATGTTCTCACTTATAAGTGGGAGCTAAACGATGAGAACACATGGACACATGGAGGGGAACAACACACACTGGGGCCTGTCGGAGGGTGGAGGGTGGGAGGAGGGAGAGCATCAGGAAAAATAGCTAATGGATACTGGGCTTAATACCTGGGTGATGGGATGATCTGTGCAGCAAACCACCATGGCACACGTTTACCTATGTAACAAACCTGCACATCCTGCACATGTACCCCGGAACTTAAAATAAAAGTTGAAA
>L1PA15 3'-end of L1 repeat (subfamily L1PA15) - a consensus sequence
CTAATATCCAGAATSTACAARGAACTTAAACAAATTTACAAGAAAAAAACAAAMAACCCCATCAAAAAGTGGGCAAAGGACATGAACAGACACTTCTCAAAAGAAGACATWTATGTGGCCAATAAGCACATGAAAAAAAGCTCAACATCACTGATCATTAGAGAAATGCAAATCAAAACCACAATGAGATACCATCTCAYRCCAGTCAGAATGGCAATTATTAAAAAGTCAAGAAACAACAGATGCTGGYGAGGCTGTGGAGAAATAGGAATGCTTTTACACTGTTGGTGGGAATGTAAATTAGTTCAACCATTGTGGAAGACAGTGTGGCGATTCCTCAAGGATCTAGAACCAGAAATACCATTTGACCCAGCAATCCCATTACTGRGTATATACCCAAAGGAATATAAATCATTCTATTATAAAGACACATGCAYGTGTATGTTYATTGCAGCACTATTCACAATAGCAAAGACATGGAATCAACCYAAATGCCCATCAATGATAGACTGGATAAAGAAAATGTGGTACATATACACCATGGAATACTATGCAGCCATAAAAAAGAATGAGATCATGTCCTTTGCAGGAACATGGATGGAGCTGGAGGCCATTATCCTTAGCAAACTAAYGCAGGAACAGAAAACCAAATACCGCATGTTCTCACTTATAAGTGGGAGCTAAAYATTGAGTACACATGGACATAAAGAAGGGAACAACAGACACTGGGGCCTACTTGAGGGTGGAGGGTGGGAAGAGGGAGAGGATCAAAAAACTACCTATCGGGTACTATGCTTATTACCTGGGTGATGAAATAATCTGTACACCAAACCCCAGCGACACGCAATTTACCTATATAACAAACCTGCACATGTACCCCCTGAATCTAAAATAAAAGTTAAAA
>L1PB1 3'-end of L1 repeat (subfamily L1PB1) - a consensus sequence
CTAATATCCAGAATCTATAAGGAACTCAAACAAATCAGCAAGAAAAAAACAAACAATCCCATCAAAAAGTGGGCTAAGGACATGAAYAGACAMTTCTCAAAAGAAGATATRYAAATGGCCAACAAGCATATGAAAAAATGCTCAACATCACTAATTATCAGGGAAATGCAAATCAAAACCACAATGCRATACCATCTTACTCCTGCAAGAATGGCCATAATTAAAAAATCAAAAAATAATAGATGTTGGCGTGGATGTGGTGAAAAGGGAACACTTYTACACTGCTGGTGGGAATGTAAACTAGTACAACCACTATGGAAAACAGTATGGAGATTYCTTAAAGAACTAAAAGTAGAACTACCATTTGATCCAGCAATCCCACTACTGGGTATCTACCCARARGAAAAKAAGTCATTATAYGAAAAAGAYACTTGCACACRCATGTTTATAGCAGCACAATTYRCAATTGCAAAAATATGGAACCAACCCAAATGCCCATCAATCAAYRAGTGGATAAAGAAAATGTGRTATATATATACCATGGAATACTACKCAGCCATAAAAAAGAATGAAATAATGGCATTTGCAGCAACCTGGATGGARYTGGAGACYATTATTCTAAGTGAAGTAACTCAGGAATGGAAAACCAAACATYRTATGTTCTCACTTATAAGTGGGAGCTAAGCTATGAGGATGCAAAGGCGTAAGAATGATACAATGGACTTTGGGGACTCGGGAGATCGGGRGAAAGGGTGGGAGGGGGGTGAGGGATAAAAGACTACAAATTGGGTACAGTGTACACTGCTCGGGTGATGGGTGCACCAAAATCTCACAAATCACCACTAAAGAACTTATTCATGTAACCAAACACCACCTGTTCCCCAAAAACCTATTGAAATAAA
>L1PB3 3'-end of L1 repeat (subfamily L1PB3) - a consensus sequence
CTAATATCCAGAATCTATAAGGAACTCAAACAAATCAGCAAGAAAAAAACAAACAATCCCATCAAAAAGTGGGCTAAGGACATGAAYAGACAMTTCTCAAAAGAAGATATRYAAATGGCCAACAAGCATATGAAAAAATGCTCAACATCACTAATTATCAGGGAAATGCAAATCAAAACCACAATGCRATACCATCTTACTCCTGCAAGAATGGCCATAATTAAAAAATCAAAAAATAATAGATGTTGGCGTGGATGTGGTGAAAAGGGAACACTTYTACACTGCTGGTGGGAATGTAAACTAGTACAACCACTATGGAAAACAGTATGGAGATTYCTTAAAGAACTAAAAGTAGAACTACCATTTGATCCAGCAATCCCACTACTGGGTATCTACCCARARGAAAAKAAGTCATTATAYGAAAAAGAYACTTGCACACRCATGTTTATAGCAGCACAATTYRCAATTGCAAAAATATGGAACCAACCCAAATGCCCATCAATCAAYRAGTGGATAAAGAAAATGTGRTATATATATACCATGGAATACTACKCAGCCATAAAAAAGAATGAAATAATGGCATTTGCAGCAACCTGGATGGARYTGGAGACYATTATTCTAAGTGAAGTAACTCAGGAATGGAAAACCAAACATYRTATGTTCTCACTTATAAGTGGGAGCTAAGCTATGGGTATATACGGGCATATAGAGTGGTATAATAGACAYTGGAGACTCAAAAGGTGGAGGGTAGGAGAGGGGTGAGGGATGAAAAATTACCTATTGGGTACAATGTWCACTATTCGGGTGATGGGTACACTAAAAGCCCAGACTTCACCACTAYACAATATATCCATGTAACAAAAAKGCACYTGTACCCCCTAAATYTATAAAAATAAA
>L1MA2 3'-end of L1 repeat (subfamily L1MA2) - a consensus sequence
YTAATATCCAGAATMTATAAGGAACTCAAACAAATCAACAAGAAAAAAACAAATAATCCMATTAAAAARTGGGCAAAAGACATGAAYAGACATTTCTCAAAAGAAGACATACAAATGGCCAACARGYATATGAAAAAATGCTCAACATCACTAATCATCAGAGAAATGCAAATCAAAACYACAATGAGATATCATCTCACCCCAGTTARAATGGCTTTTATTAAAAAGACAAAAAATAACARATGCTGGYGAGGATGTGGAGAAAAGGGAACTCTTAYAYACTGTTGGTGGGAATGTAAATTAGTACARCCAYTATGGAAAACAGTTTGGAGRTTYCTCAAAAAACTAAAAATAGARCTACCATATRATCCAGCAATCCCACTRCTGGGTATATAYCCAAAAGAAAGGAAATCAGTATATYAAARAGATACCTGCACTCCCATGTTTATTGCAGCACTATTCACAATAGCHAAGATTTGGAATCAACCTAAGTGTCCATCAACRGATGAATGGATAAAGAAAATGTGGTACATATACACAATGGAGTACTATTCAGCCATAAAAAAGAATGARATCYTGTCATTTGCAGCAACATGGATGGAACTGGAGGTCATTATGTTAAGTGAAATAAGYCARGMACARAAAGACAAACAYTGCATGTTCTCACTTATTTGTGGGATCTAAAAATCAAAACAATTGAACTCATGGAGATAGAGAGTAGAAGGATGGTTACCAGAGGCTGGGAAGGGTAGTNGGAGGATTGGGGGGNGGKGRRGAGGGATGGTTAATGGGTACAAAAAAATAGTTAGAAAGAATGAATAAGACCTAGTATTTGATAGCACAACAAGGTGACTATAGTCAATAATAATTTAATTGTACATTTTAAAATAACTAAAAGAGTATAATTGGATTGTTTGTAACACAAAGGATAAATGCTTGAGGGGATGGATACCCCATTTTCCATGATGTGATTATTACACATTGCGTGCCTGTATCAAAACATCTCATGTACCCCATAAATATATACACCTACTATGTACCCACAAAAATTAAAA
>L1MA5 3'-end of L1 repeat (subfamily L1MA5) - a consensus sequence
TTAATATCCAAAATATATAAGGAACTCAAACAACTCAACAAGAARAAAACAAATAACCCAATTAAAAAATGGGCAAARGACCTGAATAGACATTTYTCAAAAGAAGACATACAAATGGCCAACAGATATATGAAAAAATGCTCAACATCACTAATCATCAAGGAAATGCAAATTAAAACCACAATGAGATATCACCTCACACCTGTTAGAATGGCTATTATCAAAAAGACAGAAAATAATAAATGTTGGYGAGGATGTGGAGAAAAGGGAACTATTGTACACTGTTGGTGGGAATGTAAATTAGTAYAGCCAYTATGGAAAACAGTATGGAGGTTCCTCAAAAAAYTAAAAATARAACTACCATATGATYCAGCAATCCCACTWCTGGGTATATATCCAAARGAATTGAAATCAGTATGTYGAAGAGATAYCTGCACTCCCATGTTTAYTGCAGCAYTATTCACAATAGCCAAGATATGGAAWCAACCTAAGTGTCCATCAAYGGAWGAATGGATAAAGAAAATGTGGTATATATACACAATGGAATACTATTCAGCCATAAAAAAGAATGAAATCCTGTCATTTGYARCAACATGGATGAACCTGGAGGACATTATGCTAAGTGAAATAAGCCAGGCACAGAAAGACAAATACCGCATGTTCTCACTCATATGTGGAAGCTAAAAAAGTTGATCTCATAGAAGTAGAGAGTAGAATAGTGGTTACTAGAGGCTGGGAAGGGTAGGGRGAGGGGGGRATAGGGAGAGGTTGGTTAAWGGRTACAAAATTACAGTTAGATAGGAGGAATAAGTTCTAGTGTTCTGTAGCACCGTAGGGTGACTATAGTTAACAAYAATTTATTGTATATTTTCAAATAGCTAGAAGAGAGGATTTTGAATGTTCCCAACACAAAGAAATGATAAATGTTTGAGGTGATGGATATGCTAATTACCCTGATTTGATCATTACACAWTGTATACATGTATCGAAATATCACACTGTACCCCATAAATATGTACAATTATTATGTGTCAATTAAAAA
>L1MA9 3'-end of L1 repeat (subfamily L1MA9) - a consensus sequence
TTAATATCCAAAATATATAAGGAACTCAAACAACTCAACAAGAARAAAACAAATAACCCAATTAAAAAATGGGCAAARGACCTGAATAGACATTTYTCAAAAGAAGACATACAAATGGCCAACAGATATATGAAAAAATGCTCAACATCACTAATCATCAAGGAAATGCAAATTAAAACCACAATGAGATATCACCTCACACCTGTTAGAATGGCTATTATCAAAAAGACAGAAAATAATAAATGTTGGYGAGGATGTGGAGAAAAGGGAACTATTGTACACTGTTGGTGGGAATGTAAATTAGTAYAGCCAYTATGGAAAACAGTATGGAGGTTCCTCAAAAAAYTAAAAATARAACTACCATATGATYCAGCAATCCCACTWCTGGGTATATATCCAAARGAATTGAAATCAGTATGTYGAAGAGATAYCTGCACTCCCATGTTTAYTGCAGCAYTATTCACAATAGCCAAGATATGGAAWCAACCTAAGTGTCCATCAAYGGAWGAATGGATAAAGAAAATGTGGTATATATACACAATGGAATACTATTCAGCCATAAAAAAGAATGAAATCCTGTCATTTGYARCAACATGGATGAACCTGGAGGACATTATGCTAAGTGAAATAAGCCAGGCACAGAAAGACAAATACTGCATGATCTCACTTATATGTGGAATCTAAAAAAGTCAAAYTCATAGAAACAGAGAGTAGAATGGTGGTTACCAGGGGCTGGGGRAKGGGGGAAATGGGAAGATGTTGGTCAAAGGGTACAAAGTTKCAGTTATGTARGATGAATAAGTTCTRGAGAYCTAATGTACAGCATGGTGACTATAGTTAATAATACTGTATTGTATACTTGAAATTTGCTAAGAGAGTAGATYTTAAGTGTTCTCACCACANACAAATGGTAACTATGTGAGGTGATGGATATGTTAATTAGCTTGAYTGTGGTAATCATTTCACAATGTATACATATATCAAAACATCACGTTGTACACCTTAAATATATACAATTTTTATTTGTCAATTATACCTCAATAAAGCTGRAAA
>L1MA10 3'-end of L1 repeat (subfamily L1MA10) - a consensus sequence
TTAATATCCAAAATATATAAAGAACTCYTACAACTCAACAAAAAAAAAACAAACAACCCAATTAAAAAATGGGCAAARGACTTGAATAGACATTTCTCCAAAGAAGAYATAYAAATGGCCAATAAGYACATGAAAARATGCTCAACATCAYTAATCATTAGGGAAATGCAAATCAAAACCACAATGAGATAYCACCTYACACCCATTAGGATGGCTATTATYAAAAAAMCAGAAAATAACAAGTGTTGRYGAGGATGTGGAGAAATTGGAACCCTTRTRCATTGCTGGTGGGAATGTAAAATGGTRCARCCACTRTGGAAAACAGTATGGHRGTTCCTCAAAAAATTAAAAATAGAATTACCATATGACCCAGCAATYCCACTYCTRGGTATATACCCAAAAGAATTGAAATCATGTTCYYAHAAAGATAYTTGTACACCMATGTTCATAGCAGCATTATTCAYAATAGCCAAAAGGTGGAAACAACCCAAATGTCCATCAATGRWTGAATGGATAAACAAAATGTGGTATATACATACAATGGAATATTATTCAGCCTTAAAAAGGAAGGAAATYCTGACAYATGCTACAACATGGATGAACCTTGARGACATTATGCTAAGTGAAATAAGCCAGTCACAAAAGGACAAATACTGCATGATTCCACTTATATGAGGTATCTAAAATAGTCAAACTCATAGAARCAGAGAGTAGAATGGTGGTTGCCAGGGGCTGGGGGRAGGGGGAAATGGGGAGTTGCTGTTCAATGGGTATAAAGTTTCAGTTATGCAAGATGAATAAGTTCTAGAGATCTGCTGTACAACATTGTGCCTATAGTTAATAATACTGTATTGTACACTTAAAAWTTGTTAAAAGRGTAGATCTCATGTTAAGTGTTCTTATCGCACAACAAAAAAATGGGGAACTTTTGGRRGTGATGGATATGTTCATTATCTTGATTGTGGTGATGGTWTCACGGGTGTNTACATATGTCAAAACTCATCAAATTGTACACWTTAAATATATGCAGTTTTTAGTGTATAATTATACCTCAACAAAGCTGTTTT
>L1MB3 3'-end of L1 repeat (subfamily L1MB3) - a consensus sequence
TTAATATCCAAAATATATAAAGAACTCYTACAACTCAACAAAAAAAAAACAAACAACCCAATTAAAAAATGGGCAAARGACTTGAATAGACATTTCTCCAAAGAAGAYATAYAAATGGCCAATAAGYACATGAAAARATGCTCAACATCAYTAATCATTAGGGAAATGCAAATCAAAACCACAATGAGATAYCACCTYACACCCATTAGGATGGCTATTATYAAAAAAMCAGAAAATAACAAGTGTTGRYGAGGATGTGGAGAAATTGGAACCCTTRTRCATTGCTGGTGGGAATGTAAAATGGTRCARCCACTRTGGAAAACAGTATGGHRGTTCCTCAAAAAATTAAAAATAGAATTACCATATGACCCAGCAATYCCACTYCTRGGTATATACCCAAAAGAATTGAAATCATGTTCYYAHAAAGATAYTTGTACACCMATGTTCATAGCAGCATTATTCAYAATAGCCAAAAGGTGGAAACAACCCAAATGTCCATCAATGRWTGAATGGATAAACAAAATGTGGTATATACATACAATGGAATATTATTCAGCCTTAAAAAGGAAGGAAATYCTGACAYATGCTACAACATGGATGAACCTTGARGACATTATGCTAAGTGAAATAAGCCAGTCACAAAAGGACAAATACTGTATGATTCCACTTATATGAGGTACCTAGAGTAGTCAAATTCATAGAGACAGAAAGTAGAATGGTGGTTGCCAGGGGCTGGGGGGAGGGGGGAATGGGGAGTTAKTGTTTAATGGGTACAGAGTTTCAGTTTGGGAAGATGAAAAAGTTCTGGAGATGGATGGTGGTGATGGTTGCACAACAATGTGAATGTACTTAACGCCACTGAACTGTACACTTAAAAATGGTTAAAATGGTAAATTTTATGTTATGTATATTTTACCACAATTAAAA
>L1MB7 3'-end of L1 repeat (subfamily L1MB7) - a consensus sequence
YTTGTATCCAGAATATATAAAGAACTCTTACAACTCAACAATAAAAAAACAAACAACCTAATTAAAAAATGGGCAAAAGAYTTGAATAGATATTTCTCCAAAGAAGATATAYAAATGGCCAATAAGCACATGAAAAGATRCTCAACATCATTAGTCATCAGGGAAATGCAAATYAAAACCACAATGAGATAYCACTTCACACCCAYTAGAATGGCTAAAATTAAAAAGACAGRMAATAMCAARTGTTGGYRAGGATGTRGAGAAAYTGGAACHCTCATACAYTGCTGGTGGGAATGTAAAATGGTACARCYACTTTGGAAAACAGTTTGGCAGTTCCTCAAAAAGTTAAMAATAGAGTTACCATATGACCCAGCAATTYCACTCCTAGGTATWTACCCAAGAGAAATGAAAACATAYRTCCAYACAAAAACTTGTACACAAATGTTCATAGCAGCATTATTCATAATAGCCAAAAAGTGGAAACAACCCAAATGTCCATCAATRATWGAATGGATAAACAAAATGTGGTATATCCATACAATGGAATATTATTCAGCMATAAAAAGGAATGAAGTAMTGATMYATGCAACAACATGGATGAACCTTGAAAACATTATGCTAAGTGAAAGAAGCCARRCACAAAAGRCCACATATTGTATGATTCCATTTATATGAAATGTCCAGAATAGGCAAATCCATAGAGACAGAAAGTAGATTAGTGGTTGCCAGGGGCTGGGGGRAAGGGGAAATGGGGAGTGACTGCTAATGGGTACGGGGTTTCTTTTTGGGGTGATGAAAATGTTCTAAAATTAGATAGTGGTGATGGTTGCACAACTYTGTGAATATACTAAAAACCACTGAATTGTACACTTTAAAAGGGTGAATTTTATGGTATGTGAATTATATCTCAATAAARCTAT
>L1MC2 3'-end of L1 repeat (subfamily L1MC2) - a consensus sequence
YTTGTATCCAGAATATATAAAGAACTCTTACAACTCAACAATAAAAAAACAAACAACCTAATTAAAAAATGGGCAAAAGAYTTGAATAGATATTTCTCCAAAGAAGATATAYAAATGGCCAATAAGCACATGAAAAGATRCTCAACATCATTAGTCATCAGGGAAATGCAAATYAAAACCACAATGAGATAYCACTTCACACCCAYTAGAATGGCTAAAATTAAAAAGACAGRMAATAMCAARTGTTGGYRAGGATGTRGAGAAAYTGGAACHCTCATACAYTGCTGGTGGGAATGTAAAATGGTACARCYACTTTGGAAAACAGTTTGGCAGTTCCTCAAAAAGTTAAMAATAGAGTTACCATATGACCCAGCAATTYCACTCCTAGGTATWTACCCAAGAGAAATGAAAACATAYRTCCAYACAAAAACTTGTACACAAATGTTCATAGCAGCATTATTCATAATAGCCAAAAAGTGGAAACAACCCAAATGTCCATCAATRATWGAATGGATAAACAAAATGTGGTATATCCATACAATGGAATATTATTCAGCMATAAAAAGGAATGAAGTAMTGATMYATGCAACAACATGGATGAACCTTGAAAACATTATGCTAAGTGAAAGAAGCCARRCACAAAAGRCCACATATTGTATGATTCCAACTATATGACATTCTGAAAAAGGNAAAACTATGGAGACAAGTAAAAAGATCAGWGATTNCTAGAGKGASTRGGARRGGGAGGGAAGAATAGGTGGAGCNCAGGGGATTTTTAGGGCAGCGAAACTATTCTGTATGATACTATAATGGTGGATACATGACATTATACATTTGTCAAAAYCCATAGAACTGTACAAYACAAAGAGTGAACCCTAATGTATGGACTTTAGTTAATAATAATGTATCAATGTTGGTTCATCAATTGTAACAAATGTACCACATTAATGCAAGATGTTAATAATAGGGTAAACTRTTGTGTGGGGGAGGGAGTATATGGGAACTCTCTGTACTTTCTGCTCAATTTTTCTGTAAACCTAAAACTGYTTCAAAAAATAAAGTCTATTAATAA
>L1MD1 3'-end of L1 repeat (subfamily L1MD1) - a consensus sequence
YTTGTATCCAGAATATATAAAGAACTCTTACAACTCAACAATAAAAAAACAAACAACCTAATTAAAAAATGGGCAAAAGAYTTGAATAGATATTTCTCCAAAGAAGATATAYAAATGGCCAATAAGCACATGAAAAGATRCTCAACATCATTAGTCATCAGGGAAATGCAAATYAAAACCACAATGAGATAYCACTTCACACCCAYTAGAATGGCTAAAATTAAAAAGACAGRMAATAMCAARTGTTGGYRAGGATGTRGAGAAAYTGGAACHCTCATACAYTGCTGGTGGGAATGTAAAATGGTACARCYACTTTGGAAAACAGTTTGGCAGTTCCTCAAAAAGTTAAMAATAGAGTTACCATATGACCCAGCAATTYCACTCCTAGGTATWTACCCAAGAGAAATGAAAACATAYRTCCAYACAAAAACTTGTACACAAATGTTCATAGCAGCATTATTCATAATAGCCAAAAAGTGGAAACAACCCAAATGTCCATCAATRATWGAATGGATAAACAAAATGTGGTATATCCATACAATGGAATATTATTCAGCMATAAAAAGGAATGAAGTAMTGATMYATGCAACAACATGGATGAACCTTGAAAACATTATGCTAAGTGAAAGAAGCCARRCACAAAAGRCCACATATTGTATGATTCCATTTACATAACATTCTTAAAATGACAAAATTWTAGARWTGRAGARCAGATTCCTGGTTGCCAGGGGTTAGGGACGGGGGTGGGGGTGGAGGGAGGTGGGCATSSTGGAGTTCCCTGTGGTGATGGAAATGTTCTGTATCTTCACTGTCACTGTATCAATGTCAATATCCTGGTTGTGATAYTGTAYTATAGTTTTGTAAGATGTTACCATTGGGGGAAGCTGGGTGAAGGGTACACGGGATCTCTCTGTAYTATTTCTTACAATTGTCTGTGAGTKTAYAATTATTTCAAAATAAAGTTTAATTTAAA
>L1MD2 3'-end of L1 repeat (subfamily L1MD2) - a consensus sequence
YTTGTATCCAGAATATATAAAGAACTCTTACAACTCAACAATAAAAAAACAAACAACCTAATTAAAAAATGGGCAAAAGAYTTGAATAGATATTTCTCCAAAGAAGATATAYAAATGGCCAATAAGCACATGAAAAGATRCTCAACATCATTAGTCATCAGGGAAATGCAAATYAAAACCACAATGAGATAYCACTTCACACCCAYTAGAATGGCTAAAATTAAAAAGACAGRMAATAMCAARTGTTGGYRAGGATGTRGAGAAAYTGGAACHCTCATACAYTGCTGGTGGGAATGTAAAATGGTACARCYACTTTGGAAAACAGTTTGGCAGTTCCTCAAAAAGTTAAMAATAGAGTTACCATATGACCCAGCAATTYCACTCCTAGGTATWTACCCAAGAGAAATGAAAACATAYRTCCAYACAAAAACTTGTACACAAATGTTCATAGCAGCATTATTCATAATAGCCAAAAAGTGGAAACAACCCAAATGTCCATCAATRATWGAATGGATAAACAAAATGTGGTATATCCATACAATGGAATATTATTCAGCMATAAAAAGGAATGAAGTAMTGATMYATGCAACAACATGGATGAACCTTGAAAACATTATGCTAAGTGAAAGAAGCCARRCACAAAAGRCCACATATTGTATGATTCCATTTATATAACATTCTTAAAACGACAAAACTATAGAGATGGAGAACAGATTAGTGRTTGCCAGGKGTTAGGGATRCAGGRAGGAGGTGGATGTGRYTATAAARRGGTAGCATGAGRGAATYTTTATGGTGATGGAACWGTTCTGTATCTTGAYTGTGGTGRTGGTTACACGAATNTATACATGTGATAAAATTGCATAGAACTAAATACACACACACACATAAGTACAAGTAAAACTGGCGAAATCTGAATAAGATTRATGGATTGTAYCAATGTCAATTTCCTGGTTKTGATATTGTAYTATAGTTTTCCAAGATGTTACCATTGGGGGAAGCTGGGTGAAGGGTACACGGGATCTCTCTGTAYTATTTCTTACAATTGTCTGTGAGTKTAYAATTATTTCAAAATAAAGTTTAATTTAAA
>L1ME2 3'-end of L1 repeat (subfamily L1ME2) - a consensus sequence
YTTGTATCCAGAATATATAAAGAACTCTTACAACTCAACAATAAAAAAACAAACAACCTAATTAAAAAATGGGCAAAAGAYTTGAATAGATATTTCTCCAAAGAAGATATAYAAATGGCCAATAAGCACATGAAAAGATRCTCAACATCATTAGTCATCAGGGAAATGCAAATYAAAACCACAATGAGATAYCACTTCACACCCAYTAGAATGGCTAAAATTAAAAAGACAGRMAATAMCAARTGTTGGYRAGGATGTRGAGAAAYTGGAACHCTCATACAYTGCTGGTGGGAATGTAAAATGGTACARCYACTTTGGAAAACAGTTTGGCAGTTCCTCAAAAAGTTAAMAATAGAGTTACCATATGACCCAGCAATTYCACTCCTAGGTATWTACCCAAGAGAAATGAAAACATAYRTCCAYACAAAAACTTGTACACAAATGTTCATAGCAGCATTATTCATAATAGCCAAAAAGTGGAAACAACCCAAATGTCCATCAATRATWGAATGGATAAACAAAATGTGGTATATCCATACAATGGAATATTATTCAGCMATAAAAAGGAATGAAGTAMTGATMYATGCAACAACATGGATGAACCTTGAAAACATTATGCTAAGTGAAAGAAGCCARRCACAAAAGRCCACATATTGTATGATTCCATTTATATGAAATTCWAGAACAGGCAAAACTAATCTATAATGNTAGAAATCAGAATAGTGGTTGCCTCTGGKGAGGGTRAATGACTGGRAAGGGRCATGAGGGAATTTTCTGGGGTGATGGAAATGTTCTATATCTTGATCGGGGTGGTGGTTACACGAGTGTATACATTTGTCAAAACTCATCGAACTGTACACTTAAAATCTGTGCATTTTACTGTATGTAAATTATAYCTCAATTTTAAAAAA
>L1ME3a 3'-end of L1 repeat (subfamily L1ME3a) - a consensus sequence
YTTGTATCCAGAATATATAAAGAACTCTTACAACTCAACAATAAAAAAACAAACAACCTAATTAAAAAATGGGCAAAAGAYTTGAATAGATATTTCTCCAAAGAAGATATAYAAATGGCCAATAAGCACATGAAAAGATRCTCAACATCATTAGTCATCAGGGAAATGCAAATYAAAACCACAATGAGATAYCACTTCACACCCAYTAGAATGGCTAAAATTAAAAAGACAGRMAATAMCAARTGTTGGYRAGGATGTRGAGAAAYTGGAACHCTCATACAYTGCTGGTGGGAATGTAAAATGGTACARCYACTTTGGAAAACAGTTTGGCAGTTCCTCAAAAAGTTAAMAATAGAGTTACCATATGACCCAGCAATTYCACTCCTAGGTATWTACCCAAGAGAAATGAAAACATAYRTCCAYACAAAAACTTGTACACAAATGTTCATAGCAGCATTATTCATAATAGCCAAAAAGTGGAAACAACCCAAATGTCCATCAATRATWGAATGGATAAACAAAATGTGGTATATCCATACAATGGAATATTATTCAGCMATAAAAAGGAATGAAGTAMTGATMYATGCAACAACATGGATGAACCTTGAAAACATTATGCTAAGTGAAAGAAGCCARRCACAAAAGRCCACATATTGTATGATTCTATTTGCATAAAATACAAAACCAGGCAAAACTAATCAATGNTGTTAGAAGTCAGGATAGTGGTTGTTCTGGGAATAGTAATGACTGTAAGGRARCATGAGAGGGCTTTCTGGGGTGCTGGTAATGTTCTGTTTCTTGATCTGGGTGCTGGTTACACGGCTGTGTTCARTTTGTGAAAATTCATYAAGCTGTACACTTATGATWTATGCAYTTTTATGTATGTATATTATAYYTCAATAAAAA
>THE1b consensus sequence
TGATATGGTTTGGCTGTGTCCCCACCCAAATCTCATCTTGAATTGTAGCTCCCATAATTCCCACGTGTCGTGGGAGGGACCCGGTGGGAGGTAATTGAATCATGGGGGCGGGTCTTTCCCGTGCTGTTCTCGTGATAGTGAATAAGTCTCACGAGATCTGATGGTTTTATAAAGGGGAGTTYCCCTGCACANGCTCTCTTGCCTGCCGCCATGTAAGACGTGMCTTTGCTCCTCCTTCGCCTTCYGCCATGATTGTGAGGCCTCCCCAGCCATGTGGAACTGTGAGTCCATTAAACCTCTTTYCTTTATAAATTACCCAGTCTCGGGTATGTCTTTATTAGCAGCATGAGAACGGACTAATACA
>MSTa consensus sequence
TGATATGGTTTGGATCTGTGTCCCCACCCAAATCTCATGTTGAATTGTAATCCCCAATGTTGGAGGTGGGGCCTGGTGGGAGGTGATTGGATCATGGGGGCGGATTYCTCATGAATGGTTTAGCACCATCCCCTTGGTGCTGTYCTCGTGATAGTGAGTGAGTTCTCATGAGATCTGGTCGTTTAAAAGTGTGTGGCACCTCCCYCCTCTCTCTCTTGCTCCTGCTCTCGCCATGTGACGTGCCTGCTCCCCCTTCGCCTTCCGCCATGATTGNAAGCTTCCTGAGGCYTCCCCAGAAGCCGAGCAGATGCCAGCGCCATGCTTCCTGTACAGCCTGCAGAACCGTGAGCCAATTAAACCTCTTTTCTTTATAAATTACCCAGTCTCAGGTATTTCTTTATAGCAATGTGAGAACAGACTAATACA
>MSTc consensus sequence
TGCTACGGTTTGAATGTTTGTCCCCTCCAAAACTCATGTTGAAACTTAATCCCCAATGTGGCAGTATTGAGAGRTGGGGCCTTTRAGAGGTGATTGGGTCATGAGGGCTCTGCCCTCATGAATGGATTAATGGATTAACGTATTAATGGATTAATTGGTTATCACGGGAGTGGGATCGGTGGCTCTATCATAAAARYCATTTTGNCTCTCGNRTGNGCCCCTTCTTGCCCTTTCACGCCTTCCGCCATGTTATGACAGAGCACAAGGCCCTCACCAGAAACCAGATGCAGCCGCCATGATCTTGGACTTCCCAGCCTSCAGAACCGTGAGCAAAATAAACCTCTTTTCTTTATAAATTACCCAGTCTATGGTATTCCGTTAAAGCAGCACGAACGGACTAAGACA
>MLT1a (MLT1a subfamily) - consensus sequence
TGCTATGGACTGAATGTTTGTGTCCCCCCAAAATTCATATGTTGAAGCCCTAATCCCCAATGTGATGGTATTAGGAGGTGGGGCCTTTGGGAGGTGATTAGGATTAGATGAGGTCATGAGGGCGGGGCCCTCATAATGGGATTAGTGCCCTTATAAAAGAGACCYCAGAGAGCTCCCTTGCCCCTTCCGCCATGTGAGGACACAGTGAGAAGGCGCCGTCTACGAACCAGGGAATGAGCCCTCACCAGAAACTGAATCTGCCGGCGCCTTGATCTTGGACTTCCCAGCCTCCAGAACTGTGAGAAATAAATTTCTGTTGTTTAAGCTACCCAGTCTATGGTATTTTGTTATAGCAGCCCGAACAGACTAAGACA
>MLT1b (MLT1b subfamily) - consensus sequence
TGTTATGGGCTGAATTGTGTCCCCCCAAAATTCATATGTTGAAGTCCTAACCCCCAGTACCTCAGAATGTGACTGTATTTGGAGATAGGGTCTTTAAAGAGGTAATTAAGTTAAAATGAGGTCATTAGGGTGGGCCCTAATCCAATATGACTGGTGTCCTTATAAGAAGAGGAAATTWGGACACAGACACGCACAGAGGRAAGRCCATGTGARGACACAGGGAGAAGGCGGCCATCTRCAAGCCAAGGAGAGAGGCCTCAGAAGAAACCAACCCTGCCGRCACCTTGATCTCGGACTTCYAGCCTCCAGAACTGTGAGAAAATAAATTTCTGTTGTTTAAGCCACCCAGTCTGTGGTACTTTGTTACGGCAGCCCTAGSAAACTAATACA
>MLT1c (MLT1c subfamily) - consensus sequence
TGTTATGGGTTGAATTGTGTCCCCCCAAAATTGATATGTTGAAGTCCTAACCCCTAGTACCTCAGAATGTGACCTTATTTGGAAATAGGGTCWTTGCAGATGTAATTAGTTAAGATGAGGTCATACTGGAGTAGGGTGGGCCCTAAATCCAATATGACTGGTGTCCTTATAARAAGAGGAAATTTGGACACAGACACGCACACGGGGAGAAGGCCATGTGAAGACGGAGGCAGAGATTGGAGTGATGCAKCTACAAGCCAAGGAACGCCAARGRYTGCCAGCAAACCACCAGAAGCTAGGAAGAGGCAAGGAACAGATTCTCCCTCACAGCCYTCAGAGGARRCCAGCCCTGCCGACACCTTSATCTCGGACTTCTGGCCTCCAGAACTGTGAGAGAATAMATTTCTGTTGTTTAAGCCACSCAGTTTGTGGTACTTTGTTACGGCAGCCCYAGGAAACTAATACA
>MLT1d (MLT1d subfamily) - consensus sequence
TGTGGTAGGCWGAATAATGGCTCCCCAAAGATGTCCACGTCCTAATCCCCAGAACCTGTGAATATGTTACCTTACATGGCAAAAGGGACTTTGCAGATGTGATTAAGTTAAGGATCTTGAGATGGGGAGATTATCCTGGATTATCCGGGTGGGCCCAATGTAATCACAAGGGTCCTTAWAAGAGGGAGGCAGAGGGTCAGAGTCAGAAGAAGGAGATGTGACGATGGAAGCAGRRAGNGAAAACTCAACGTTGCTGGCTTTGAAGATGGAGGAAGGGGCCATGAGCCAAGGAATGCGGGCAGCCTCTAGAAGCTGGAAAAGGCAAGGAAACGGATTCTCCCCTAGAGCCTCCAGAARGAACGCGGCCCTGCCGACACCTTGATTTTAGCCCAGTGAGACYCATTTTGGACTTCTGACCTCCAGAACTGTAAGATAATAAATTTGTGTTGTTTTAAGCCACTAAGTTTGTGGTAATTTGTTACAGCAGCMAYAGGAAACTAATACA
>MLT1e (MLT1e subfamily) - consensus sequence
TGTGGTAGGCAGAATTCTAARATGMTCCCAATGATCCTCGCCTCCTGGCGTAATCTCCTTGAGTGTGAGTAGGACCTGTGACTTGCTTCTAGCCAACGGAATATGGCAAAGGTGATGARATRTCACGTGATTACGCGTACGTGATTATGTAASATTCAGTCTTTGMCGTCATTCTTGCCGAGAGACTCTCCTSCTGGTYTTGAAGAAGTAAGCTGCCACGTCATGAGNNNNCNNANNAGARYGCCGCAAGGCAAGGGNNTCTAGAGCTGAGAGTCGCCCTTACTGATGGGCAGCAAGAAGCAAGCCACCTCAGTCCTACAGCCGCAAAGAACTGAATTCTGCCAACAACCTAGTGAGCTTGGAAGCAGATCCTGCCCAGTCGAGCCTCCAGATGAGANCGCAGCCCTGGCTGACGCCTTGACTGCAGCCTTGNTAGACCTTGAGCAGAGGACCCAGCTAAGCCGTGCCCAGACTCCTGACCCACAGAAACTGTGAGATAATAAATGTGTGTTGTTTTAAGCCGCTAAGTTTGTGGTAATTTGTTACGCAGCAATAGAAAACTAACACA
>MLT1f (MLT1f subfamily) - consensus sequence
TGTGGTAGCCAGCCTCCAAGATGGCCCCCAATGATCCCTGCTCCTGGTATTCACAYCCTTGTATGGTCYCYTCCTACATTGARYYAGGGCTRGTCTGTGTGACCAATAGAATAGGGCAGAAGTGATGGCGTGTSACTTCCAAGAYTARGTCAYAAAWAACACTGTGGYTTCTGCYTTGNTCTCTTCGGGCTACTCACTCTGGGGGAAGCCAGCTGCCATGCTATGAAGACACTCAAGCAGCCTATGGAGAAGTCCACGTGGSAAGGAACTGAGGTCTCCTGCCAACAGCCAGCTTCGACYTGCCAGCCATGTGAGTGAGCCATCTTGGAAGCGGATCCTCCAGCCCCAGTYAAGCCTTCAGATGACTGCAGCCCCGGCTGACATCTTGACTGCAACCTCATGAGAGACCCTGAGCCAGAACTACCCAGCTAAGCTGCTCCTARATTCCTGACCCACAGAAACTGTGAGATAATAAATGTTTRTTGTTTTAAGCCACTAAGTTTTGGGGTAATTTGTTACGCAGCAATAGATAACTAATACA
>THE1BR THE-1B Mammalian LTR retrotransposon internal sequence - a consensus
GTAAATTGGTACCAGTAGAGTGGGGCGCTGCTGAAAAGATACCCGAAAATGTGGAAGCGACTTTGGAACTGGGTAACAGGCAGAGGTTGGAACAGTTTGGAGGGCTCAGAAGAAGACAGGAAAATGTGGGAAAGTTTGGAACTTCCTAGAGACTTGTTGAATGGCTTTGACCAAAATGCTGATAGTGATATGGACAATAAAGTCCAGGCTGAGGTGGTCTCAGATGGAGATGAGGAACTTGTTGGGAACTGGAGCAAAGGTGACTCTTGTTATGTTTTAGCAAAGAGACTGGCGGCATTTTGCCCCTGCCCTAGAGATTTGTGGAACTTTGAACTTGAGAGAGATGATTTAGGGTATCTGGCGGAAGAAATTTCTAAGCAGCAAAGCGTTCAAGAGGTGACTTGGGTGCTGTTAAAGGCATTCAGTTTTAAAAGGGAAGCAGAGCATAAAAGTTCGGAAAATTTGCAGCCTGACAATGCGATAGAAAAGAAAATCCCATTTTCTGAGGAGAAATTCAAGCCGGCTGCAGAAATTTGCATAAGTAACGAGGAGCCGAATGTTAATCCCCAAGACAATGGGGAAAATGTCTCCAGGGCATGTCAGAGATCTTCGCGGCAGCCCCTCCCATCACAGGCCCGGAGGCCTAGGAGGAAAAAATGGTTTCGTGGGCCAGGCCCAGGGTCCCCGTGCTGTGTGCAGCCTAGGGACTTGGTGCCCTGCGTCCCAGCCGCTCCAGCCATGGCTAAAAGGGGCCAACGTACAGCTCGGGCCGTGGCTTCAGAGGGTGCAAGCCCCAAGCCTTGGCAGCTTCCACGTGGTGTTGAGCCTGCGGGTGCACAGAAGTCAAGAATTGAGGTTTGGGAACCTCCGCCTAGATTTCAGAGGATGTATGGAAACGCCTGGATGTCCAGGCAGAAGTTTGCTGCAGGGGCGGGGCCCTCATGGAGAACCTCTGCTAGGGCAGTGCGGAAGGGAAATGTGGGGTCGGAGCCCCCACACAGAGTCCCTACTGGGGCACTGCCTAGTGGAGCTGTGAGAAGAGGGCCACCGTCCTCCAGACCCCAGAATGGTAGATCCACCGACAGCTTGCACCGTGCGCCTGGAAAAGCCGCAGACACTCAACGCCAGCCCGTGAAAGCAGCCAGGAGGGAGGCTGTACCCTGCAAAGCCACAGGGGCGGAGCTGCCCAAGACCATGGGAACCCACCTCTTGCATCAGCGTGACCTGGATGTGAGACATGGAGTCAAAGGAGATCATTTTGGAGCTTTAAGATTTGACTGCCCCGCTGGATTTCGGACTTGCATGGGGCCTGTAGCCCCTTTGTTTTGGCCAATTTCTCCCATTTGGAATGGCTGTATTTACCCAATGCCTGTACCCCCATTGTATCTAGGAAGTAACTAACTTGCTTTTGATTTTACAGGCTCATAGGCGGAAGGGACTTGCCTTGTCTCAGATGAGACTTTGGACTGTGGACTTTTGAGTTAATGCTGAAATGAGTTAAGACTTTGGGGGACTGTTGGGAAGGCATGATTGGTTTTGAAATGTGAGGACATGAGATTTGGGAGGGGCCAGGGGCGGAA
>MSTAR MSTa-Mammalian LTR internal retrotransposon sequence - a consensus
GAAWATTGGTACTGAGGAGTGGAGCATTGCTATAAAGATACCTGAAAATGTGGAAGCGACTTTGGAACTGGGTAACAGGCAGAGGTTGGAAGAGTTTGGAGGGCTCAGAAGAAGACAGGAAGATGAGGGAAAGTTTGGAACTTCTTAGAGACTTGTTAAATGGTTGTGACCAAAATGCTGATAGTGATATGGACAGTAAGGGCCAGGCTGACGAGGTCTCAGATGGAAATGAGGAACTTATTGGGAACTGGAGCAAAGGTCACTCTTGTTATACATTAGCAAAGAGCTTGGCTGCATTTTGCCCCTGCCCTAGAGATTTGTGGAAGTTTGAACTTGAGAGTGATGATCTAGGGTATCTGGCGGAAGAAATTTCTAAGCAGCAAAGCGTTCAAGATGTGACCTGGCTGCTTTTAACAGCTTACAGTCATATGCGAGAGCAAAGAAATCACTTAAAGTTGGAATTTATATTTAAAAGGGAAGCAGAGCGTAAAAGTTTGGAAAATTTGCAGCCTGGCCATGTGATAGAAAAGAAAAACCCGTTTTCTGGAGAGAAATTCAAGCAGGCTGCGGAGCGACCGTTTGCTAAAGAGATTAGCATAACTAAAAGGAAGCCAAGTGCTGATAGCCAAGACAATGGGAAAAAGGCCTCGAAGGCATTTCAGAAATCTTCGAGGTGGTCCTTCCCATCACAGGCCCAGAGGCCTAGGAGGACTGAATGGTTTCGTGGGCCAGGCCCAGGGCCCCGCTGCCCTGTGCAGCCTCGGGACACTGCTCCCTGCATCCCGGCTGCTYCGGCTCCAGCCGTGGCTCAAAGGGCCCCAGGTACAGCTCGAGCTGCCGCTTCGGAGAGTGCAAGCTATAAGCCTTGGTGGCTTCCACATGGTGTTAAGCCTGCAGGTGCACAGAATGCAAGAGTGAAGGAGGCTTGGCAGCCTCCACCTAGATTTCAGAGGATGTATGGGAAATCCTGGGTGCCCAGGCAGAAGCCTGCTGCAGGGACGGAGCCCTCACAGAGAACCTCTACTAGAGCAGTGCCAAAGGGAAATGTGGGGTTGGAGCCCCCACACAGAGTCCCCACCGGGGCACTGCCTAGTGGAGCTGTGGGAAGGGGGCCACTGTCCTCCAGACCCCAGAATGGTAGAGCCACTGGCAGCGTGCACCGCCAGCCTGGAAAAGCCGCAGGCATCAGACTCCAACCCGTGAGAGCAGCCACGTGGGCTGTGCCCAGCAAAGCCACAGGGGCGGAGCTGCCCAAGGCCTTGGGAGCCCACCCCTCGCACCAGCGTGCCCTGGATGCGAGACACGGAGTCAAAGGAGATTATTTTGGAGCTTTAAGATTTAATGACTGCCCTGCTGGGTTTCGGACTTGCGTGGGGCCTGTAGCCCCTTTCTTTTGGCCCATTTCTCCCTTTTGGAATGGAAATATTTACCCAATGCCTGTACCACCATTGTATCTTGGAAGTAAATAACTTCTTTTTGATTTTACAGGCTCATAGGTGGAAGGAACTTGCCTTGTCTCAGATGAGACTTTGGACTTTGGACTTTTGAGTTAATGCTGGAATGAGTTAAGACTTTGGGGGACTGTTGGGAAGGCATGATTGTATTTTGCAATGTGAGAAGGACGTGAGATTTGGGGGAACCAGGGGCAGAA
>MLT1R MLT1-Mammalian LTR retrotransposon internal sequence - a consensus
GATTTTGGCACTAGGAAGTGGGGTGCTTACGTAACAAATACCTAAAAATGTGGAAGCGACTTTGGAACTGGGTAATAAGTAGAGGCTGGAAGAGTTTTGAGGTACATGYTAGAAAAAGCCTAGATTTCCTTGAAGAGACTGTTGGTAGAAATATGGATATTAAAGGYAATTCTGGTGGGGGGCTCAGAAAGGAAGWGGAGAGCTATAGAGAAAGCTCCCGTCGTCTTAGAGAATACAAAAATCGTCATGAACAGAATGTTGCTAGAAATATGAATGTTAAAGGTGCTTCTGGTGAGGTCTCAGACGGAAATGAGGGAGATGTTATTGAAAATTGGAGGAAAGGTGATCCTTGTTATAAAGTAGCAAAGAACTTGGCTGAATTGTGTTCATGTCCTAGGGCTTTATGGAAAGTAGAACTTGYAAGTGATGAACTKGGATATTCAGCTGAGGAAATTTCTAAGCAAAGTGTTGAGGGCGCAACCTGACTTCTCCTAACTGCTTATAGTAAAATGTGAGAGACATAAAGATGGAANTGTTGAGTAAAAAGGAACCAGAACGTAAAGATTTGGAAAATTCTCAGCCTGATCATGTAACAGAAANNNCAATAGCGTTCTCTGGAAAGAANACCAAGGATGTNNCCGNGCAACCGTTTGCTAAAGAGATTAGRATCGTGACTCGTGGGTCCAATCAACCATCTCAGCARAARCCARGAATAGAGATGRGGTTATTTAGGAAATATCTGTGGAGGACTCTCTTATCTGATGGCTCGAACCCCTATGACTTNCATAGGAGACCGACAAGGNTTTTGAGAATNTTACACCAGCAGAAACACTGCCAACTTGGACTRAAGGGRACAGAGACGAGAAAAAATGAAGGAAGRGTGGCAGACCGAAGGTGGGGCTGTCTCGTTTCAGAGCATGGKGTCACCCCAGCGGGCCCGGAAGATGAATCTCAGGACTCAGAGGCATTAGCCTCCAGCCTTAAGATCTAATGAAGTTTGCCCTGCTGGGTTTTGGACTTGCTTGGGACCNGTGACTCCTTTCTTYYYTTCYATTTCTCCCTTTTGGAATGGGAATATCTATCCTATGCCTGYCCCACCGTTGTATTTTGGAAGCAGATAACTTGTTTNATTRCACAGGTCCACAGATGGAGAGGAATTTTGCCYCTGAATGAATCTYACCCTGAGTYTCTNCCAYACYTGATGYRGRTGATATTTCGCTGAGATTGTGGACTAAGAGTTGGTGCTGGAAGGGGTTAGACATTGGGGAGATGTTGCTATGGGATGCAGGGATTTTGCATGTGAGAAGGACATGATTATGGGGGGAGCGGAGGGCAAAC
>MLT2A1 Interspersed repeat MLT2A1- a consensus
TGTGATGGTTAATACTGAGTGTCAACTTGATTGGATTGAAGGATACAAAGTATTGATCCTGGGTGTGTCTGTGAGGGTGTTGCCAAAGGAGGTTAACATTGGACTCAGTGGGCTGGGGAGAGGCAGACCCACCCTTAATCTGRGTGGGCGCMATCYAATCAGCTGCCAGCGTGGCTAGAATATAAAGCAGGCAGAAAAATGTGAAAAGAGAGACTGGCCTAGCCTCCCAGCCTACATCTTTCTCCCGTGCTGGATGCTTCCTGCCCTTGAACATCAGACTCCAAGTTCTTCAGTTTTGGGACTCGGACTGGCTCTCCTTGCTCCTCAGCTTGCAGACGGCCTATTGTGGGACCTTGTGATCGTGTGAGTTAATACTTAATAAACTCCCCTTTATATATATCTATTCYATTAGTTCTGTCCCTCTAGAGAACCCTGACTAATACA
>MLT2B2 Interspersed repeat MLT2B2 - a consensus
TGTGATGGTTAATTTTATGTGTCAACTTGACTGGGCTAARGGGTGCCCAGATAGCTGGTTAAACATTATTTCTGGGTGTGTCTGTGAGGGTGTTTCCAGATGAGATTAGCATTTGAATCAGCGGACTGAGTAAAGAAGATTGCCCTCACCAATGTGGGCGGGCATCATCCAATCCGTTGAGGGCCTGRATAGAACAAAAAGGCAGAGGAAGGGTGAATTTGCTCTCTCTCCTTGAGCTGGGACATCCATCTTCTCCTGCCCTTGGACATTAGAACTCCAGGTTCTCGGGCCTTCGGACTYCGGGACTTGCACCAGCAGCCCCCCAGATTCTCAGGCCTTCGGACTCGGACTGARYYACGCCACCGGCTTCCCTGGTTCTCCAGCTTGCAGACGGCATATCGTGGGACTTCTCAGCCTCCATAATCACGTGAGCCAATTCCCCTAATAAATCYCYTCTATCCATCCTATTGGTTCTGTCTCTCTGGAGAACCCTGACTAATACA
>MLT2C2 Interspersed repeat MLT2C2 - a consensus
TGTGATAGTTAATTTTATGTGTCAACTTGGCTAGGCTATGGTGTCCAGACGTTTGGTCAAACAYCAGTCTAGATGTTGCTGTGAAGGTATTTTRTAGATGTGATTAACATTTAYAGTCAGTTGACTTTAAGTAAAGGAGATTACCCTCCATAATGTGGGTGGGCCTCATCCAATCAGTTGAAGGCCTTAAGAGCAAAGACTGAGGTTTCCCGAGGAAGAAGAAATTCTGCCTCAAGACTGCAACGTGGAAATCCTGCTGNTTTWCCAGCCTCCAAGCCTTCGGACTCGAACTGCAACATCARCTCTTSCCTGGGTCTCCAGCCTGCCGGCCTACCCTGCAGATTTCGGACTTGCCAGCCTCCACAATCGCGTGAGCCAATTCCTTAAAATAAATCTCTCTCTACACACACCCTATTGGTTCTGTTTCTCTGGAGAACCCTGACTAATACA
>MLT2D Interspersed repeat MLT2D - a consensus
TGTGATAGTTAATTTTATGTGTCAACTTGGCTAGGCTATGGTGTCCAGACGTTTGGTCAAACATTAGTCTGGGTGTTTCTGTGAAGGTTATTTTTTGGATGAGATTAACATTTAAATCGGTAGACTGAGTAAAGCAGATTACCCTCCCTAATGTGGGTGGACCTCATCTAATCAGTTGAAGGCCTGAATGGAAAAAAAGGGCTGACCCTCCCCCAAGTAAGAGGAAATTCTGCCTGCCTGATNGTCTTCGAACTGGAATATCAGCTCTGCGGATTTTGGACTTGCCAGCCTCCATAATTGCATGAGCCAATTCCTTATAATAAATCTATCTACTCTCTCTACACACACCCTATTGGTTCTGTTTCTCTGGAGAACCCTGACTAATACA
>LTR1 LTR from human endogenous retrovirus-like sequence (HUERS-P2).
TGATATGGGAGTGCTGGGAAGGGAAGAGCGTGGTCCCTTTAAATGATACAGAAGGGGGAAAGGAAGTGCTGTGTGGAGGAGGATGTGGTCCCTGGCTAGTACTCCAACCACACAGACCTAGGTTAAGGACAGGCATTTTTGTTGCATTTCCCAAGACCACCCTGGCCTGCCATGCCCCCATCCTGTGCCTATAAAAACCCAAGACCCTAATAAGGCAGAGATAGAAGCAGCTGGACGTCATGAGGAACACATCAGTGGAAGAGCACACAAGCGGCTAGTCATCAAGAGCTCACCAGTGGAAGAGCAGCCCGATAGGCACTGGCACGCAGGCAGGTACCGGCATGCCAGCAGGCCATCGACTGGCAAAATGATGCCGAATTTGGCTGGAGTGGTCAGAGAAGAGCCAGGTCACTGAGCTGCCGGACTCCAGGGGAAAACCATCTCCCTTCTGGCTCCCCCATCCACTGAGAGCTATTTCTACTCAATAAAACCTTGCAGTCATTCTCCAGGCCCACATGTGATCTGATTCTTCTGGTACATCAAGGCAAGAAACCCCAGGATACAGAAAGCCCTCTGTCCTTGTGACAAGGTAGAGGGTCTAACTGAGCTGGTTAACACAAGCTGCCTGTAGATGGCAAACTAAAAGAGCACCTTGTAACACATGCCCACTGGAGCTTCAGGAGCTGTAAACATTCACCCCTAGACACTGCCATGGGATTGGAGCCCCACAGCTTGCCTGTCCAAATGCTCCCCTAGAGGTTTGAGCAGCAGGGCACTGAAGAAGTGAGCCACACCCCCATCACATCCCCTGTGAGGGGAACAAGGGAACCTTTCCTATTTCA
>LTR2 LTR from human endogenous retrovirus (4-14), 3' long terminal repeat
TAAGGAAGGAGACCACCTCTCCCATTGTCTCCTGTTTCATGAGAAAGCAAAAAGTTAAAAAAAGAAGCAGAAGTGAGATCAATGGCCAGATGGTTTAGTGCCAAGAACCAGGCCTGGTAGTTAAACATCAACTCCTGACCTAACCGCTTGTGCTATCCATAGATTCCAGATATTGTATGAGGAAGACTTGTGAAACTTTCTGTTCTGTTCTGCTAGCCCCCATCACTGATGCATGTAGCTCTCAGTCATGTAGCCCCCACTTGCACAATGTATCATGACCCTTTCACGTGGACCCCTCAGAGTTGTAAGCTCTTAAAAGGGACAGGAATCTTTACTTTGGGGAGCTCGGATCTTGAGACGCGAGTCTACCAATGCTCCCAGCTGATTAAAGCCTCTTCCTTCATAGAACCGGTGTCTAAGAGGTTTTGTCTGTGACTGTTCCTGCTACA
>LTR3 LTR from human DNA related to mouse mammary tumor virus (MMTV) 3' LTR
GTTGGAGGCCGAAAGAATAGGGTCGTGACCAACTCAGTATACCACTGGAGGCTATATGAGCAAACAGCAAACTGTTCTCATGAATGCAGGATGCTGGCAAGCTGACAACTGCATCTGCCACCAGAAGGAATGCTGAGGGCAGTCATACCCCACGTGCAGTGTTCCTTGTGGTTATCTATAGGAATATCTGGAGGCTGTTGTATAAAGAAAGCAATTATGTGAGCCCGTGATAAATCAAGCAGCTGACCAACCATTACCTCTTCCTCCCTGTTGATTCTACCTAATAAATACAAAGGGCTGTAGAAGCTCAGGGCCCTTGTTCCCTAGAAGAAAGGAGCCGCCTGTCTCCTTCTTTAAAACAGATCTTTTTGTCTTTGTCTTCATTTCTGCATTTGTTCTCTTTTGTTCAGTCCCAAACCGACAGCCATA
>LTR4 LTR from human endogenous retrovirus ERV3, POL-ENV-3'LTR region
GAAGCAGGAAATATAAAAGGAAAAACAAGTAAAGGGAAAACAAGTCCTTTCCTGACCAGTCTGACTCACTCCAAAGTCCTGCTGGAGCTATGATAATTATCTGCAAGGCCAGGCAGGGGCTCCGAAGGAGGGCTCCAGGAGCAGGGATGAGAAAAACAAGTTCTCCTTATCAGTTTCCCTGTTTGAAATTCTCTCCCCATAACATTATTCTTTGTTCTGCTCTCACAACTATTTTTGTAACTATTTCTGCAAGTCTGTAAAGATTTTGTAAGTTCTTGTTTTTCTTTCTGTAGCATGGCAAGGTCACAAGACATGTTTAAGTAAGGTAGGCTCATGTTGCAAATCCTGTTGTAAAACCTGTCACGGTATGATTAACTGCCTTTGTTCTGCTTCTGTAAGACTGCTTTCTCACCTCGCAGGTTTTGCGCCAAAAACCCGACTTGCCCCTGCCTGATGCATGTATAAAAGTCAAGCCCGTCTTTGTTCCGGGCTCAGCCTTTGGATGTTAATCCGCTGGGCCAGTGGCCACCTAAATAAAACCTTCCTGTTGCACCCAGTGATCTCTCCGGCCTCCTGATACCCACAACA
>LTR5 LTR from human endogenous retrovirus 5' LTR, clone HERV-K18
TGTGGGGAAAAGCAACAGAGGTCAGATTGTTACTGTGTCTGTATAGAAAGAAGTAGACATAGGAGACTCCATTTTGTTCTGTACTAAGAAAAATTATTCTGCCTTGAGATGCTGTTAATCTATGACCTTACCCCCAACCCCGTGCTCTCTGAAACATGTGCTGTGTCAAACTCAGGGTTAAATGGATTAAGGGCGGTGCAAGATGTGCTTTGTTAAACAGATGCTTGAAGGCAGCATGCTCATTAAGAGTCATCACCACTCCCTAATCTCAAGTACCCAGGGACACAAAAACTGCGGAAGGCTGCAGGGGCCTCTGCCTAGGAAAGCCAGGTATTGTCCAAGGTTTCTCCCCATGTGAGAGTCTGAAATATGGCCTCGTGGGAAGGGAAAGACCTGACCGTCCCCCAGCCCGACACCCATAAAGGGTCTGTGCTGAGGAGGATTAGTATAAGAGGAAAGCATGCCTCTTGCAGTTGAGACAAGAGGAAGGCATCTGTTTCCCACCCATCCTTGGGCAATGGAATGTCTCGGTATAAAACCCGATTGTACGTTCCACCTACTGAGATAGGGAGAAACCACCTTAGGGCTGGAGGTGGGACATGCAGGCAGCAATACTGCTTTGTAAAGCATTGAGATGTTTATGTGTATGCATATCTAAAAGCACAGCATTTAATCCTTTACCTTGTCTATGATGCAAAGACCTTTGTTCACGTGTTTGTCTGCTCACCCTCTCCCCACTATTGTCTTGTGACCCTGACACATCTCCCTCTCAGAGAAACACCCACGAATGATCAATAAATACTAAGGGGACTCAGAGGCTGGTGGGATCCTCCATATGCTGAACGTTGGTTCCCCGGGCCCCCTTATTTCTTTCTCTATACTTTGTCTCTGTGTCTTTTTCTTTTCCAAGTCTCTCATTGCACCTTACGAGAAACACCCACAGGTGTGGAGGGGCAACCCACCCCTTCA
>LTR6 LTR from human SSAV-related endogenous retroviral LTR-like element
TGGCCAGATTCCTGCTTAGATTCATCACTCACATCAAAAAGGCCAACAGAGCCCAACAAGAAACATAGGTCCCCAAGCATAGGCCAGGCCCCTTAAAACTGTGCCTAAGTCGAGTGAAGCCTTTAGATTAATTCTTTTTATTTATCTCTCTTGTTTATTTCCACCTGTTATGCCCTCCGTGCCTTCCTATTCTTCTCACTTCTTTCACGACAGGACGTGTATTTGCAAACACTACTTGGAAGGCAAGAACCTCCAAGAAAGTCTCTTTTGCAGTCGATTTATGTGCTTTGTTCCCAGAGCCTGCCCATAACCTTGAAGAACAATGCAACCTGCCGGTCATAGAAGCGGGGAACATCAACCTTGCTACAGGGTTCGGACACACAGGAAGCCGGACTGGATGTAAAAACTCTAAAAGTGAAAAAAAAAGGACTCCAGAGCATTGACTTTTACCTCTGTCCTAAAAATCACCCTGACTCTAGTTGTCACGATTCTTACCAATTTTTCTGCCCTCACTGGTTTTGTGTGACCCTAGCCA
>LTR7 LTR from human endogenous retrovirus RTVL-H2
TGTCAGGCCTCTGAGCCCAAGCTAAGCCATCACATCCCCTGTGACTAGCACATATACGCTCAGATGGCCTGAAGTAACTGAAGAATCACAAAGAAGTGAAAATGCCCTGCCCCACCTTAACTGATGACATTCCACCACAAAAGAAGTGAAAATGGCCGGTCCTTGCCTTAAGTGATGACATTACCTTGTAAGAGTCCTTTTCCTGGCTCATCCTAGCTCAAAAATCTCCCCTACTGAGCACCCTGCGACCCCCACTCCTACCCGCCAAAGAACAACCCCCCTTTGACTGTAATTGTCCTTTACCTACCCAAATCCTATAAAACAGCCCCACCCCTATCTCCCTTTGCTGACTCTCTTTTCGGACTCAGCCCGCCTGCACCCAGGTGATTAAAAGCTTTATTGCTCACACAAAGCCTGTTTGGTGGTCTCTTCACACGGACGCGCATGAAA
>LTR8 region
TGAAACCGTCTTTGCAAAATTATAACTGAGATAGTGAAAGAGATTTAACTTAACTGCTTTTATCTTGCTTTTAACCTTTAAGCTGTCCTTGTTTATTCCTGGGTGTGGGCTGAACTAACTTTTGGAGAAACTTAGTTTATAGTTTATAGTTTAAACAAAGACAGTAACAGCCCTTTCCCAAGCAGACCTCCTTCATGCCTGGGGACTAGATTGCTTCTGTAGGACTAATGTTAGCGACCAAATTAAAAATTATGGTTTAGGAGTTATGCAGTTTGAGGCTACAAAATTTTAACCCTCTCTAAACTGCTCCTAAGATCAGTGCTTGAGATATTTTGCAGACCCTGCCCTTGACGGATCAGCTGGCACCAACCAGATCAATCAACTGGCTCATCTGATCTTGCGGCCCCCACCCAGGAACTGACTCAGCGCAAAAAGACAGCTTCAACTTCCTATGATTTCATCCCTGACCAATCAACACTCCTGGCTCACTGGCTTCCCCCCACCCACCAAGTTATCCTTAAAAACTCTGATTCCTGAATGCTCAGGGAGACTGATTGGAGTAACAATAAAACTCCAGTCTCCCACACAGACGGCTCTGTGTGAATTACTCTTTCTCCATTGCAATTCCCCTGTCTTGTTGAATCGGCTCTGTCCAGGTAGTGTGCAAGGTGAACCCCTTGGGTGGTTACA
>LTR9 LTR from human endogenous retrovirus-like sequence (HUERS-P3)
AAAGAATAAATCACTGATATAAGAGTTAAGAAAAAATCACTTAGGCAGAGAGCAAGGGTATGGGAGTCCTCAGTAAGGCTTTTATTTTTAATGAAAAGCAGCCCCAAATCATTTTCTAACAAAAAGCACCCTGCAAGCTGGAAGTTTGCACAGGTGGATGCTGGCAGGAACTAAGGATTAGATATGTTCAAGATGGTGGTTCCATCTTCCCTTCTTTGCCAGCCAGGTGTACTGTAAAGGAGCAGACAAGATGGCGCTAATCAACTGGAAAGCCCAGTTGCATAAAAAGATTAGGCTTCCCTGCGCACCATGCAAACGTCATATCTGATCAAACCAATCTATGAGCTCTATGTAAATCAGACACCACTTCCTCAAACTGGACTATAAAACTCGATGGATTCACCACCAGCTGGTCTTTTCCGCTTGGAGACCCCTTCCTCTATAGAGGAAGCTGTTTCTCTTTGTCTTCTCTCCTACCCATTAAACCTCTGCTCCTAAACTCCTCATGTGTGTCCATATCCTAAATTTTCCTGGCACGTGACAACAAACCCCAGTGTATACACACCCCAGACAACATAGCCACTTCAAAATGGGGGCTCGTCTGGGAT
>LTR10 Human DNA sequence 5'-flanking minisatellite PMS32
TGTTGTAAATAAATTTTTGGTGCTGCAAAAGAAATACCACTCAAACATAAGTTTAATTTTCTCAGCAAGGCAATTTTACTTCTCTAGAAGGGTGCGACTCGCAGATGGAGCAATGGCCAGAGCACACCTGAACAAGGGAGGGGAAGGGGTTCTGATTCCTGACACAGGTAGCCCCTACTGATGCGTCGTTCCCGTATCGGCTAGGGTTGGACTGCACAGTCTAAGCTAATTCCGATTGGCTACTTTAAAGAGAGCAGGGGTATGAGCCAGAGTGGCGGGGTGAGTAGTTTGGTGGGAAGGGTGGTT
>LTR11 LTR from human HTLV-I related endogenous retroviral sequence (HRES-1/1)
TGTGTTTCTGCAGGATGTACAGCCCTCCCAGCACGGTGCTCGCTTCCCTAATGCCATTCCACAGTATTTGTTGCAGAGAAGGAAGGCAGCATGCCAGGACAGATGGAGACAGGACTAATTTGGCCTGAGGTATGTAATTTTGAACTTGAGCCTCTCTCTGGGACTGTAAAACTCCAAATCAAAGCTAATCTGAGAATACATACATCTGAAAGATGATTAGGACTGTAAACATCTATTAATATTCAACTCTGATACAAAGTACAAGTTGTTTATTCTTACCACGCAAGGCCAAAAAAGGGGAGAAAAAAAAAAAAGCACACAGCATATGCACTGGAAAGTTTCGCTTATTCAAAACAGTATTTGTCAAGCACCTCCAGTCTGGTGCTGCAGGGGAAACAAAGATTAAACAGCCAGGCGGACACTGCTCTGCTTCCAAGGTGCTTACGGTCTTAAGAAGGAGACAAGACATGTTTATAAATAGCCAAAATGCAACCCAGAAAAGGCTAAAAAACACTGAGAGGGAGGGAGAAATAAACGAAGCAAGAGGTCTCCGGAGGAAGAGATGAATGAATTAGCCTATTAATAACTCCGTCACTGTAATCCCAATGTAAAGCAAGAATTCCAAACCAGGAAAGGTCAAACTGAAGTATTTGAGGAACACAGGCGTCGCCTAAGCCCTTCACA
>LTR12 LTR from human ERV9 endogenous retroviral sequence (HRES-1/1)
TGTATCTAGTTAATCTGGTGGGGAGTTGGAGAATCTTTATGTCTAGCTAAGGGATTGTAAATACACCAATCAGCACTCTGTATCTAGCTCAAGGTTTGTAAACACACCAATCAGAACCCTGTGTCTAGCTCAGGGTTTGTGAATGCACCAATCAGCACTCTGTATCTAGTTAATCTGGTGGGGACTTGGAGAATCTTTATGTCTAGCTAAGGGATTGTGAATGCACCAATCGGCACTCTGTATCTAGCTCAAGGTTGTAAATGGACCAATCAGCACTCTATGTCTAGCTCAGTGTTTGTAAATACACCAATCGACACTCTATCTAGCTAATCTAGTGGGGACGTGGAGAACTTTTGTGTCTAACTCAGGGATGTAAATGCACCAATCAGAACCCTGTCAAAATGGACCAATAGCTCTCTGTAAAACAGACTGACTTTCTGTAAAATGGACCAATCAGCAGGATGTGGGTGGGGCCAGATAAGAGAAGAAAAGCAGGCTGCCTGAGCCAGCAGTGGCAACCCGCTTGGGTCCCCTTCCACACTGTGGAAGCTTTGTTCTTTCGCTCTTTGCAATAAATCTTGCTGCTGCTCACTCTTTGGGTCCACACTGCCTTTATGAGCTGTAACACTCACCGCGAAGGTCTGCAGCTTCATCTGAAGCAGCGAGACACGAACCCACCAGGAGGAACAAACAACTCCGATGCGCTGCCTTAAGAGCTGTAACACCGCGAGGTCTCGAGCTTCACTCCTGAGCCAGCAAGACCACAAACCCACCAGAAGGAAGAAACTCAGGAAAACAGCCGAACATCAGAAGGAATAAACTCTGGACACACCACCTTTAAGAACTGTGACACTCGCTGCGAGCGTCTGTGGCTTCA
>LTR13 LTR from a putative human endogenous retrovirus
TGTGGGCCGCAAGCCAGGGAGCTGCCCAGGCAAGAGCCTGAAGGCACAAGCTGTTCCAGTACAGCAAAGAAAATAATTAGAATAAGAAAAGTTTTACTAGAGATAGGAAACGGATAGGATTATATCTGACTATTATTAATCATTAGTTTGTAGCATCACTCTTTGTTCTATTACCATAATGATCTCTGTTCTATTATGATTACCTTGGGGGAAACCAGGCCACACAGAGTTAGGAGCTGAAGGGCCACAGTGAGAGGTGACCAGAAGACGAGAGTGTGAGCCCTCATTCACGCCCAGAGAAGGGCCGCTGGAGGGCTCCTTGGCCTAGCGGTAATGCCAGTGCCTGGGAAGGCCCTGGTTACTTAGCAGGCCTTGGTCTAGCGGTGGCCCCAGTGCCTGGGAAGGCACCCGTTACTTAGCAGACCCGGAAAGGAATCTCCCTCTCTCCAGGGGAGACAGAGAACGCTCCGCTCCACCACCTCTTGTGGGAGGTCTGACATTAGCCAGGCCGGGCCGAGTCATCCGGAGGCTCCAACGTCTGTCTCCCTGTGATGCTGTGCTTCAGTGGTCACGCTCCTTGTTCACTTTCATGTTCAGCCTGTGCACCTGGCTCCTCCTTTTAAGTTCTTAGAAGACAGCAGTAGCAGAACTAGTAGGAGTACCACAGTCTTCGATCTTTCTGATAAGTGCATAGAAGAAACGCTGACGTTTGCTGTCCTCCCTCTCCACCTCGGCTACCACAAAGGGAAAGGCCCCCTGTCCAGTGGACACGTGACTCGCGTGACCTATCGATCATTGGAGATGACTGGCACTCCTTACCCTGCCCCCTTGCCTTGACTACAATAAATAGCAGCGCCTCCAGGCACTCGGGGCCACTACCTGTCTGTCTCCGCGCTTTGGTGGCAGTGGTCCCCCGGGCCCAGCTGTCTTTCTTCCTATCTCTTTGTCTTCTGTCTTTATCTCTTCGATCTCTCGTCTCCGCACACACGCGAAGAGAAAACCCACAGACCCGGTAGGGGTGGACCCTACA
>MER1A Nonautonomous DNA transposon
CAGGGGTCCCCAACCCCCGGGCCACGGACCGGTACCGGTCCGTGGCCTGTTAGGAACCGGGCTGCACAGCAGGAGGTGAGCGGCGGGCGAGTGAGCGAAGCTTCATCTGTAKTTACAGCCGCTCCCCATCACTCGCATTACCGCCTGAGCTCCACCTCCTGTCAGATCAGCGGTGGCACTAGATTCTCATAGGAGCGCGAACCCTATTGTGAACTGCGCATGCGAGGGATCTAGGTTGCGCGCTCCTTATGAGAATCTAATGCCTGATGATCTGTCGCTGTCTCCCATCACCCCCAGATGGGACCGTCTAGTTGCAGGAAAACAAGCTCAGGGCTCCCACTGATTCTACATTATGGTGAGTTGTRTAATTATTTCATTATATATTACAATGTAATAATAATAGAAATAAAGTGCACAATAAATGTAATGCACTTGAATCATCCCGAAACCATCCCCCCCCCCTGGTCCGTGGAAAAATTGTCTTCCACGAAACCGGTCCCTGGTGCCAAAAAGGTTGGGGACCACTG
>MER1B Nonautonomous DNA transposon
CAGGGGTCCCCAACCCCCGGGCCGCGGACCGGTACCGGTCCGTGGCCTGTTAGGAACYGGGCTGCACAGCAGGAGGTGAGCGGCGGGCGAGTGAGCATTACCGCCTGAGCTCCGCCTCCTGTCAGATCAGCGGCGGCATTAGATTCTCATAGGAGCGCGAACCCTATTGTGAACTGCGCATGCGAGGGATCTAGGTTGCGCACTCCTTATGAGAATCTAATGCCTGATGATCTGAGGTGGAACAGTTTCATCCCGAAACCATCCCCGCCCCCCGGTCCGTGGAAAAATTGTCTTCCACGAAACCGGTCCCTGGTGCCAAAAAGGTTGGGGACCACTG
>MER2 Nonautonomous DNA transposon
CAGTCGYCCCTCCGTATCCGTGYGTTCCACATCCGTGGATTCAACCAACCGCGGATCGAAAATATTCAGGYAAAAAATTGYATGGTTGCGTCTGTACTGAACATGTACAGACTTTTTTNCTTGTCATTATTCCCTAAACAATACAGTATAACAACTATTTACATAGCATTTACATTGTATTAGGTATTATAAGTAATCTAGAGATGATTTAAAGTATACGGGAGGATGTGCGTAGGTTATATGCAAATACTACGCCATTTTATATCAGGGACTTGAGCATCCGCGGATTTTGGTATCTGCGGGGGGTCCTGGAACCAATCCCCCACGGATACCGAGGGATYACTG
>MER3 Nonautonomous DNA transposon
CAGCGCTGTCCAATAGAACTTTCTGTGGTGATGGAAATGTTCTATATCTGCGCTGTCCAATACGGTAGCCACTAGCCACATGTGGCTAYTGAGCACTTGAAATGTGGYTAGTGCGACTGAGGAACTGAATTTTTAATTTTATTTAATTTTAATTAATTTAAATTTAAATAGCCACATGTGGCTAGTGGCTACCATATTGGACAGCGCAG
>MER4A a consensus
TGTGAAAGGAAAATAAATCTCGGGRCCCCMAAATCACTAAGCCAAAGGGAAAAGTCAAGCTGGGAACTGCGTYAGGCAAACCTGCCTCCCATTTTATTCCTAAATAAGATAGCTACAAAGATAAAAGGCTACATACCTCTCTCACAATTTYCYACAAGGAAATTCCTTGCGGACCTCAAGATCTTTACCCTAAAACAGTTCTGYTGAMYTTCACCTTGGCAWTGYAAATGGRTACAGGACAAAGGTACAGAACTGAAAGTCATCCCTCTGCTCACCTGAGACAAATGCATATCTGATTGCTTCCTCTGCCCTATTGTTTATGTAAAAATGCAGATTCACTGAGCCAGACTMAATTGTGTATTCAGTGAAARGCTGATCARRGACTCAAAAGAATGMAGCCWTTTGTCTCTTATCTACCTATGACCTGGAAGCCCCTRCTTCGAGTTGTCCCGCCTTTCCAGACCGAACCAATGTACATCTTACATATATTGATTGATGTCTCATGTCTCCCTAAAATGTATAAAASCAAGCTGTRCCCCGACCACCTTGGGCACATGTCGTCAGGACCTCCTGAGGCTGTGTCACGGGTGCGTCCTTAACCTTGGCAAAATAAACTTTCTAAATTGAYTGAGACCTGTCTCAGATACTTTTGGGTTCACA
>MER4B a consensus
TGTAAACCAAAAATAAAATTCTAAGKCCCCCAACCGTCTGAATGGACYCCTCCTCTYGGCCAAGGGCAYTCCAAAGYTAACCTGRAAAACTAGTTCAGGCCATGATGGGAAGTGGGGGTCGGACACGCCTCATTATACCYTCCYYCTTCTGGAATTCAGGCACAACTGACCAGCATTAACATCAACACAGACNTTAAGTCTGATAAGAAACAGTTTACAAYCTRTTCTCTCTGAAGCCTGCTANCTGAARGCTTCATCTGCACGATAAAACTTGGTCTCCGCAACCCCTTATNTCATAACCCGGACATTCCTTTCCATTGATCTYAANTCTTCAACCARTTGCCAATCAGAAAATCTTTGAATCTACCTATGACCTGGAAGCCCCCGCTTCGAGTTGTCCCGCCTTTCCGGACCGAACCAATGTACATCTTACATGTATTTGATTGATGCCTCATGTCTCCCTAAAATGTATAAAASCAAGCTGTRCCCCGACCACCTTGGGCACATGTKGTCAGGACCTCCTGAGGCTGTGTCACGGGTGCGTCCTTAACCTTGGCAAAATAAACTTTCTAAATTGAYTGAGACCTGTCTCAGATACTTTTGGGTTCACA
>MER4C a consensus
GTTRGNGTTRGNGATTGCNNNTGTGAAAGGAAAATAAAAACTTGGGACCCNAATTCACTNTGCCAAAAGGAAAAAATTAAGCTGAAANCTGAGTCATGCAAGAAACTGCCTTTCCTTTTNTTCCTAAGCAGATANCTACAGATAAAAGGTTAAATATCTCCACAGRCAGTGACTCTATGTTCACCTTYCYTATGTAAAGTGKCGATTTACTGAGCACGMKAKGRATAGATAATTGACTATTCCCCTACCTGCTCCTTTTCTCTTGCAACATGTGGATTACCAYAMCCTYYYTCTTTCCCCTCCAGCCTACYTTTCCCNTTTAAATATTGAAGCCCTCAAANTCATCNCTGGAGAAAGGCACAGACCACAGAMTSTTTYTGTRAYTYCGTGTTTCTCCTNGGCATGTCCTTAACNTTGGCAAAATAAACTNCTAAATCGATTGAGACCTGTYTCAGAYACWTTTKGGTTTACA
>MER5a a consensus
CAGTGGTTCTCAAAGTGTGGTCCCCGGACCAGCAGCATCAGCATCACCTGGGAACTTGTTAGAAATGCAGATTCTCGGGCCCCACCCCAGACCTACTGAATCAGAAACTCTGGGRGTGGGGCCCAGCAATCTGTGTTTTAACAAGCYCTCCAGGTGATTCTGATGCATGCTCAAGTTTGAGAACCACTG
>MER5b a consensus
CAGTGGTTCTCAACCYTGGCTGCAYATTAGAATCACCTGGGGAGYTTTTAAAAATCCNGATGCCCGGGCCACACCCCAGACCAATTAAATCAGAATCTCTGGRGGTGGGACCCAGGCATCAGTATTTTTTAAARCTCYYCAGGTGATTCCAATGTGCAGCCAAGGTTGAGAACCACTG
>MER6 Nonautonomous DNA transposon
CAGCAGGTCCTCGAATAACGCCGTTTCATTCAACGTCGTTTCGTTATAACGYTGATGAGRAAAAAAATCGATTCCCGGCCGGGGCCACTGTCTGTGTGGAGTTTGCACGTTCTCCCCATGTCTGCGTGGGTTTTCTCCAGGTACTCCGGTTTCCTYCCACATCCCAAAGATGTGCACGTTAGGTTCAYTGGCGTGTCTACATGGTCCCAGTCTGAGTGAGTGTGNNTGTGTGTGTGAGTGTGCCCTGCGATGGGATGGCGTCCTGTCCAGGGNTGGYTCCCGCCTTGCGCCCTGAGCTGCCGGGATAGGCTCTGGCCACCCGTGACCCTGAAMTGGAATAAGTGNRTTGRAAAATGAATRAATGAATGARTACGAATTATTATAAAATAAAAATTTGTAAAGTCTATGNTAATCTTACACATACATGACAATACATGAAATGGTAAGAAAGTGATCAGTGAGCCTGCCATATATGTTATTGCTTGTTTCTGAACTGAGTGGTGGGAGGAGGTGTTCCTAACAATGTTCACTTTGCAGACATTTATTTCTTTATTTAATCCATTATCACTATGACCACTGTCATTCAGTKATTCWCCAAAAATTGGGTAAATAATTATCWTRYTTGTTTTTATTAATCTTTCTTAAATGTATGTATAGCTCACATTTATTTCAGTGTTTAATATTAGAAGTGTTTTGGGTCTTTATTTAGAAGTTTGGTGATGTTTTTGTGACCAGAAATATGCCATAGGAACTTAACTCTTGTTTATATCAATTAGCCTRTGGTAAAATTGGTTTCGTTATACGTCGTTTCACTTAAAGTCGCAGTTTCCAAGAACCTATCAACGACGTTAAGTGAGGACTTACTG
>MER7A Nonautonomous DNA transposon
CAGTCATGCGTCGCTTAACGACGGGGATACGTTCTGAGAAATGCGTCATTAGGCAATTTCGTTGTGCGAACATCATAGAGTGTACTTACACAAACCTAGATGGTATAGCCTACTACACACCTAGGCTATRTGGTATAGCCTATTGCTCCTAGGCTACAAACCTGTACAGCATGTTACTGTACTGAATACTGTAGGCAATTGTAACACAATGGTAAGTATTTGTGTATCTAAACATAGAAAAGGTACAGTAAAAATACGGTATTATAATCTTATGGGACCACCGTCGTATATGTGGTCCATCGTTGACCGAAACGTCGTTATGCAGCGCATGACTG
>MER7B Nonautonomous DNA transposon
CAGTCATGCGTCGCTTAACGACGGGGATACGTTCTGAGAAATGCGTCATTAGGCAATTTCGTTGTGCGAACATCATAGAGTGTACTTACACAAACCTAGATGGTATAGCCTACTACACACCTAGGCTATRTGGTATAGCCTATTGCTCCTAGGCTACAAACCTGTACAGCATGTTACTGTACTGAATACTGTAGGCAATTGTAACACAATGGTAAGTATTTGTGTATCTAAACATAGAAAAGGTACAGTAAAAATACGGTATAAAAGATAAAAAATGGTACACCTGTATAGRGCACTTACCATGAATGGAGCTTGCAGGACTGGAAGTTGCTCTGGGTGAGTCAGTGAGTGAGTGGTGAGTGAATGTGAAGGCCTAGGACATTACTGTACACTACTGTAGACTTTATAAACACTGTACACTTAGGCTATACTAAWTTTATWWWWWWWWWWWWWYTTTTTCAGCAATAAATTAACCATAGCTTACTGTAACTTTTTTACTTTATAAACTTTTGCATTTTTAACTTTTGACTCTTTTGTAATAACACTTAGCTTAAAACACAAACACATTGTACAGCTGTACAAAAATATTTTCTTTCTTTATATCCTTATTCTATAAGCTTTTTTCTATTTWWAAATTTTTWATTTTTTTATTTTTTAAAANATTTTTGTTAAAAACTAAGACACAAACACACACATTAGCCTAGGCCTACACAGGGTCAGGATCATYAATATCACTGTCTTCCGCCTCCACATTTTGTCCCACTGGAAGGTCTTCAGGGGCAATAACATGCATGGAGCTGTCATCTCCTATGATAACGATGCYTTCTTCTGGAATATCTCCTGAAGGACCTGCCTGAGNCTGTTTTACAGTTAACTTTTTTTTTTAATAAGTAGAAGGAGTAYACTCTAAAATAATAATAAAAAGTATAGTATAGTAAATACATAAACCAGTAACATAGTCATTTATTATCACTATCAAGTATTATGTACTGTACATAATTGTATGTGCTATACTTTTATACAACTGGCAGCGCAGTAGGTTTGTTTACACCAGCATCGCCACAAACGCGTGAGTAMTGAGTRATATGTTGCACTACAACGTCACTAGGCGATAGGAATTTTTCAGCTCCATTATAATCTTATGGGACCACCGTCGTATATGTGGTCCATCGTTGACCGAAACGTCGTTATGCAGCGCATGACTG
>MER8 Nonautonomous DNA transposon
CAGTTGTCCCTCTGTATANNCGGGGGATTGGTTCCAGGACCCYTGTGTATACMAAAATCCGCGCATACTCAAGTCCCGAAGTCGGCCCTGCGGAACCCACGNATATGAAAAGTCGGCCCTCCATATATACGGGTTTCGCATCCCGCGAATACTGTATTTTCAATCCGCGTTTGATTGAAAAAAATCCGCGTATAAGTGGACCCACGCAGTTCAAACCCGTGTTGTTCAAGGGTCAACTG
>MER9 a consensus
TGCGAGACCAGCTCGACTGGGGACAGCCTAACCCAGTGGCACTAGAGGAATTAAAGACACACACACAGAAATATAGAGGTGTAAAGTGGGAAATCAGGGCCTCACAGCCTTCAGAGCTGAGAGCCCCAAACAGAGATTACCCATGTATTTATTAACAGCAAGCCAGTCATTAGCATTGTTTCTATAGATACTCGATTAACTAAAAGTATCCCTTATGGGAAAAGAAGGGATGGGCCGAAATGAAGGGGTGGGTCTGGCTAGTTATCTGCAGCAGGAACATGCCCTTAAGGCACAGATTGCTCATGCTATTGTTCATGGTTTAAGAACGCCTTTAAGCGGTTTTCCGACCTGGGTGGGCCAGGTGTTCCTTGTCCTCATTCCAGTAAACCCACAACCTTCCAGCGTGGGCGTTANGGCCATCATGAACATGTCACAGTGCTGCAGAGATTTTGTTTATGGCCAGTTTTGGGGCCAGTTTATGGCCAGATTTGGGGGGGCCTGTTCCCAACA
>MER11A a consensus
AGGTGTTGCGGGAAGTCAGGGACCCCGAATGRAGGGACCGGCTGRAGCCATGGCAGARGAACGTRRATTGTGAAGATTTCATGGACATTTATCGGTTCCCAAATTAATACTTTTATAATTTCTTATGCCTGTCTTTACTTTAATCTCTTAATCCTGTTATCTTCGTAAGCTGAGGATGTATGTCACCTCAGGACCACTGTGATAATTGTGTTAACTGTACAAATTGATTGTAAAACGTGTGTTTGAACAATATGAAATCAGTGCACCTTGAAAAAGAACAGAATAACAGCRATTTTTAGGGAACAAGGGAAGACAACCATAAGGTCTGACTGCCTGCAGGGTCGGGCAAAAAGAGCCATATTTTTCTTCTTGCAGAGAGCCTATAAATGGACATGCAAGTAGGGAAGATATCGCTAAATTCTTTTCCTAGCAAGGAATATTAATATTAATACCCTGGGAAAGGAATGCATTCCTGGGGGGAGGTCTATAAACGGCCGCTCTGGGAATGTCTGTCTTATGTGGTTGAGATAAGGACTGAGATACGCCCTGGTCTCCTGCAGTACCCTCAGGCTTACTAGGGTGGGGAAAAACTCCACCCTGGTAAATTTGTGGTCAGACCGGTTCTCTGCTCTCGAACCCTGTTTTCTGTTGTTTAAGATGTTTATCAAGATAATATGTGCACCGCTGAACATAGACCCTTATCAGTAGTTCTGTTTTTGCCCTTTGCCTTGTGATCTTTGTTGGACCCTTATCAGTGGTTCTGCTTTTGCCCTTTGTCCTGTTCCCTCAGAAGCATGTGATCTTTGTTAGACCCTTATTAGTAGTTCTGCTTTTTGCCCTTTGAAGCATGTGATCTTTGTACCCACTCCCTGTTCTTACACCCCCTCCCCTTTTGAAACCCTTAATAAAAAACTTGCTGGTTTGAGGCTCAGGTGGGCATCACAGTCCTACCGATATGTGATGTCACCCCCGGCGGCCCAGCTGTAAAATTCCTCTCTTTATACTGTCTCTCTTTATTTCTCAGCCGGCCGACACTTAGGGAAAATAGAAAGAACCTACGTTGAAATATTGGGGGCGGGTTCCCCCGATACTAATTNTCTT
>MER11B a consensus
TGCAAGTAGGGAAGATATCGCTAAATTCTTTTCCCAGCAAGGAATATTAATAATTAATAGCCCTGGGAAAAGAATGCATTCCTAGGGGGAGGTCTCTRAAATGGCCGCTCTGGGAATGTCTGTCTTATGTGGTTGTAGATAAGGGATGAAATACGCCCTGGTCTCCTGCAGCACCCCCAGGCTTACTAGGATGGTGGGAAATTCCAGCCTGGTAAATTTTAGTCAGACCGGTTCTCTGCTCTCGAACCCTGTCTCCTGTTAAGATGTTATCAATGATAATGCGTGCCCGAAACCTCATTAGCAATTTTAATTTCGCCTCCATCCCTGTGGTCCTGTGATCTCGCCCTGCCTCCATTTGCCTTGTGATATTTTATTGCCCTGTGAAGTATGTGATCTCTGTGACCCACACCCTGTTCGTACACTCCCTCCCCTTTTAAAATCCCTAATAAAAACTTGCTGGTTTGACGGCTCGGGGGGCATCACGGAACCTACCGACATGTGATGTCTCCCCCGGACGCCCAGCTTTAAAATTTCTCTCTTTTGTACTCTKTCCCTTTATTTCTCAGRCCGGCCGACACTTAGGGAAAATAGAAAAGAACCTACGTGAAATATTGGGGCTGGTTCCCCCGATACTAATTNTCTT
>MER20 Nonautonomous DNA transposon
CAGTGGTTCTCAACCGGGGGTGATTTTGCCCCCCAGGGGACATTTGGCAATGTCTGGAGACATTTTTGGTTGTCACAACTGGGGGGGGGGRATGCTACTGGCATCTAGTGGGTAGAGGCCAGGGATGCTGCTAAACATCCTACAATGCACAGGACAGCCCCCACAACAAAGAATTATCCGGCCCAAAATGTCGATAGTGCCAAGGTTGAGAAACCCTG
>MER21 a consensus
GCCCTYCTRTTKCAGRAAAACCTCTCTCAAACCATGTTTTYCCTCTGCTSTCATACCACGACAACAGTCGTCAACACAGAAGACTTCTGTGACCAAATGTGTGGAGGATTTTCCCCACACACCAAGCAGCAGACACCAGCTGGGCGTCCTCCAAYTCAGTTCCGACACTGTCTACCTGGAGATAGCGTCAGATCCCACAGGTTGAGGTCTCAGTCCCCAAGACTGNCCCCACCTTCAGAYACAGTTGCAAGYCCGGGYCTCTGGAACTTCTGACCAACTGGCTTCAARTTGGGGTTCCCACGACACCTCTTTAGGTTCGAYTAATTTGCTAGAGTGGYTCACAAAACTCARRGAAACACTTATTAWGTTTACTGGTTTATTAATAGATGATATTTCAAAGGATACAGATGAAGAGATACATACGGGGCGGTCTGGAAGRKCCCAGCGCAGGAGCTTCCGTCYTGATAGRRTTGGGGTTACACCCTCCAGATTCTTCACCTTCTGTYAGCCTCCACGTGTTCAGCTCTCCAGAAGCTCYCTGAACCCTGTCCTTTGGGCCTTTTATGGAGAYCTCATTGGNTGTCCATGACTGAAGCATGGACGAYTGNNAWAATGTGATTGGRCAAAAAGGGTCTGATCTAATCCCAGCAAGGYCTGTCCAGATTCTTCTTGGTCTCTTTGTGCAGCATTCCTTCCTCCAGGGTATGGGGCAGGACCYCCTCTGGAATGAGGGTCTTACGACCCACAATCAGATTATAGAGTCCTGCCTTGGGCGGMTGAAARGAGGRCARGAGAAGGYCAGAGARATATTCTGTTTCCTGAGGCCTAAAGCACCTCTACATTATAGCGAAAGACTGTAACCATGGTCATGTGAGTTATGGACAAGAACCATGGACAAAAACACATATACAATCATATCCCACCTCCCAACGC
>MER21B a consensus
TCAACACACAACACTTCTGTCACCAAACGTGTGGRRRTTTTTCCCCACACACAAACAAKTCTTCAGTTCTGCGGCGGACACCARCTGGGTGTCCTCCAATTCARTTCAGTTCTGACACTAWCTACCTRGAGATAGCGTCAGATCCCACAGGTTTAAGGGCTCAGTCCCACAAGACTGCCCCCACTTCAGATRCCAGTCGCAAGTCTRGGTTKTCACCCGTACTTCTGACCAACTGGCTATAAATTGTTCCCACGACCCCTCTTTAGGTTCGATTAATTTGCTAGAATRGCTCACARAACTCAGGGAAACACTTATATTTAYCGGTTTATTATAAAGGATATTACAAAGGATACAGATGAACAACCAGATGAAGAGATRCATAGGGCGAGGTMTGGGAGAGTCCNGGGNNCAGGAGCTTCCGTGCCCTCTCTGGSTNNRCCACCTTCCWGGCACCTCCACGTGTTCACCAACCCGGAAGCTCTCCGAACCCTGTCCTTTTGGGTTTTTATGGAGGCTTCATTACGTAGGCATGAYTGATTACATCANTGGCCATTGATTATCAACTCAACCTYCAGCYCCTCTCCYCTCCCCAGAGGTTGGAGGGTGGGGCTGAAAGTTCCAACCYTCTAATCTGCCTTGGTCTTTCTRGCGACCAGCYCCCATCCWGRAGCNTNCTAGGGGCTGCCCRCCAKGAGTCGMCTCATTAGMACAAAAGRNCRTYNCTATTACCCAGGARATTCCAAGGGTTTTAGGAGYTCTGTGTCAGGAACCGGGGTCAAAGACCAAATATTAGAT
>MER22 Human SSTI moderately repetitive DNA sequence family
GAGCTCTGGGCTTCCATACCTGTGTGGGACAGGGAAGCTCTCTCGGTCTCCATGGCCCAAGTGATGGCTGCACGCTCGGTCCAGGAAGAGGCGGAGGAAGCCCACCGCTCCTGACATTGGCCTTCTAGGAAAGGCGGTGTTGCATCCCACCTGCACTTCCTCTCTGATTCTTGAGGGCCAACCGCTTCCTCCGCTCCTGGGGAAAGTGCCTTCTAGCACCGAATCTTTTGGCTGCCACGGATGTCAGGGAGCCAACGGGACTGGGTTTTGGCTGGGTGCAGGGGAGGTTGCGTCAGGGGTACTAGCCGGCGGCGGGCTGGGGGTGGGGTGTACTTTGTCCAAACTCCCGGCTCCTCTGGCGGGCCTCCCTGAACGTGGCGTGGACTCGCGCACAGGCCCTGTCTCGCAGGTTTTCAGGTGCGCTTGGCTTTTCCTCCGCTTTGTGGGGCAGGTCTCCAGTGCCCCCGGCGCACGCCTGGACATCACTGTCCGTCTCGTCGTCGCCCCTACGGCCTCAAAGACACACGCTGCCTGCATGTGCTCTTGGGGGACGACAGTGCACATGTGGACACACTGGCTCCAGCTCGGACTCGCCTCTGTCTCTCTTTGCCCGTGTCGCCGGAAGCCGCCTCGGGTTGCCGGAGCCCTCGGGCCTTGGAGATGAAGGCAGGCCCCTGCTCCTGCCAGGAAGGAGGGAGGCAGTGGGCTCATGGGTCGGTGCCTTTGCAGCCGACAGCACGTGCGGCCCTGGGGATCTTCCTGTGCCCCGGCGAGACCCTTTCCGCCTCACTGCATTGGAACCCCATTCCCGATCACCCGCTGGGATCCATCATCGGACTCCAAGAGGAGTCCGCGCAGCCAGCCGGCACCCCGAAGCTCCTCCTTCAGCGGGAACCGAAGCAGAAGAGCGATCAAGGAGGTCCTCACCACAGGACTCCTATGGGTCCGACCCTGGGTCTCCCGCAGGCCCCTCTGGCAGTCCTCTTCCCACCCGCCGCCTCGGCTTCGCCGCCGCCGCCGCAACCTCCAGCACCGCCCCCCAGGCCCCGCAGCCGCCGTCGCCGCCATTTTTTAAAGGGTCGCAGCCTGACTCTGCGGAGTAAGGGGGGGTGGAGCGGGGGAGTCGCTCGCCAGCATGCGCGAGCCCGAGCCGCCGCTTGGGTCACAGTGAAAGCCACCGTTGCCCGGGGATGGGTCCCTGACACTTGGGGAAGTAGGAGCCCTGTGTGATCGTGCGTCTGAGTCTGGGCTGAGACCAGTCCTGGCCAGGGCAGTTACCAGGACGGTCTCGGAGGCCGGGATTCGCGGAGGGTCCAGCAGCAGGAAGAAACCCCAGGAGGAAGAAACCTCAGACAGATCGCCGGCGAGGCAGCGCGGGATCCCAGCCTCAGGCGTGCGCGGACGGTGTGCGGGTGAGTCTCCCCAAAAGTGGAGCCCTTGTGATGACGAGCACAGGTCCGCCTGCGTGCCCGTGGGCGGCTCTCTCACCGGTGGCTCTCAGTCGCGGAGAGCAGAACCCGCAGCTTCAGGGGCTGCTGCGGGAGGGTGTTCCCTGCTGTACGT
>MER25 Older LINE1 5' end region - a consensus
ACAAANTAGGGAAAAATGGCGGATAGGAGGCAGGACTAAATTGCAGCTCCCACTCGGATGGACAGAGCAGCATGTGGAGACTCACATCGTGAACTTTTGCTCCAAGAACCACCGCAGGAATATAYCAAGAAAGCCGAGAGAATYCACAGACCCTCTGAAGGAAGCAGATTGCTCCTGCARGAYCCAGGAAACGGCCCAAAAACTGTGAGTGCCCAAAGTGTGAGAAGGGRAAAATCTGCCCCCGAACACACATCCTYACTGGGGAACCTGAAGATCCAGATCACAGGAGAAGGATTTGACCTTACCTGGAGCTGAGACAATTTAGAGGGCCGAGCAAAATACAGGGGTAGAGGAAGCAGCGGGAAAAGCCCCGTGGGCACTCCCAGTCYYYAGNNAARCCCAGGGAAGCCATTTCTGACTTATCTCACAGGGGTCCCTTGGGAGGGCAGCCGGAGGAACTGGGAAAGGGSCACAGGGAAAAGAAAACCTCCAGCTGAACTTTGTAATAATTCCGACCGAKAGAGAAATTTCCTGGCCAGAACTMAGGGCAGGGCGRCGKAAGTGCTGGTGGGAGACCAGAAGTGCTGTTGGGGGGGACACGGTRGGAGTGAGACYTGCCTTTTGAGCTGCATGGGAGCTGGGTGAGGCCTGTNACTGCCAGCTTTCCCCCACTTYCCTGGTGACCTGCATGACACAGAAGAGGCAGCCATAATCCCCCTGGGAACGTAACTCCATTRGCCTGGGAACTACACCCCCATCCCTCACAGTAGCCGCAGCAAGCCCCGCCCAAGGAGACTCTGAGCTCAGACATGCCTAACCCTGCCCCCACCTGATGGTCTTTCTCTACCCACCCTGGTAGCCGAAGACAAAAGACATAAWCTCTTGGGAGCTCTAYGGCCCCACCCATCGCCTGAGAAACWGAAATAYTTAYCYWGGCMAMCTTAGGGCAAGCTTRTATCCWCCCTATACTRTCGCAGCTGATGCCCTCTTGAAAGCGCCACCTCTTGGCTGGAGGCCAACCAACTCAAGACATTACAGCAAYTCAYRACAGAATAACCCTGCCCCTARRRAAGGAGAAAACGACAGCTATCACCACTGCCTGCAACATCCTGGCTAACCAGAGGTCCTGAGTCTGTCCACGTGAYAASTTCACTRCTAKYATAACCAGCATTCGAGAAARCCAGCACACTAAGTCTATCTACAACCAAGGAATCTCACAGAGTCTAYTTCACTCCCCTGCCACCTCCATCAGAGCTGGTGCTGGTATTCACCGCTGRGAGACTTGAAGACAGGTCACATCACWGGATYCYTTGCAGACATTCCCCAGYACCAGCCCGGAGTCTGGTAGCTCCACTGGGTGGCTAGAYCCAGAAGAGCAATAACGATCACTGYAGTCCGGCTCTCAGGAAGTCCCATTCCTAGGRGAAGGGGGAGAGCACCACATCAAGGGAACACCCTGTGGGACAAAAGAATCTGAACGGCAGSCCTTGAGTCCCAGATCTTYCCTCTGACATAGCCTACCCAAATGAGAAGGAACCAGAAAAAYAATTCTGGTAATATGACAAAACAAGGTTCTTTAACACCCCCAAAARATCACACTAGCTCACCAGCAATGGATCCAAACCAAGAAGAAATCYCTGAATTGCCAGAAAAAGAATTCAGAAGGTCGATTATTAAGCTACTCAAGGAGGCACCGAGGAAGGTGAANACCAACTTAAAGAAANTTANAATATAATACAGGATATGAATGRARAAATCTYCAGWGAAANAGATAGCATAAAKAAAAAACAATCAMAACTTCWGGAAATCGAAGYACACTTATAGAAATGCGAAATGCWCTGGAAAGTCTCARCAATAGAATNGAACAAGCAGAAGAAAGAACTTCAGAGCTCGAAGACAAGGYTTTCAAATTAACCCAATCCGACAAAGACAAAGAAAAAAGAATAAGAAAATATGAACAAAGCCTCCAAGAAGTCTGGGATTATGTTAAACGACCAAACCTAAGAATAATCGGCGTTCCTGAGNAAGAAGAGAAATCTAAAAGTTTGGAAAACTTATTCGNGGAAATAATCGAGGAAAACTTCCCCGRCSTTGCTARAGAYCTAGAYATCCAAMTACAAAGAAGCTCWAWRAACA
>MER28 Nonautonomous DNA transposon
CAGTTGACCCTTGAACAACATGGGTTTGAACTGCGTGGRTCCACTTATACGCGGATTTTCTTCCATCTCTGCCACCCTGAGACAGCAAGACCAACCCCTCCTCCTCCTCAGCCTACTCAACNTGAAGACGANGAGGATGAAGACCTTTATGATGATCCACTTCCACTTAATGAATAGTAAATATATTTTCTCTTCCTTATGATTTTCTTAATAACATTTTCTTTTCTCTAGCTTACTTTATTGTAAGAATACGGTATATAATACATATAACATACAAAATATGTGTTAATCGACTGTTTATGTTATCGGTAAGGCTTCCAGTCAACAGTAGGCTATTAGTAGTTAAGTTTTKGGGGAGTCAAAAGTTATACGTGGATTTTTNACTGCGCGGGGGGTCAGCGCCCCTAACCCCCGCGTTGTTCAAGGGTCAACTG
>MER30 Nonautonomous DNA transposon
CAGGGGTGTCCAATCTTTTGGCTTCCCTGGGCCACACTGGAAGAAGAAGAATTGTCTTGGGCCACACATAAAATACACTAACACTAACGATAGCTGATGAGCTWAAAAAAAAAAAAMAATCCCAMAAAAATCTCATAATGTTTTAAGAAAGTTTACGAATTTGTGTTGGGCCGCATTCAAAGCCATCCTGGGCCGCGTGCGGCCCGCGGGCCGCGGGTTGGACAAGCTTG
>MER31 a consensus
CACCCTGCGTATCTGAYCAGGTTCCTCARTCTCCGCCGTCCCCCAGGTAATGTTTGRTCACCTGGCCTGCCTTCAGCTAGAATCCTRTTAGGTCAGTTTAGCAGAATCTCCTTACTCCTGATGTTTCCTCTTRGTAATTTTCCATCCACTGCCCCCGYACTCTGCTCYTTGGCTATAAATCCCCACTTGTCCTTGCTRTATTCGGAGTTGAGYCCAATCTCTCTCCCCTACCGYAAGACYCCATTGCAGTGGTCCCTGTAYCTRTCGNRATGGTCCTGAATAAAGTCTKCCTTACCATGCTTTAACAAGTRTYATTGAAWAATTTTTTTT
>MER33 Nonautonomous DNA transposon
CTGCGCTGTCCAATACGGTAGCCACTAGCCACATGTGGCTATTGAGCACTTGAAATGTGGCTAGTCCAAATTGAGATRTGCTGTAAGTRTAAAATATACACCAGATTTCAAAGACTTAGTACGAAAAAAAGAATGTAAAATATCTCATTAATAATTTTTATATTGATTACATGTTRAAATGATAATATTTTGGATATATTRGGTTAAATAAAATATATTATTAAAATTAATTTCACCTGTTTCTTTTTACTTTTATTAATGTGGCTACTAGAAAATTTAAAATTACATATGTGGCTCGCATTRTATTTCTATTGGACAACGCTG
>MER34 a consensus
TAGGGGAGTGAGAGATCACCTCCAACCCTCCCTCCCCTTTGCTCTTATGTGGGCTCTTTGGTGAATCTAGGAACCAAATTGACACAAGGCAGATTAACAAGAGAAAAGCATACAAATTTCATTAGTTTTACATGTGCATAGGAAYCCTCACAAAAGTCAAGYCCAGAGAAGCGGCCAAAGTAAGATGCYTTTATACTTTTTNNACAAAGNACAATAARYTNNRRAARTGTCAGAAGAAAGGGGATCTGGCTAGGGGCAGTAAATTTCTCGCGGAGTCATTAGGAGAAAAGTGTGTGTGTTGGGGTGTAAACTTAGTGGAAGATAACGGTTACTTCGGAAAGTATATTCAGGTCCAAAGCAGCCCCCAGTTTCGTCTCTGGTGATAGGTGCTATTTTCTCCCTCTGGTAAGGGACGGGTACTCCAGAGGAATCCTGGAGGAAGCTTTATGCGCTTGCTGCATGCAGGAAGAGATAGGTCATCAAACCTTTTCTGAAACTACAATTTCTCCAATATTTTCAACTCGAAATAATCAATGTACCAATTCCATATATTTTTGGGATGGCACATCCATCAGTCCTTC
>MER35 a consensus
GATGTGGCGTTTGAGTGGACACGGGGGAAGAAACAAGTAATATGAATAACATGGTGAGACAGAAAGAGTTGTGGACAGAGCTGTGGGAAATATGAGAGATAAGGAGAGAGATACTGAAAAGAGCGTTAAGAGAGATGAAGATAGGGTGTCTGGCCCATGAAGGCCCTCGTGAAGAGCAATGCTGAATAGATGAATGAACCTCAATGCCCAGCAGTGGTGGGATGAAAAGGGGATCCTGTGCAGAAACCACACTACCCATCAGAGAAGCAACTCTGCTCGTTTCCCCTTGA
>MER39 a consensus
GGGCATTANNNCTGTAGGGGCAGAAAGGTGTGATNCCTTCCCTACCCATCATAAGGGTCACGGCNNACACTCCTATAATAAAANAYAGGTTAGCAAGAGAAAAGCATAAYAGATTTATTTAATCAAAGTTTTATGTGACATGRGAGCCTTCAGAAATGAAGACMCAAAKACTCAGGGAAAACTCTATTTTTATGYTTAGATTTGATGAAGAATGGANAGCTGCGCAGAAATGTGATTRGACAAAAGGGGWATGATCTAATGGTMATARACTGRGTGTGGRAACCCAGCAAGGCTTGTCTGTTCGTATTCTTCTTGGTCTMTCTGTGCGGCATTCCTTCCTCCCGGGTATAGGGCGGGACCCCTTCTGGAATGAGGGTCTTATGACCTACWATCAGACGAGATAGGTCAGAWAATTTCTTTACGGSCAGCYCYAAGACAGAAAGGCGGGKRAWGATTAGAGGGCNAGAGAAGGTCAGAAAATGANNTTCTGTTTYCTGAGGNCTGCTTCTGAGGCTTAGAGCGCCCCAACATTNTAACAAAAGNCTGTCCNTCACCTTTACCGCTCTGAAGCTGTTCCAAAGCTGCTACATGAACCAAGGACAAAAAGCCANATANTTCAACAAAAGATATNCTTATNGTTTTAGTCACTCAGGAAACAGCAAGGCTTATAGGAGCTGAGAACCCGGAATTATG
>MER41 Medium reiteration sequence MER41
AACCTGCCAAGAACAGAAACTGGCAGAATCTGTCACAAGAAAAAGTCCCAATCAGACTTCAAGAGAGGGTTCTTGGATCTTGTGCAAGAAAGAATTCATGGGGAGTCTGAGTAAAGTGAAAGCAAGTTTATTAAGAAAGAGGAATAAGAGAATGGCTACTCCAAAGACAGAGCAGCCCTGAGGGCTGCTGGTTGCCTATTTTTATGGTTATTTCTTGATTATATGCTAAGCAAGGGGTGCATTATTTAAGCCTCCCCTTTTTAGGCCATATGGGGTTATATCCTGATGTTACTATGGCATTTGTAAACTATTATGGTGCTGGTGGGAGTGTAGCAGTGAGGACGACCAGCAGTCACTCCCATGGCCATATTGGTTTTGGTGGGTTTTAGCCGGCTTCTTTCTGCAACCTGTTTTATCAGCAAGGTTTTAAGGACCTGTATCTTGTGCTGACCTCTTATCTCATCCTGTGACTTAGAATGCCTTAACTGTCTGAGGATGCAGCCCAGTAGGTTTCAGCCTTATTTTACTCAGCTCCTATTCAGGATGAAGTTGCTCTAGTTCATATGTCTTAGACATTTCCTCCTTCCCTTT
>MER42a MER42 repetitive sequence: subfamily MER42a - a consensus
ATGTAYAGKAGGATTGATCAAATAAGTAAACGTATTNAAGATAATGGGAGCCAGGTTTCTCACTGTCGGAGAAGGGAGTTACAAATATGGAAAGGGRGAAGRCTAGAATGAACCCTGTGGTATTRGATTRGAATTGGAGGTATCAGTRTGAACTCATGRTTTTTAATATAYRYRYRYRYRTTTTTCCTAGTCCTGTCCACTGAGAGGGCCTAGAAGCAACGACACCCCAGTAGCAACGAGCACACCTAGCACCCAGATCTTGGTTTCTAATACCATTCTCCAATAAAAGGAACCAGGGCTCCTTGGAGAAATGGCTGATTCTAGGACTAGGGCAGGAAATATACAAGATGAGCCTGGAACATCTTGTARTGCCAGAAAATAAGGAAGTGCTCAAAAAACGATRRGGGTATGTCAAARGGACACAGAAGCCAACTGAAAGAGCTCCCAATGGCCAAAGCTGGAACAATTTGAGCAACAAAATAAATTATRGTAGTATTGGATTATAACTCAAAGTATAAAATAAATATCCATGAGTTCATACTAATACAAATAAATGATTAAATAAATAAATAAATTGAGAARATAAATAAGTCTTTCTTGCAGAAGAATTTCAAATAATTTATGTAGATARCCTCCCCTCAAGGAAGTGGAGCGTAAYTCCCCACTCCTTAAGTGTGGGATGGRTATAGTGACTTCCTTCYAGAAAGNATAGTNTAGGACGGAARAAAAAGTAAATTTACAGTAGAGAAACCTGACAAACACTACCTTAGCCARRTAATCAARGTTAGCATCAACGATAATARGTCATGYTGATARTATATANCCTTRATATGATGTGATAAGAATGGCACTTTACCTCCGTGGTCTTCCTCCCAAAAACCCATAACCCCAGTCTAATCATRAGAAAATATCAGACAAATTCCAACTGAGGRACATTCTACAAAATACCTGACCAGTACTCCTCAAAACTGTCAAGGTCATCAAAAACAAGRAAAGTCTGAGAAACTGTCACAGCYAARAGGAGCCTAARGAGACATGACAACTAAATGTAATGTGGTATCCTGRATGGGATCCTGGAACAGAAAAAGGACATTAGGTAAAAACTAAGGAAATMTGAATAAAGTATGTACTTTAGTTAATAATAATGTATCAATATTGGTTTATTAGTTGTGACAAATGTACYATANTAATGTAAGATGTTAAYARTAGGGGAAACTGGATGTGGGGTAYATGGGAACTCTCTGTACTATTTTTGCAACTTTCCTGTAAATCTAAAACTATTTTAAAATAAAAT
>MER42c MER42 repetitive sequence: subfamily MER42c - a consensus
ATGTAYAGKAGGATTGATCAAATAAGTAAACGTATTNAAGATAATGGGAGCCAGGTTTCTCACTGTCGGAGAAGGGAGTTACAAATATGGAAAGGGRGAAGRCTAGAATGAACCCTGTGGTATTRGATTRGAATTGGAGGTATCAGTRTGAACTCATGRTTTTTAATATAYRYRYRYRYRTTTTTCCTAGTCCTGTCCACTGAGAGGGCCTAGAAGCAACGACACCCCAGTAGCAACGAGCACACCTAGCACCCAGATCTTGGTTTCTAAATACCATTCTCCACTAAAAGGAACCAGGGCTCCTTGGAGAAATGGCTGATTCTAGGACTAGGGCAGGAAATGTACAAGATGAGCCTGGAACATCTTGTTRTGCCAGAAAATAAGGAAGTGCTCAAAAAACGATRRGGGCATRTCAAAAGGACACAGAAGCCAGCTTGAAGGGGCTCCCACTGGCCAAATCTGGGACAATTTGAGCATCAAAATAAATAATRGTAGTAATGGATTATAACTCATTGAATAAAATAAATATCCATGAGTTCATACTAATATAAATAAATGAATAAAAWAAATAAATGAGAARGGAAAGCTCTTCTTACAGTNGAATGCCAANTAATAAATNTAGAARGAATAATAATAGAAAAATCACCATTAGGCAAAYACCGCAGTAATAACTGTTTYAGGCAAGATCCATCGATAGATGCTMTAATTAGTGGGCGAAARTTTGATGAGAAACGGRATATTTGCATAGTCTCAAAGTATCTCCTCACAAGATATTTATTAATTACAAAGGGAAAAAYAGTGACTTTACAGTAGAGAAACCTGGCAGACACCACCTTAACCAAGTGATCAARGTTANCATCACCAAAAATGAGACAAAYTGACATCATGCGCYNCCTGATRTGATGCGCCGAGAAGAACAACATSGCTTCTGTGATATTCCTGCCAAAGATGCATAACCTGAATCTAATCATRAGAAAATATCAGACAAACCCAAATTGAGGGACAKTCTACAAAATAACTGGNCTGTACTCATCAAAARTGTCAAGGTCATAAAAGACAARGAAAGACTGAGGAACTTTCTACNTTTGACGGAAGACTAGARNCATGACAACTAAATGCAACGCGGGATTCTGRANTGGATCCTGGRTCGAGAAATAGTGGGAGTTTKTAYCTATAAAGGACATTATTGGGACANTTGRCGAAATTTGAATANGGTCTGNAGATTAGATAATAGTATTGTATCAATGTTAATTTCCTGATTTTGATAATTGTAYTGTGGTTATGTAAGAGAATGTCCTTGTTTTTAGGAAANACACACTGAAGTATTTAGGGGTAAAAGGNCATSATGTCTGCAACTTACTCTCAAATRGTTCAGRAAAAAAAATNNATATAYATAARYAGAGAATGATAAAGCAAATGCGGYAAAATGTTAACAATTGGTGAATCTGGGTGAAGGGTATACGGGWGTTCTTTGTACTATTCTTGCAACTTTTCTGTAAGTTTGAAATTACTTCAAAATAAA
>MER43 Homo sapiens clone DOE1-35 MER repetitive sequence - a consensus
CCCAAGCCCAGTAACGCTGTGGCTCTTGCAGACTCNTAGAGGTACTGCCTTNRTGGTCTTGGATAAGATCTGGAAGAATTCCCTGGATTACCAGGCAGAGACTCTTGTTCTCTTCCCTTACTTTCTCCCAAACAAACAAATGGAGTCTCTCTCTCTNTCTGTGCTGAGCTGCCTAGANCTGNGGGWGGGGTGACACAAGCACCCCTGTGGCCACCACCACTGGGACTGTGCTGGGTCAGACCTGAAGCCAGCACAGCATTGGGTCTCACCCA
>MER44A Nonautonomous DNA transposon
CAGTAGTCCCCCCTTATCCGCGGGGGATACGTTCCAAGACCCCCAGTGGATGCCTGAAACCACAGATAGTACCGAACCCTATATATACTATGTTTTTTCCTATATATATATACCTATGATAAAGTTTAATTTATAAATTAGGCACAGTAAGAGATTAACAATAACTAATAAAATAGAACAATTATAACAATATACCGTAATAAAAGTTATGTGAATGTGGTCTCTTTCTCTCAAAATATCTTATTGTACTGTACTCACCTATTTTCGGACCGCGGTTGACCATGGGTAACTGAAACTRCGGAAAGTGAAACCGCGGATAAGGRGGGACTACTG
>MER44C Nonautonomous DNA transposon
CAGTAGTCCCCCCTTATCCACGGGGGATACGTTCCAAGACCCCCAGTGGATGCCTGAAACCACGGATAGTACCGAACCCTATTGCTATCAGTCTTTTGGAACATGTTTCTGTTCATGTCTTCTGCCCACAAATTTAATGCCTCTTCCACCTCAACTAAACACGTATCATGCACTCCGGCCATCACTTTTGCAGTTTGAGGTATGACATCAAAACTAGCATGAATTTATTTTTCCTTCTTCACAATTCCAAAGATGGAAGATTCTTTCTTACCGTAGATCTTAGCAACCTCAGCATACGATTATTTTTCYTTTCTTTTTAAGTCAAGAACTTTCACCTTTTCGCTTAAAGGAAGCACTTTACAGCTTCTYTTTGGCATGTCCGAATTGCCACCAACACTACTCTTGTGCTTTTGGGCCATTATTAAGTAAAACGGGAGTTACTTGAACACAAGCACTGTGATACCAAGACAGTCGGTCTGATAACTGAGATGGCTACTAAGTGATTAACAGGCAGGTAGCGTANACGGCGTGGATACGCTGGACAAAGGGATGATTCACATCCCGGATGGGACGGCGCGAAATTTCATCACGCTACTCAGAACGGCGCGYAATTTAAAACTTATGAATTGTTTATTTCTGNAATTTTCAATTTAATATTTTCGGACCGCAGTTGACCACGGGTAACTGAAACCACAGAAAGTRAAACCACGGATAAGGGGGGACTGCTG
>MER45 Nonautonomous DNA transposon
CAGGACCGGCTACATAATTTGCGGGRCCCAGTGCAAAATGAAAATGCGGGGCCCCTTGTTCAAAAATTATTAAGAATTTCAAGACGGCGACAGCAGAGCATTAAACCAAGCACGGGGCCCTTCTRAGCGCGGGGCCCTGTGTGACTGCACAGGTCGCACGCCCATGAAGCCGGCCCTG
>MER46 Nonautonomous DNA transposon
CAGGTTGAGTATCCCTTATCCAAAATGCTTGGGACCAGAAGTGTTTCGGATTTCGGATTTTTGGATTTTGGAATATTTGCATTATACTTACCGGTTGAGCATCCCAAATCTGAAAATCCGAAATCCAAAACGCTCCAATGAGCATTTCCTTTGAGCGTCATGTCGGCGYTCAAAAAGTTTCGGATTTTGGAGCATTTCGGATTTCGGATTTTCGGATTWGGGATGCTCAAYCTG
>LOR1 Human low copy repetitive sequence - a consensus
TGTTACTGAACACCAGGGGTTCGGTCTAGGTCCTGCTGCTCGCCACACAGAAAGCCAATCACTGAGACAATAAGTATTGCCAAGGAAGAAGGCTTTAATCGGGTGCTGCAGCCGAGGAGACGGGAGATCAGTCTCAAATCCATCTCCCTGACCGACTAAAATTAGGGGTTTATATAGCAGGGAAGAAATGTAACCGTGTGTGGGAAAACAGGAATTAGGGAGGGGTAAGGAAGAGAATTTGGTCAACAGGAAGCAGGTGGTCAGTTAGGCAATCATGATGGGTGAGGGGTCTGACGTCTCATTGTCCGGATGCAGTGATCTGGTAAGTTTCAGCTCCTTGATACTATCTGGGAGGCCTGATGGTTGGTTTCCTGAAAAAGGAACTCAGATAAGACAAATGTAACTTTCTCGAGTTTTAAGACTGGGAGAATCARTTTCTATGTTTATTCAAAGAAACCATAAACATCAGTTCTATGGGACAATTGGGTCAGTTTCAATTG
>SVA Composite retroposon
CTCCCTCTCCCTCACCCTCTCCCCATGGTCTCCCTCTCCCTCTCTTTCCACGGTCTCCCTCTGATGCCGAGCCGAAGCTGGACGGTACTGCTGCCATCTCGGCTCACTGCAACCTCCCTGCCTGATTCTCCTGCCTCAGCTTGCCGAGTGCCTGCGATTGCAGGCGCGCGCCGCCACGCCTGACTGGTTTTCGTATTTTGTTAGTGGAGACGGGGTTTCGCTGTGTTGGCCGGGCTGGTCTCCAGCTCCTAACCGCGAGTGATCCACCAGCCTCGGCCTCCCGAGGTGCTGGGATTGCAGACGGAGTCTCGTTCACTCAGTGCTCAATGATGCCCAGGCTGGAGTGCAGTGGCGTGATCTCGGCTCGCTACAACCTCCACCTCCCAGCAGCCTGCCTTGGCCTCCCAAAGTGCCGAGATTGCAGCCTCTGCCCGGCCGCCACCCCGTCTGGGAAGTGAGGAGTGTCTCCGCCTGGCCACCCATCGTCTGGGATGTGAGGAGCGTCTCTGCCCTGCCGCCCATCGTCTGAGATGTGGGGAGCACCTCTGCCCGGCCGCCCCGTCCGGGATGTGAGGAGCGTCGCTGCCCGGCCGCCCCGTCTGAGAAGTGAGGAGACCCTCTGCCTGGCAACCGCTCCATCTGAGAAGTGAGGAGCCCCTCCGCCCGGCAGCCGCCCTGTCTGAGAAGTGAGGAGCCCCTCCGCCCAGCAGCCACCTGGTCCGGGAGGGAGGTGGGGGGGTCAGCCCCCCGCCCGGCCAGCCGCCCCGTCCGGGAGGGAGGTGGGGGGGTCAGCCCCCAGCCCGGCCAGCCGCCCCGTCCGGGAAGTGAGGGGCGCCTCTGCCCGGCCGCCCCTACTGGGAAGTGAGGAGCCACTTTGCCCGGCCAGCCACTCTGTCCGGGAGGGAGGTGGGGGGGTCAGCCCCCCGCCCGGCCAGCCGCCCCGTCCGGGAGGGAGGTGGGGGGATCAGCCCCCCGCCCAGCCAGCCGCCCCGTCCGGGAGGGAGGTGGGGGGGTCAGCCCCCCGCCCGGCCAGCCGCCCTGTCCGGGAGGTGAGGGGCGCCTCTGCCCGGCCGCGCCTACTGGAAAGTGAGGAGCCCCTCTGCCCGGCCACCACCCCGTCTGGGAGGTGTGCCCAACAGCTCATTGAGAAGGGGCCATGATGACAATGGCGGTTTTGTGGAATAGAAAGGGGGGAAAGGTGGGGAAAAGATTGAGAAATCGGATGGTTGCCGTGTCTGTGTAGAAAGAGGTAGACCTGGGAGACTTTTCATTTTGTTCTGTACTAAGAAAAATTCTTCTGCCTTGGGATCCTGTTGATCGGTGACCTTACCCCCAACCCTGTGCTCTCTGAAACATGTGCTGTATCCACTCAGGGTTGAATGGATTAAGAGCGGTGCAAGATGTGCTTTGTTAAACAGATGCTTGAAGGCAGCATGCTCCTTAAGAGTCATCACCACTCCCTAATCTCAAGTACCCAGGGACACAAACACTGCGGAAGGCCGCAGGGTCCTCTGCCTAGGAAAACCAGAGACCTTTGTTCACTTGTTTATCTGCTGACCTTCCCTCCACTATTGTCCTGTGACCCTGCCAAATCCCCCTCTGTGAGAAACACCCAAGAATGATCAATAAAAAAAAAAAAA
>ALR Human alpha repetitive DNA - a consensus
AATTCTCAGTAACTTCCTTGTGTTGTGTGTATTCAACTCACAGAGTTGAACGATCCTTTACACAGAGCAGACTTGAAACACTCTTTTTGTGGAATTTGCAAGTGGAGATTTCAGCCGCTTTGAGGTCAATGGTAGAATAGGAAATATCTTCCTATAGAAACTAGACAGAAT
>MSR1 Human 37 BP minisatellite repeats, specific to chromosome 19
AGTCAAGACCCCCAGCCCCTCCTCCCTCAGACCCAGGAGTCAAGAACCCCCAGCCCCTCCTCCCTCAGACCCAGGAGTCAAGAACCCCCAGCCCCTCCTCCCTCAGACCCAGGAGTCAAGACCCCCCAGCCCCTCCTCCCTCAGACTCATGAGTCCAGACCCCCAGCCCCTCCTCCCTCAGACCCAGGAGTCCAGACCCCCAGCCCCTCCTCCCTCAGACCCAGGAGTCCAGACCCCCAGCCCCTCCTCCCTCAGACCCAGGAGTCCAGGCCCCACCCCTC
>TAR1 Human telomere associated repeat sequence, complete sequence
GATCAACAGTGAGGAGGTCCCACAAGGCTAAGTGGGGCAAGTCGGGGACCTAAGGCAGTAGCAGGAAAACCAAAGAAAACAGGCGGAGACTTGAGACAGAGGCAGGAATGTGAAGAAGTCCAAAATAAAAATCCCTGCACAGGACTCTTAGGCTGTTATCATGCACTATCAGCCTACTCCTCCCTATTTTTGTACAATAAGCTCTTTACACTGTATTTCTTTTCAATGAAGTTATCTTCCATCTTTGTACTGCCTCTTGGTGAAAAGCTGTCTTCCAAGTTAATAACTGGGACATCAGCTCTCTGCAGTAATAGCTCCTTTTCAGTTTTAATTTGCAGAACTGATGGGGATTAATAACTGGCGCTCTGACTTTAAGTGGTGCAGGAGGCGGCCAGTAGGGGACGCCAGCCGTTACGCCGGGAGCAAGAGGGCCCTGCGTAGTCCCCATCTGCCTGCATGTGGCGTGCAGCCACGACAATGGCAGCAAGAGGGCCCGGCAGTGTGCCCAGCTGCCAGCAGGCGGGTGTGCTGCCACTATAATGTGAGGAAGAGGGCCCTGCAATGTCCCTAGCTGCCAGCAGGCGGCGTGCCACCACTATACTGCGAGCAAGAGAGCCCTGCCGTGCCCCGGCGCCAGCAGGGGGCGCTGGACAGCACTGTAAGCAAGAGGGCCCTGCAGTTGTCCTAGTCGCCAGTAGGGGACGCAATGGCAGAGCACCGTGGGCAAGCTGGTCCTGTAGTGCCCGGCTGCAAGCAGGGGGCGCCCGAAACGGGCTTTTCAGATTACTCAGGTTCCACTCGTCTCTGCGCCGCCGGGGACGTGTGTCTCTGCGCGTGCACCGCGCCACCCCCGCGCTCCCCGCCCGGCGGCGCGCGACTGTGCGACTGCAACACTCCCCGCCACCCTCAGCCCAGCGACGTGCGTCTCTGCGCCTGCGCCGCGCCTCACTCCCGCCCGCTCAGCGACCCCTCCCTTCCGGGGAGGCGCCGGCGTGCGTCTACGCCCTGCGCCGCGTCTCCCCAACAGCGGCGCGCCTCTCTGCGCCTGCGCCGGCGCGCCGCGCCTCTCTGCGCCTGCGCCGGCGCGCCGCGCCTCTCTGCGCCTGCGCCGGCGCCCCGCGCCTCTCTGCGCCTGCGCCGGCGCCCCGCGCCTCTCTGCGCCTGCGCCGGCGCCCCGCGCCTCTCTGCGCCTGCGCCGGCGCCCCGCGCCTCTCTGCGCCTGCGCCGGCGCCCCGCGCCTCTCTGCGCCTGCGCCGGCGCCCCGCGCCTCTCTGCGCCTGCGCCGGCGCCCCGCGCCTCTCTGCGCCTGCGCCGGCGCCCCGCGCCTCTCTGCGCCTGCGCCGGCGCCCCGCGCCTCTCTGCGCCTGCGCCGGCGCCCCGCGCCTCTCTGCGCCTGCGCCGGCGCCCCGCGCCTCTCTGCGCCTGCGCCGGCGCCCCGCGCCTCTCTGCGCCTGCGCCGGCGCCCCGCGCCTCTCTGCGCCTGCGCCGGCGCCCCGCGCCTCTCTGCGCCTGCGCCGGCGCCCCGCGCCTCTCTGCGCCTGCGCCGGCGCGCCGCCTTTGCGAGGGCGGAGTTGCGTTCTCTTTAGCACACACCCGGAGAGCATCGCGAGGGCGGAGCTGCGTTCTCCTCTGCACAGACTTCGGGGGTATTGCGAAGGCGGAGCAGAGTTCTTCTCAGGTCAGACCCGGGCGGGCGGGCTGAGGGCACTGCGAGGGTGGAGCTGCGTTCTGTTCAGCACAGACGTGGGGGGCACCGTAAAGGCGGAGCAGCATTCTTCTCAGCACAGACGTTGGGGGTACTGCCTGCCTTTGGGATAACTCGGGGCCGCATCGAGGGTGAATAAAATCTTTCCCGTTTGCTGCCCTGAATAATCAAGGTCAGAGACCAGTTAGAACGGTTTAGTGTGGAAAGCGGGAAACGAAAAGCCTCTCTGAATCCTGCGCACCGAGATTCTCCCAAGGCAAGGCGAGGGGCTGTATTGCAGGGTTCAAGTGCAGCGTCAGAACTCAAATGCAGCATTCCTAATGCACACATGACACCCTAAATATAACAGGCATATTACTCATGGAGGGTTAGGGTTCAGGTTCGGGTTCGGGTTCGGGTTCGGGTT
>CER Human D22Z3 repetitive DNA (centromeric DNA)
CTGCAGAACACTACTTCCAGGGTCTAAATGTCTGTCCTTCACATAGGATTCCAGAACACTGCTACGAGAGTGTGAATGTTTGTCCTTCACATAGCATTTCACAACTGCCATGGTCTGAATGGTTGTCCCTCACATAGTATTCCAGAACACTGCTATGAGGGTCTGAATGTTTGTACCTCACATAGGATTCCAGAACACTGCTATGAGGGTCTGAATGTTTGTACCTCACATAGGATTCCAGAACACTGCTATGAGTGTTTGAAAGTTTGTCCCTCACATAGGATTCCAGAAGACTGCTGCTGGGGTCTGAATGTCTGTCCCTCACATCGGATTCCAGAACCCTGCTGCTGGGGTTTGAATGTCTGTCCCTCACATAGAATTC
>BSR Human beta satellite DNA - a consensus
GATCAGTGCAGAGATATGTCACAATGCCCCTGTAGGCAGAGCCTAGACAAGAGTTACATCACCTGGGT
>HSATII Human satellite II DNA
ANTCCATTCGGGTCCATTCGATGATGATCACACTGGATTTCATTCCATAATTCTATTCG
>HSATI Human satellite I DNA HinfI fragment
GANTCNGCTCNNGACACAACTCTCTGAGCCTTCGGTGACCTTTCNGTCTNGTGTAANNGCACTCNTGTCYYCCTGGCAGCAGTTGGACCTCGCGATGTGGATTGTGCCCTCACCCAGCNNTNTTTATGCCCTNTCNCCATGGTGACNGGATTAGGGGTCTCCTGCTCTTCNNTCCTAAGGACCACTGTCTGTGCTGTGTCTTTCAAAGGTCAGAAGAGATTGNACCTTTGTGTTTTTATTTTCCCTGTGTTTGCTTTTTCTCNNTGGGGAACCTGTGTTGCTGCTTTGAAGGTATATTCATACTGGCCNNTCANNTGNNCAACATCNNCAAANTNACTAGTTANGGCTTTCAAAATATGNTATTTCAAAAAATTANCCGTCTGTATTTTCCATATGCAGTTATAAGTAGGTTTCATCGGTTATGTTTTATTCCTCAGTTTATACATTTGATTATTGTACCAAGCAGAGTACCTTTGAAATTTTTTTTCATTTAAAAAATATGGATCTTTAAAAAAAAATTATATATGATATATATTACATGTTATGTGCTATGCCTTATNTGTAACATATAACCTCATATATTTTNTATGTCATAGTATATAATATTTATCCTGTGTCATCTTATATATAC
>R66 A 66bp tandem repeat - a consensus
ACAGAGTGCTGATTGGTGCRTTTACAAACCTTTAGCTAGACACAGAGCGCTGATTGGTGCGTTTTT
>SAR Human satellite I DNA
ACATAAAATATCAAAGTACATCAAATATATATTTTATTCTGT
>SN5 Human centromeric SN5 satellite DNA sequence
CTTCCCTTCAGGGACCTCAAAGTGACCAGCTTCCCCTTGAAGAATGACTCTCCAAGGCCCAGGAGCCCAGCTTCTGGGCCTCCAAGCCAGGCCATCTGGCGAGGGAGTCGGTGGACGTGCCCTGGCTTCTTCCATGTTGAGTTGGTACTACCCACCAAGGGGGGTAGAGAGGCGAGCAGATGTTGTCTCTGGCCTGTGTCTTGTTATCATGGTGCTGACTAGGCCTGGTACAGGGCCCTGATGGGGTTGTCCTGGGTGGTCACGGGGGTGATGAGAAGAAGATGCAGAATGGATTGCTGTGAGGATGAATGAGACGACTGTCAGTACAGACAGGCACACGGTGAAGTGTTCAGGGATTCCCCTCAGTAGCTGCCCAGACCCAAAACCTGACTCCTGAGTCACGTTACTGTCCCACTATACGTTAAGAGGAGGGAAAGCTGGGTCGCGCAGGTCCC
>HY3 Ro(hY3) pseudogene - a consensus
TAGTCAANTGAAGCAGCGGGAGTGGAGAAGGAACAAAGAAATTTGTAACTGGTTGTGATCAATTAGTTGTAAACANCGCTGCACTCCAACCAGCC
>HIR Human HINF family repeat DNA
GATTCCCAGGTGCACAGAGATCCTAATCCGCATCCATCGAAATCTCACAAAGTGTCCATAAATCACTCAGGGAGGGCCCCCATGGATACAGGGCCGTAGTAGGATGCTCCTATAGTGGGCATTAATATGAGAATGACCGAAAAGTGCATTTAGGACCATATTATAATTTTCGGGTTCCCAGGTGCACGTTTCCAATAACCAGGTGCACGGATGTATAGGGTCCCCCCCATGGATAGAGGTCCGTGTTAGGGTGCTCCATATCGGGCATGAATATCAGGAACACCGGCATGTGCACTTAGGACCATGTTTTAATTTTTCA
> satellites 2 and 3
GGAATGGAATGGAATGGAATGGAATGGAATGGAATGGAATGGAATGGAATGGAATGGAATGGAATGGAATGGAAT
>IVR Repetitive sequence from human involucrin gene - a consensus
CAGGAGGGGCAGCTGAAGCACCTGGAGCAG
>7SK Human family A3 repeated element DNA; 7SK RNA pseudogene
GATGTGAGGGCAATCTGGCTGCGACATCTGTCCCCACTGATTACCAGGGTTGATTCGGCTGATCTGGCTGGCTAGGCGGGTCTCCTCTTCCTCCCTCAGCCCTCCATGTGTGTACCTCCTGAAGCGGACTGGTCTTCAGTCAAGGGTAGACGAGTAGCTGTGCTCCCCTGCTAGAACCTCCAAACAAGCTCTC
>KER Human K element interspersed repeat DNA
AGCTCATCTGTCCACTGAAGATGCTTGGACAGAGTTAGGAATGCTTCCTGGGAGAGGTAACATTTGAGACTTTCCTGGAAGAATGGTCAGAGTAAACCAAGTAAGTAGGAATGGAAAGAGGATGGGAGGCCCCAGCTTCCCAGAGGCATAAGGTGAGGANGNCCCTATGCATTCAGATGTGGCCCACCCTGGGGTCTGGTGGACTAAAGNCTTGGACACCCCAGATCAGCCTTAGTGGGATGAGGCAGGAAAGACAGCTGAGGGTCAGAACCCAGGCAGGTCCAATGCCAGGGTGGGCATTTCGAGTTGGTGAGACATTTCACCCTGGTGCCAAGCT
>XTR Repetitive element X-2 from human alpha-fetoprotein gene
TTAATTTGAGAGAAATTAATTATTCTGCAACTTAGGGACAAGTCATGTCTTTGAATATTCTGTAGTTTGAGGAGAATATTTGTTATATTTGCAAAATAAAA
>XBR Xba repetitive element copy A, from human alpha-fetoprotein gene
AATTGATAGGTCACGTTCTCACTCTATTTGCCTTTAAGGGAAGAAAGCAATCAAGTTAATATGTTTTCCTTCATTGTATAGTATGTAACTACGGACACTATTAGAGGAGGGATTTGTGTAGCACTTAGGACATTATACTTGATAATTTCCAAGGGTCTTTCTAGATTTAAAAGTCTGATTCTAACGTAGTAATAAAAATAAAGGCCCAATTTTCTCTTTAATATTGCCTGAAGATATTACTCTATTATTGCATTAAAATTAAACATTCACACATTGTTTGCACTGCTAAATAAAATTATGTAA
>MARINER1 Human mariner
TTAGGTCGGTRCAAAAGTAATTRCGGTTTTTGCAYTGTTGGAATTTGYCATTTGATATTGGAATACATTCTTAAATAAATGTGGTTATGTTATACATCATTTTAATGGGCATTTCTCGCTTTACGTTTTTTTGCTAATGACTTATTACTTGCTGTTTATTTKRTGTTTATTTTAGACTATGNAAATGATGTTAGACAAAAAGCARATTCGAGCGATTTTCTTATTCAAGKTCAAAMTGRRTCGTAAAGCGGCGGAGACAACTCGCAACATCAGCAACGCATTTGGCCCAGGAACTGCTAATAAACATACAGTGCAGTGGTGGTTCAAGAAGTTTTNCAAAGGAGACGAGAGCCTTGAAGATGAGGAGTGTAATGACGGGCCATCAGAAGTTGACAACGACCAGTTGAGAGCAATCATCGAARYCGATCCTCTTACAACTANACGAGAAGTTGCTGAAGAACTCGACGTTGACCATTCTACGGTCGTTCGGCATTTGAAGCAAATTGGRAAGNAAAAACTCGATAAGTGGGTGCCTCATAAAGTGAGCAAAACTTTTTNAAATTGTCATTTTAAAGTGTCATCTCTTATTCTATGCAATAACAACGAACCATTTCTTGATCAGATTGTGACGTAGAACGAAAAGTGGATTTTATACGACAACCGGCGACGACCAGCTCAGTGGTTGGACCGAAAGAAGCTCCAAAGCACTTCCCAAAGCCAAACTTGCACCAAAAAAGTCGCGGTCGCGGTCTGGTGGTCTGCTGCCAGTGTGATCCACCACAGCTTTCTGAATCCTGGCAAAACCATTACATCTGAGAAGTATCTTCAGCAAATTGATGAGATGCACCAAAAACTGCAATGCCTGCACCTGGCATTGGTCAACAGAAAGGGCCCAATTCTTCTCCACGACAACGCCCGACCGCACGTYGCACAACCAACGCTTCAAAAGTTGAATAAATTGGGCTACGAACTTTTGCCTCATCCGCCATATTCACCTGACCTCTCGCCAACAAACTACCACTTCTTCAAGCATCTCGTCAACTTTTTGCAGGGAAAACGCTTCCACAACCAGCAGGATGCAGAAAATGCTTTCCAAGAGTTCGTCGAATCCCAAAGCACGGATTTTTATGCTACAGGAATAAACAAACTTATTTCTCGTTGGCAAAAATGTGTTGATTGTAATGGTTCCTATTTTGATTAATAAAGATGTGYTTGAGCCTAGTTATGATTATGATTTAATGGCCAAAACCACAATTACTTTTGCACCAACCTAA
>Made1 Human mariner derived element 1 - a consensus
TTAGGTTGGTGCAAAAGTAATTGCGGTTTTTGCCATTACTTTYAATGGCAAAAACCGCAATTACTTTTGCACCAACCTAA
>Tigger1 Autonomous DNA transposon
CAGGCATACCTCGTTTTATTGCGCTTCGCTTTATTGCGCTTCGCAGATACTGCGTTTTTTACAAATTGAAGGTTTGTGGCAACCCTGCGTTGAGCAAGTCTGTCGGCGCCATTTTTCCAACAGCATGTGCTCACTTCGTGTCTCTGTGTCACATTTTGGTAATTCTCGCAATATTTCAAACTTTTTCATTATTATTATATCTGTTATGGTGATCTGTGATCAGTGATCTTTGATGTTACTATTGTAATTGTTTTGGGGTGCCACGAACCGCACCCATATAAGACGGCGAACTTAATCGATAAATGTTGTGTGTGTTCTGACTGCTCCACCGACCGGCCGTTCCCCCGTCTCTCTCCCTCTCYTCGGGCCTCCCTATTCCCTGAGACACAACAATATTGAAATTAGGCCAATTAATAACCCTACAATGGCCTCTAAGTGTTCAAGTGAAAGGAAGAGTMRCACATCTCTCACTTTAAATCAAAAGCTAGAAATGATTAAGCTTAGTGAGGAAGGCATGTCAAAAGCCGAGATAGGCCAAAAGCTAGGCCTCTTGCGCCAAACAGTTAGCCAAGTTGTGAATGCAAAGGAAAAGTTCTTGAAGGAAATTAAAAGTGCTACTCCAGTGAACACACGAATGATAAGAAAGYAAAACAGCCTTATTGCTGATATGGAGAAAGTTTTAGTGGTCTGGATAGAAGATCAAACCAGCCACAAYATTCCCTTAAGCCAAAGCCTAATCCAGAGCAAGGCCCTAACTCTCTTCAATTCTATGAAGGCTGAGAGAGGTGAGGAAGCTGCAGAAGAAAAGTTTGAAGCTAGCAGAGGTTGGTTCATGAGGTTTAAGGAAAGAAGCCATCTCCATAACATAAAAGTGCAAGGTGAAGCAGCAAGTGCTGATGTAGAAGCTGCAGCAAGTTATCCAGAAGATCTAGCTAAGATCAYTGATGAAGGTGGCTACACTAAACAACAGATTTTCARTGTAGATGAAACAGCCTTCTATTGGAAGAAGATGCCATCTAGGACTTTCATAGCTAGAGAGGAGAAGTCAATGCCTGGCTTCAAAGCTTCAAAGGACAGGCTGACTCTCTTGTTAGGGGCTAATGCAGCTGGTGACTTTAAGTTGAAGCCAATGCTCATTTACCATTCTGAAAATCCTAGAGCCCTTAAGAATTATGCTAAATCTACTCTGCCTGTGCTCTATAAATGGAACAACAAAGCCTGGATGACAGCACATCTGTTTACAGCATGGTTTACTGAATATTTTAAGCCCACTGTTGAGACCTACTGCTCAGAAAAAAAGATTCCTTTCAAAATATTACTGCTCATTGACAACGCACCTGGTCACCCAAGAGCTCTGATGGAGATGTACAAGGAGATTAATGTTGTTTTCATGCCTGCTAACACAACATCCATTCTGCAGCCCATGGATCAAGGAGTAATTTCGACTTTCAAGTCTTATTATTTAAGAAATACATTTTATAAGGCTATAGCTGCCATAGATAGTGATTCCTCTGATGGATCTGGGCAAAGTAAATTGAAAACCTTCTGGAAAGGATTCACCATTCTAGATGCCATTAAGAACATTCGTGATTCATGGGAGGAGGTCAAAATATCAACATTAACAGGAGTTTGGAAGAAGTTGATTCCAACCCTCATGGATGACTTTGAGGGGTTYAAGACTTCAGTGGAGGAAGTAACTGCAGATGTGGTGGAAATAGCAAGAGAACTAGAATTAGAAGTGGAGCCTGAAGATGTGACTGAATTGCTGCAATCTCATGATAAAACTTGAACGGATGAGGAGTTGCTTCTTATGGATGAGCAAAGAAAGTGGTTTCTTGAGATGGAATCTACTCCTGGTGAAGATGCTGTGAACATTGTTGAAATGACAACAAAGGATTTAGAATATTACATAAACTTAGTTGATAAAGCAGCGGCAGGGTTTGAGAGGATTGACTCCAATTTTGAAAGAAGTTCTACTGTGGGTAAAATGCTGTCAAACAGCATCACATGCTACAGAGAAATCTTTCATGAAAGGAAGAGTCAATTGATGCGGCAAACTTCATTGTTGTCTTATTTTAAGAAATTGCCACAGCCACCCCAACCTTCAGCAACCACCACCCTGATCAGTCAGCAGCCATCAACATCAAGGCAAGACCCTCCACCAGCAAAAAGATTACGACTCGCTGAAGGCTCAGATGATCGTTAGCATTTTTTAGCAATAAAGTATTTTTAAATTAAGGTATGTACATTGTTTTTTAGACATAATGCTATTGCACACTTAATAGACTACAGTATAGCGTAAACATAACTTTTATATGCACTGGGAAACCAAAAAATTCGTGTGACTCGCTTTATTGCGATATTCGCTTTATTGCGGTGGTCTGGAACCGAACCCGCAATATCTCCGAGGTATGCCTG
>Tigger2 Autonomous DNA transposon
CAGTTGACCCTTGAACAACACGGGTTTGAACTGCGCGGGTCCACTTATACGTGRATTTTTTYCAATAAATATATTGGAAAAAWTTYTGGAGATTTGCAACAATTTGAAAAAACTCGCAGACGAACCGCGTAGCCTAGAAATATTGAAAAAATTAAGAAAAAGGTATGTCATGAATGTATAAAATATATGTAGATACTAGTCTATTTTATCATTTACTACCATAAAATAYACACAAANCTATTATAAAAAGTTAAAATTTATCAAAACTTAYAYAYAYACTTACAGACTGTACGTGGTACCATTCGAAGTNGAGAGAAATATAAACAAACNTAAAGATGCAGTATTAAATCACAACTGCGTAAAATTAACTGTAGTACATACTATACTACCGTAATAATTTTGTAGCCACCTCCTGTTGCTATTGCAGCGAGCTCAAGTGTTGTGAGTACCTGCTTAAAACGCTSKGTGATGCTAATCATCTCCGCGCGAGCAGTTYATCTCTCCAGTAAATTGCGTATTGCAGTAAAAAGTGATCTCTCACGGTTCTCGCGTATTTTTCATTGTGTTTARTGCAATATTGTAAACCTTGAATAACACCATGGGACCCATACGAAGTGCCACTAGTGATGCTGGAAGTGCTCCCAAGAAGCAGAGAAAAGTCATGACATTACAAGAAAAAGTTGAATTGCTTGATATGTACCATAGATTGAGGTCTGCAGCTGGGGTTGCCTGCCATTTCAAGAYAGATGAATCCGGCGTAAGGACCGTTGTMAAAAAAGAAAAGGAAATTCGTGAARACCGTCGCTGCAGTTATGCCCAGCAGGCACAAAAACTTGTNACTTTTTGCGAAATACCTTTTTATGTTGTATTGAAAATGCAGCTTTTNTGTGGGTGCAGGATTGCTATAAGAAAGGMATACCTANAGACTCTAATATGATTAGAGAAAAAGCGAAGTCATTATGTGANNACTTAAAGCAAAARRAAGATGAMRGATCTAAAGCTGGANAATTTAATGCCAGCAAAKGATGGTTTGACAATTTTAGAAAGARGTWTGGCTTAAAAAATKTCAAGAKAACAGGAGAAGCASYTTCTGCTGACCAAGAGACAGCAGACGAGTTNCCAGATGCCATTAACAAAATCATTGAGGAGAAAGGATATCTGCCTGAACAGGTTTTTAATGCAGATGARAGTGCCCTATTCTGGGGGGAAAAAATGCCACAAAGRACATTTATTAGTAAGNAAGAGAAGCGAGCACCAGGATTTAAGGCARGAAGGGATAGGCTAACTCTACTGTTTTGTGCAAATGCAGTTAGGTTTATGATCAGGACTGCCCTTATCTATAAAGCTGCTAACCCCCGAGCCTTGAAGGGAAAAGATAAACGCCAGCTGCCAGTCTTTTGGTTGTACAACAAGAAGGCCTGGACAACGAGAACCCTTTTTCTGGATTGGTTCCATTKATGCTTTGTCCCTGAWGTCAGGAAGTACCTTGCCAGTAAGRGACTGCCTTTTAAAGTTCTTTTGATATTGGACAATGCCCYTGGCCACCCAGAACCCCATGAGTTCAACACCGAAGGTGTCGAAGTGGTCTACTTGCCCCCAAACACAACGTCTCTAATTCAGCCTCTAGATCAGGGGGTCATAAGGACCTTTAAGGCTCATTACACACGGTACTCTATGGAAAGGATTGTCAACGCTATGGAAGAGAACCCCGATAGARAGAACATCATGAAAGTCTGGAAGGATTACACCATTGAAGATGCCATTGTTRTTATAGAAAAAGCCGTGAAAGCCATCAAGCCCAAAACAGTAAATTCCTGCTGGAGAAAACTGTGTCCAGATGTTGTACATGACTTCACAGGATTTACGACAGAGCCAATCAAGGAAATCATGAAAGAGATTGTGGATATGGCAAAAAAGTTGGGGGGTAAAGGGTTTCAAGATGCGAATCTTGGAGAAATTCAAGAGCWAATAGACACCACACCAGAGGAATTAACAGAAGACGACTTGATGGAGATGAGTGCTTCCGAACCAGTGCCAGACGATGAGGAAGAAGACATNGAAGAAGCAGTGCCAGAAAACAAATTGACATTAGACAATCTRGGCAGAAGGGTTCCAATTATTCAAGACTGCTTTTGACTTCTTTTACAACATGGACCCTTCTATGATACGGGCACTGAAACTAAAGCAAACAGTGGAAGAAGGATTGGTAYTATACAGAAACATTTTTAGAGAAATGAAAAGGCAAAAAYRTCAGACAGAAATTACGATGTATTTCCGTAAAGTTACACCGAGTGTGCCTGCCTCTCCTGCCTCCCCTTCCACCTCCTCCACCTCTTCCACCTCTGCCACCCTGAGACAGCAAGACCAACCCCTCCTCCTCCTCAGCCTWCTCAATGTGAAGACGACGAGGATGAAGACCTTTATGATGATCCACTTCCACTTAATGAATAGTAAATATATTTTCTCTTCCTTATGATTTTCTTAATAACATTTTCTTTTCTCTAGCTTACTTTATTGTAAGAATACGGTATATAATACATATAACATACAAAATATGTGTTAATCGACTGTTTATGTTATCGGTAAGGCTTCCAGTCAACAGTAGGCTATTAGTAGTTAAGTTTTKGGGGAGTCAAAAGTTATACGTGGATTTTTNACTGCGCGGGGGGTCAGCGCCCCTAACCCCCGCGTTGTTCAAGGGTCAACTG
>PTR5 Human PTR5 mRNA for repetitive sequence
GAATTCCGAAGCTTTGTTCTTTAGCTCTTTGCAATAAATCTTGCTGCTGCTCACTCTTTGGGTCCACACTGCCTTTACGAGCTGTAACACTCACCGCGAAGGTCTGCAGCTTCACTCCTGAAGCCAGTGAGACCACGAACCCACCAGGAGGAACAAACAACTCCAGATGTGCTGCCTTAAGAGCTGTAACACTCACCGCGAAGGTCTGCAGCTTCAGTCCTAAGCCAGCAAGACCACGAACCCACCAGAAGGAAGAAACTCTGAACACATCCAAACATCAGAAGGAACAAACTCTGGACATGCCGCCTTTAAGAACTGTGACACTCACCACGAGGGTCCGTGGCTTCATTCTTGAAGTCAGTGAGACCAAGAACCCACCAATTCCAGACACATTTTGGCAACCACAAAGGGACTATCACCTATTGCCAAGCGGTGAGACTATCGCCAAGTGGTGAGACCATCGTCTATCGCTGAGCAGCAAAACAATCGCCTATCGCCAAGCAAATCGAAGCCATCAAGCTACAGATGGTCTTACAAATGGAACCCCAAATGAGTTCAACTAACAACTTCTACCGAGGACCCCTGGACCGACCCGCTGGCACTTCCACTGGCCTAGAGAGTTCCCCCTTGAGACACTACAACTGCAGGGCCCCTTCTTCACTTCTATCCAGCAGGAAGTAGCTAGAGCAGTCATCGGCCAAATTCCCAACAGCAGTTGGGGTGTCCTGTTTAGAGGGGGGATTGAGAGGTGGCAGTGTGCTGGCAGCCCTCGCAGCCCTCGCTCACTCTTGGCTCCTCCTCGGCCTTGGCGCCCACTCTGGCCATGCTTAAGGAGCCCTTCAGCCTGCCACTGCACTGTGGGAACACTGGCCAAGGCCAGAGCCAGCTCACTCAGCTTGTGGGGAAGTGTGGAGGGAGAGGCGCAGGCGGGAACTGGGGCTCGATGCGGCGCTTGCGGGCCAGCGTGAGTTCCGGTGGTTGGTGGCTTGGCGGGCCCCAGACTCGGAGCGGCTGGCCTGCCCTGCTGGCCCCAGGCAGTGAGGGGCTTAGCACCCAGGCCAGCAGCTGTGGATGGTGCGCTGAGTCTCCCAGCAGTGCTGGCCCACCCCACCAGCACTGCACTCGATTTCTCGCCAGGCCTTAGCTGCCTCCCCGCAGGCAGGCCTTGGGACCTGCAGCCCACCATGCCTGAGTCTCCCCTGCTGCCGCCGTGGGCTCCTGCGTGGCCCAAGCCTCCCCGACGAGCACTGCCCCCTGCTCCCCGGTGCCTGGTCCCATCGACCCCAAGGGCTGAGGAGTGCAGGTGCATGCTGCGGGACTGGCAGGCAGCTCCACCTGCGGCCCCATGCAGGAAGCCAGCTGGGCTCCTGAGTCTGGTGGGGACTTGGAGAATTTTTATGTCTAGCTAAGGGATTGTAAATACACCAATCAGCACTCTGTATCTAGCTCAAGGATTGTAAATACACCAATCAGCACCCTGTGTCTAGCTCAGGGTTTGTCAATGCACCAATCGGCACTCTGTATCTAGTTAATCTGGTGGGGAGTTGGAGAATCTTTATGTCTAGCTAAGGGATTGTAAATACACCAATCAGCACTCTGTATCTAGCTCAAGGTTTGTAAACACACCAATCAGAACCCTGTGTCTAGCTCAGGGTTTGTGAATGCACCAATCAGCACTCTGTATCTAGTTAATCTGGTGGGGACTTGGAGAATCTTTATGTCTAGCTAAGGGATTGTGAATGCACCAATCGGCACTCTGTATCTAGCTCAAGGTTGTAAATGGACCAATCAGCACTCTATGTCTAGCTCAGTGTTTGTAAATACACCAATCGACACTCTATCTAGCTAATCTAGTGGGGACGTGGAGAACTTTTGTGTCTAACTCAGGGATTGTAAATGCACCAATCAGAACCCTGTCAAAATGGACCAATAGCTCTCTGTAAAACAGACTGACTTTCTGTAAAATGGACCAATCAGCAGGATGTGGGTGGGGCCAGATAAGAGAAGAAAAGCAGGCTGCCTGAGCCAGCAGTGGCAACCCGCTTGGGTCCCCTTCCACACTGTGGAAGCTTTGTTCTTTCGCTCTTTGCAATAAATCTTGCTGCTGCTCACTCTTTGGGTCCACACTGCCTTTATGAGCTGTAACACTCACCGCGAAGGTCTGCAGCTTCATCTGAAGCAGCGAGACACGAACCCACCAGGAGGAACAAACAACTCCGATGCGCTGCCTTAAGAGCTGTAACACCGCGAGGTCTCGAGCTTCACTCCTGAGCCAGCAAGACCACAAACCCACCAGAAGGAAGAAACTCAGGAAAACAGCCGAACATCAGAAGGAATAAACTCTGGACACACCACCTTTAAGAACTGTGACACTCGCTGCGAGCGTCTGTGGCTTCATTCTTGAAGTCAGTGAGACCAAGAACCCACCAATTCTGGAC
>PAB Human pseudoautosomal boundary-like sequence.
CCTTACCAGCCCCCTACTGTGGCAGGCCAGGTCCCACTAACACAGGCCTCCATAACAACTGTTTCAGCTCTGACTGAGTGGTTAAGTTAAATACTAAAAGCCGAGAGAGCCAGTCCCCTTATACAGAGGCTGGAATGTAACAAAAGCCCACCAAGAGTTTTGCCTAGGCCTTTCCTGGGCCTTGAAGCATGACAAAATAACAAAAGAATTCTTAACAGAATCTATTTAGGATTAAACAAGTTTTACTGGGGGTTCTGAAGAAACTCCCCAGTCCTCCACAAACAAGTTTACTGGGGTCTGAAAGAACTCCCCAAACCTCCATGATTTAGCAGGAGACAAGATAAGGGTAATCACCCCAGCACCTGGACCCAGCTAGATTTAGTCAATTTACTGAGGCTACAAAGGAAGGTCTTCAGGACTCAGACCTCAGTTATAGATTAGAAGAAGTTAATCACTTATGTCTTTAGATGATTGCACACTTACACATAGACATATAGCTTAGAAGGTGTATAAGCTCTGGAAAACTTTGTAATTTTGAGTTGGTCTGGTGATATTTTCCAGGCCTTCTCCCTATACCCGGTTACAGAAATAAAAACTTTCTTCCTCCCCAGTTCATCTGCATCTTGTTAATGGGCTGCCAGAAATAGCAGCCCAACCCTCAGTTAGGTCTGGGAACACTACCCCCCAACACACACACACACAC
>TARE Transposable element
GAATTCCGCGCCCGTCCCGTCGCCGCCGCCGCCGCCGCAGACCCCTCGGTCTTGCTATGTCGAGCTCACCCGTGAAGCGTCAGAGGATGGAGTCCGCGCTGGACCAGCTCAAGCAGTTCACCACCGTGGTGGCCGACACGGGCGACTTCCACGCCATCGACGAGTACAAGCCCCAGGATGCTACCACCAACCCGTCCCTGATCCTGGCCGCAGCACAGATGCCCGCTTACCAGGAGCTGGTGGAGGAGGCGATTGCCTATGGCCGGAAGCTGGGCGGGTCACAAGAGGACCAGATTAAAAATGCTATTGATAAACTTTTTGTGTTGTTTGGAGCAGAAATACTAAAGAAGATTCCGGGCCGAGTATCCACAGAAGTAGACGCAAGGCTCTCCTTTGATAAAGATGCGATGGTGGCCAGAGCCAGGCGGCTCATCGAGCTCTACAAGGAAGCTGGGATCAGCAAGGACCGA
>A Primate simple repeat pattern
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
>C Primate simple repeat pattern
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
>AC Primate simple repeat pattern
ACACACACACACACACACACACACACACACACACACACACACACACACACACACACACACACACACACA
>AT Primate simple repeat pattern
ATATATATATATATATATATATATATATATATATATATATATATATATATATATATATATATATATATA
>AG Primate simple repeat pattern
AGAGAGAGAGAGAGAGAGAGAGAGAGAGAGAGAGAGAGAGAGAGAGAGAGAGAGAGAGAGAGAGAGAGA
>CG Primate simple repeat pattern
CGCGCGCGCGCGCGCGCGCGCGCGCGCGCGCGCGCGCGCGCGCGCGCGCGCGCGCGCGCGCGCGCGCGC
>GCC Primate simple repeat pattern
GCCGCCGCCGCCGCCGCCGCCGCCGCCGCCGCCGCCGCCGCCGCCGCCGCCGCCGCCGCCGCCGCCGCC
>TAA Primate simple repeat pattern
TAATAATAATAATAATAATAATAATAATAATAATAATAATAATAATAATAATAATAATAATAATAATAA
>CAA Primate simple repeat pattern
CAACAACAACAACAACAACAACAACAACAACAACAACAACAACAACAACAACAACAACAACAACAACAA
>GCA Primate simple repeat pattern
GCAGCAGCAGCAGCAGCAGCAGCAGCAGCAGCAGCAGCAGCAGCAGCAGCAGCAGCAGCAGCAGCAGCA
>CTA Primate simple repeat pattern
CTACTACTACTACTACTACTACTACTACTACTACTACTACTACTACTACTACTACTACTACTACTACTA
>GGA Primate simple repeat pattern
GGAGGAGGAGGAGGAGGAGGAGGAGGAGGAGGAGGAGGAGGAGGAGGAGGAGGAGGAGGAGGAGGAGGA
>GAA Primate simple repeat pattern
GAAGAAGAAGAAGAAGAAGAAGAAGAAGAAGAAGAAGAAGAAGAAGAAGAAGAAGAAGAAGAAGAAGAA
>TCA Primate simple repeat pattern
TCATCATCATCATCATCATCATCATCATCATCATCATCATCATCATCATCATCATCATCATCATCATCA
>CCA Primate simple repeat pattern
CCACCACCACCACCACCACCACCACCACCACCACCACCACCACCACCACCACCACCACCACCACCACCA
>TAGA Primate simple repeat pattern
TAGATAGATAGATAGATAGATAGATAGATAGATAGATAGATAGATAGATAGATAGATAGATAGATAGAT
>CAAA Primate simple repeat pattern
CAAACAAACAAACAAACAAACAAACAAACAAACAAACAAACAAACAAACAAACAAACAAACAAACAAAC
>TAAA Primate simple repeat pattern
TAAATAAATAAATAAATAAATAAATAAATAAATAAATAAATAAATAAATAAATAAATAAATAAATAAAT
>GAAA Primate simple repeat pattern
GAAAGAAAGAAAGAAAGAAAGAAAGAAAGAAAGAAAGAAAGAAAGAAAGAAAGAAAGAAAGAAAGAAAG
>TCCA Primate simple repeat pattern
TCCATCCATCCATCCATCCATCCATCCATCCATCCATCCATCCATCCATCCATCCATCCATCCATCCAT
>CGAA Primate simple repeat pattern
CGAACGAACGAACGAACGAACGAACGAACGAACGAACGAACGAACGAACGAACGAACGAACGAACGAAC
>TGAA Primate simple repeat pattern
TGAATGAATGAATGAATGAATGAATGAATGAATGAATGAATGAATGAATGAATGAATGAATGAATGAAT
>CGGA Primate simple repeat pattern
CGGACGGACGGACGGACGGACGGACGGACGGACGGACGGACGGACGGACGGACGGACGGACGGACGGAC
>GGAA Primate simple repeat pattern
GGAAGGAAGGAAGGAAGGAAGGAAGGAAGGAAGGAAGGAAGGAAGGAAGGAAGGAAGGAAGGAAGGAAG
>TACA Primate simple repeat pattern
TACATACATACATACATACATACATACATACATACATACATACATACATACATACATACATACATACAT
>TCAA Primate simple repeat pattern
TCAATCAATCAATCAATCAATCAATCAATCAATCAATCAATCAATCAATCAATCAATCAATCAATCAAT
>GACA Primate simple repeat pattern
GACAGACAGACAGACAGACAGACAGACAGACAGACAGACAGACAGACAGACAGACAGACAGACAGACAG
>CCTA Primate simple repeat pattern
CCTACCTACCTACCTACCTACCTACCTACCTACCTACCTACCTACCTACCTACCTACCTACCTACCTAC
>GCCC Primate simple repeat pattern
GCCCGCCCGCCCGCCCGCCCGCCCGCCCGCCCGCCCGCCCGCCCGCCCGCCCGCCCGCCCGCCCGCCCG
>TTAA Primate simple repeat pattern
TTAATTAATTAATTAATTAATTAATTAATTAATTAATTAATTAATTAATTAATTAATTAATTAATTAAT
>GGGA Primate simple repeat pattern
GGGAGGGAGGGAGGGAGGGAGGGAGGGAGGGAGGGAGGGAGGGAGGGAGGGAGGGAGGGAGGGAGGGAG
>GGCA Primate simple repeat pattern
GGCAGGCAGGCAGGCAGGCAGGCAGGCAGGCAGGCAGGCAGGCAGGCAGGCAGGCAGGCAGGCAGGCAG
>GCCA Primate simple repeat pattern
GCCAGCCAGCCAGCCAGCCAGCCAGCCAGCCAGCCAGCCAGCCAGCCAGCCAGCCAGCCAGCCAGCCAG
>CAAAA Primate simple repeat pattern
CAAAACAAAACAAAACAAAACAAAACAAAACAAAACAAAACAAAACAAAACAAAACAAAACAAAACAAA
>TGGAA Primate simple repeat pattern
TGGAATGGAATGGAATGGAATGGAATGGAATGGAATGGAATGGAATGGAATGGAATGGAATGGAATGGA
>TAAAA Primate simple repeat pattern
TAAAATAAAATAAAATAAAATAAAATAAAATAAAATAAAATAAAATAAAATAAAATAAAATAAAATAAA
>GCCCA Primate simple repeat pattern
GCCCAGCCCAGCCCAGCCCAGCCCAGCCCAGCCCAGCCCAGCCCAGCCCAGCCCAGCCCAGCCCAGCCC
>GCTCA Primate simple repeat pattern
GCTCAGCTCAGCTCAGCTCAGCTCAGCTCAGCTCAGCTCAGCTCAGCTCAGCTCAGCTCAGCTCAGCTC
>GAAAA Primate simple repeat pattern
GAAAAGAAAAGAAAAGAAAAGAAAAGAAAAGAAAAGAAAAGAAAAGAAAAGAAAAGAAAAGAAAAGAAA
>TACAA Primate simple repeat pattern
TACAATACAATACAATACAATACAATACAATACAATACAATACAATACAATACAATACAATACAATACA
>CTCCA Primate simple repeat pattern
CTCCACTCCACTCCACTCCACTCCACTCCACTCCACTCCACTCCACTCCACTCCACTCCACTCCACTCC
>TCTAA Primate simple repeat pattern
TCTAATCTAATCTAATCTAATCTAATCTAATCTAATCTAATCTAATCTAATCTAATCTAATCTAATCTA
>TAGAA Primate simple repeat pattern
TAGAATAGAATAGAATAGAATAGAATAGAATAGAATAGAATAGAATAGAATAGAATAGAATAGAATAGA
>GGAGA Primate simple repeat pattern
GGAGAGGAGAGGAGAGGAGAGGAGAGGAGAGGAGAGGAGAGGAGAGGAGAGGAGAGGAGAGGAGAGGAG
>TTAAA Primate simple repeat pattern
TTAAATTAAATTAAATTAAATTAAATTAAATTAAATTAAATTAAATTAAATTAAATTAAATTAAATTAA
>GCCCC Primate simple repeat pattern
GCCCCGCCCCGCCCCGCCCCGCCCCGCCCCGCCCCGCCCCGCCCCGCCCCGCCCCGCCCCGCCCCGCCC
>GCGCA Primate simple repeat pattern
GCGCAGCGCAGCGCAGCGCAGCGCAGCGCAGCGCAGCGCAGCGCAGCGCAGCGCAGCGCAGCGCAGCGC
>GGGGA Primate simple repeat pattern
GGGGAGGGGAGGGGAGGGGAGGGGAGGGGAGGGGAGGGGAGGGGAGGGGAGGGGAGGGGAGGGGAGGGG
>GGCCC Primate simple repeat pattern
GGCCCGGCCCGGCCCGGCCCGGCCCGGCCCGGCCCGGCCCGGCCCGGCCCGGCCCGGCCCGGCCCGGCC
>TCCCA Primate simple repeat pattern
TCCCATCCCATCCCATCCCATCCCATCCCATCCCATCCCATCCCATCCCATCCCATCCCATCCCATCCC
>CCCCA Primate simple repeat pattern
CCCCACCCCACCCCACCCCACCCCACCCCACCCCACCCCACCCCACCCCACCCCACCCCACCCCACCCC
>CCCTAA Primate simple repeat pattern
CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCC
>CCCGAA Primate simple repeat pattern
CCCGAACCCGAACCCGAACCCGAACCCGAACCCGAACCCGAACCCGAACCCGAACCCGAACCCGAACCC
>TATACA Primate simple repeat pattern
TATACATATACATATACATATACATATACATATACATATACATATACATATACATATACATATACATAT
>TCACCA Primate simple repeat pattern
TCACCATCACCATCACCATCACCATCACCATCACCATCACCATCACCATCACCATCACCATCACCATCA
>CCCCAA Primate simple repeat pattern
CCCCAACCCCAACCCCAACCCCAACCCCAACCCCAACCCCAACCCCAACCCCAACCCCAACCCCAACCC
>CAAAAA Primate simple repeat pattern
CAAAAACAAAAACAAAAACAAAAACAAAAACAAAAACAAAAACAAAAACAAAAACAAAAACAAAAACAA
>CCCTCA Primate simple repeat pattern
CCCTCACCCTCACCCTCACCCTCACCCTCACCCTCACCCTCACCCTCACCCTCACCCTCACCCTCACCC
>GCCCCC Primate simple repeat pattern
GCCCCCGCCCCCGCCCCCGCCCCCGCCCCCGCCCCCGCCCCCGCCCCCGCCCCCGCCCCCGCCCCCGCC
>GAAAAA Primate simple repeat pattern
GAAAAAGAAAAAGAAAAAGAAAAAGAAAAAGAAAAAGAAAAAGAAAAAGAAAAAGAAAAAGAAAAAGAA
>GGAGAA Primate simple repeat pattern
GGAGAAGGAGAAGGAGAAGGAGAAGGAGAAGGAGAAGGAGAAGGAGAAGGAGAAGGAGAAGGAGAAGGA
>CCCCCA Primate simple repeat pattern
CCCCCACCCCCACCCCCACCCCCACCCCCACCCCCACCCCCACCCCCACCCCCACCCCCACCCCCACCC
>TAAAAA Primate simple repeat pattern
TAAAAATAAAAATAAAAATAAAAATAAAAATAAAAATAAAAATAAAAATAAAAATAAAAATAAAAATAA
>GGGAGA Primate simple repeat pattern
GGGAGAGGGAGAGGGAGAGGGAGAGGGAGAGGGAGAGGGAGAGGGAGAGGGAGAGGGAGAGGGAGAGGG
>GCCCCA Primate simple repeat pattern
GCCCCAGCCCCAGCCCCAGCCCCAGCCCCAGCCCCAGCCCCAGCCCCAGCCCCAGCCCCAGCCCCAGCC
>GGGGGA Primate simple repeat pattern
GGGGGAGGGGGAGGGGGAGGGGGAGGGGGAGGGGGAGGGGGAGGGGGAGGGGGAGGGGGAGGGGGAGGG
>GAGACA Primate simple repeat pattern
GAGACAGAGACAGAGACAGAGACAGAGACAGAGACAGAGACAGAGACAGAGACAGAGACAGAGACAGAG
>A Primate simple repeat pattern
TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT
>C Primate simple repeat pattern
GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG
>AC Primate simple repeat pattern
TGTGTGTGTGTGTGTGTGTGTGTGTGTGTGTGTGTGTGTGTGTGTGTGTGTGTGTGTGTGTGTGTGTGT
>AT Primate simple repeat pattern
TATATATATATATATATATATATATATATATATATATATATATATATATATATATATATATATATATAT
>AG Primate simple repeat pattern
TCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCTCT
>CG Primate simple repeat pattern
GCGCGCGCGCGCGCGCGCGCGCGCGCGCGCGCGCGCGCGCGCGCGCGCGCGCGCGCGCGCGCGCGCGCG
>GCC Primate simple repeat pattern
GGCGGCGGCGGCGGCGGCGGCGGCGGCGGCGGCGGCGGCGGCGGCGGCGGCGGCGGCGGCGGCGGCGGC
>TAA Primate simple repeat pattern
TTATTATTATTATTATTATTATTATTATTATTATTATTATTATTATTATTATTATTATTATTATTATTA
>CAA Primate simple repeat pattern
TTGTTGTTGTTGTTGTTGTTGTTGTTGTTGTTGTTGTTGTTGTTGTTGTTGTTGTTGTTGTTGTTGTTG
>GCA Primate simple repeat pattern
TGCTGCTGCTGCTGCTGCTGCTGCTGCTGCTGCTGCTGCTGCTGCTGCTGCTGCTGCTGCTGCTGCTGC
>CTA Primate simple repeat pattern
TAGTAGTAGTAGTAGTAGTAGTAGTAGTAGTAGTAGTAGTAGTAGTAGTAGTAGTAGTAGTAGTAGTAG
>GGA Primate simple repeat pattern
TCCTCCTCCTCCTCCTCCTCCTCCTCCTCCTCCTCCTCCTCCTCCTCCTCCTCCTCCTCCTCCTCCTCC
>GAA Primate simple repeat pattern
TTCTTCTTCTTCTTCTTCTTCTTCTTCTTCTTCTTCTTCTTCTTCTTCTTCTTCTTCTTCTTCTTCTTC
>TCA Primate simple repeat pattern
TGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGA
>CCA Primate simple repeat pattern
TGGTGGTGGTGGTGGTGGTGGTGGTGGTGGTGGTGGTGGTGGTGGTGGTGGTGGTGGTGGTGGTGGTGG
>TAGA Primate simple repeat pattern
ATCTATCTATCTATCTATCTATCTATCTATCTATCTATCTATCTATCTATCTATCTATCTATCTATCTA
>CAAA Primate simple repeat pattern
GTTTGTTTGTTTGTTTGTTTGTTTGTTTGTTTGTTTGTTTGTTTGTTTGTTTGTTTGTTTGTTTGTTTG
>TAAA Primate simple repeat pattern
ATTTATTTATTTATTTATTTATTTATTTATTTATTTATTTATTTATTTATTTATTTATTTATTTATTTA
>GAAA Primate simple repeat pattern
CTTTCTTTCTTTCTTTCTTTCTTTCTTTCTTTCTTTCTTTCTTTCTTTCTTTCTTTCTTTCTTTCTTTC
>TCCA Primate simple repeat pattern
ATGGATGGATGGATGGATGGATGGATGGATGGATGGATGGATGGATGGATGGATGGATGGATGGATGGA
>CGAA Primate simple repeat pattern
GTTCGTTCGTTCGTTCGTTCGTTCGTTCGTTCGTTCGTTCGTTCGTTCGTTCGTTCGTTCGTTCGTTCG
>TGAA Primate simple repeat pattern
ATTCATTCATTCATTCATTCATTCATTCATTCATTCATTCATTCATTCATTCATTCATTCATTCATTCA
>CGGA Primate simple repeat pattern
GTCCGTCCGTCCGTCCGTCCGTCCGTCCGTCCGTCCGTCCGTCCGTCCGTCCGTCCGTCCGTCCGTCCG
>GGAA Primate simple repeat pattern
CTTCCTTCCTTCCTTCCTTCCTTCCTTCCTTCCTTCCTTCCTTCCTTCCTTCCTTCCTTCCTTCCTTCC
>TACA Primate simple repeat pattern
ATGTATGTATGTATGTATGTATGTATGTATGTATGTATGTATGTATGTATGTATGTATGTATGTATGTA
>TCAA Primate simple repeat pattern
ATTGATTGATTGATTGATTGATTGATTGATTGATTGATTGATTGATTGATTGATTGATTGATTGATTGA
>GACA Primate simple repeat pattern
CTGTCTGTCTGTCTGTCTGTCTGTCTGTCTGTCTGTCTGTCTGTCTGTCTGTCTGTCTGTCTGTCTGTC
>CCTA Primate simple repeat pattern
GTAGGTAGGTAGGTAGGTAGGTAGGTAGGTAGGTAGGTAGGTAGGTAGGTAGGTAGGTAGGTAGGTAGG
>GCCC Primate simple repeat pattern
CGGGCGGGCGGGCGGGCGGGCGGGCGGGCGGGCGGGCGGGCGGGCGGGCGGGCGGGCGGGCGGGCGGGC
>TTAA Primate simple repeat pattern
ATTAATTAATTAATTAATTAATTAATTAATTAATTAATTAATTAATTAATTAATTAATTAATTAATTAA
>GGGA Primate simple repeat pattern
CTCCCTCCCTCCCTCCCTCCCTCCCTCCCTCCCTCCCTCCCTCCCTCCCTCCCTCCCTCCCTCCCTCCC
>GGCA Primate simple repeat pattern
CTGCCTGCCTGCCTGCCTGCCTGCCTGCCTGCCTGCCTGCCTGCCTGCCTGCCTGCCTGCCTGCCTGCC
>GCCA Primate simple repeat pattern
CTGGCTGGCTGGCTGGCTGGCTGGCTGGCTGGCTGGCTGGCTGGCTGGCTGGCTGGCTGGCTGGCTGGC
>CAAAA Primate simple repeat pattern
TTTGTTTTGTTTTGTTTTGTTTTGTTTTGTTTTGTTTTGTTTTGTTTTGTTTTGTTTTGTTTTGTTTTG
>TGGAA Primate simple repeat pattern
TCCATTCCATTCCATTCCATTCCATTCCATTCCATTCCATTCCATTCCATTCCATTCCATTCCATTCCA
>TAAAA Primate simple repeat pattern
TTTATTTTATTTTATTTTATTTTATTTTATTTTATTTTATTTTATTTTATTTTATTTTATTTTATTTTA
>GCCCA Primate simple repeat pattern
GGGCTGGGCTGGGCTGGGCTGGGCTGGGCTGGGCTGGGCTGGGCTGGGCTGGGCTGGGCTGGGCTGGGC
>GCTCA Primate simple repeat pattern
GAGCTGAGCTGAGCTGAGCTGAGCTGAGCTGAGCTGAGCTGAGCTGAGCTGAGCTGAGCTGAGCTGAGC
>GAAAA Primate simple repeat pattern
TTTCTTTTCTTTTCTTTTCTTTTCTTTTCTTTTCTTTTCTTTTCTTTTCTTTTCTTTTCTTTTCTTTTC
>TACAA Primate simple repeat pattern
TGTATTGTATTGTATTGTATTGTATTGTATTGTATTGTATTGTATTGTATTGTATTGTATTGTATTGTA
>CTCCA Primate simple repeat pattern
GGAGTGGAGTGGAGTGGAGTGGAGTGGAGTGGAGTGGAGTGGAGTGGAGTGGAGTGGAGTGGAGTGGAG
>TCTAA Primate simple repeat pattern
TAGATTAGATTAGATTAGATTAGATTAGATTAGATTAGATTAGATTAGATTAGATTAGATTAGATTAGA
>TAGAA Primate simple repeat pattern
TCTATTCTATTCTATTCTATTCTATTCTATTCTATTCTATTCTATTCTATTCTATTCTATTCTATTCTA
>GGAGA Primate simple repeat pattern
CTCCTCTCCTCTCCTCTCCTCTCCTCTCCTCTCCTCTCCTCTCCTCTCCTCTCCTCTCCTCTCCTCTCC
>TTAAA Primate simple repeat pattern
TTAATTTAATTTAATTTAATTTAATTTAATTTAATTTAATTTAATTTAATTTAATTTAATTTAATTTAA
>GCCCC Primate simple repeat pattern
GGGCGGGGCGGGGCGGGGCGGGGCGGGGCGGGGCGGGGCGGGGCGGGGCGGGGCGGGGCGGGGCGGGGC
>GCGCA Primate simple repeat pattern
GCGCTGCGCTGCGCTGCGCTGCGCTGCGCTGCGCTGCGCTGCGCTGCGCTGCGCTGCGCTGCGCTGCGC
>GGGGA Primate simple repeat pattern
CCCCTCCCCTCCCCTCCCCTCCCCTCCCCTCCCCTCCCCTCCCCTCCCCTCCCCTCCCCTCCCCTCCCC
>GGCCC Primate simple repeat pattern
GGCCGGGCCGGGCCGGGCCGGGCCGGGCCGGGCCGGGCCGGGCCGGGCCGGGCCGGGCCGGGCCGGGCC
>TCCCA Primate simple repeat pattern
GGGATGGGATGGGATGGGATGGGATGGGATGGGATGGGATGGGATGGGATGGGATGGGATGGGATGGGA
>CCCCA Primate simple repeat pattern
GGGGTGGGGTGGGGTGGGGTGGGGTGGGGTGGGGTGGGGTGGGGTGGGGTGGGGTGGGGTGGGGTGGGG
>CCCTAA Primate simple repeat pattern
GGGTTAGGGTTAGGGTTAGGGTTAGGGTTAGGGTTAGGGTTAGGGTTAGGGTTAGGGTTAGGGTTAGGG
>CCCGAA Primate simple repeat pattern
GGGTTCGGGTTCGGGTTCGGGTTCGGGTTCGGGTTCGGGTTCGGGTTCGGGTTCGGGTTCGGGTTCGGG
>TATACA Primate simple repeat pattern
ATATGTATATGTATATGTATATGTATATGTATATGTATATGTATATGTATATGTATATGTATATGTATA
>TCACCA Primate simple repeat pattern
TGATGGTGATGGTGATGGTGATGGTGATGGTGATGGTGATGGTGATGGTGATGGTGATGGTGATGGTGA
>CCCCAA Primate simple repeat pattern
GGGTTGGGGTTGGGGTTGGGGTTGGGGTTGGGGTTGGGGTTGGGGTTGGGGTTGGGGTTGGGGTTGGGG
>CAAAAA Primate simple repeat pattern
TTGTTTTTGTTTTTGTTTTTGTTTTTGTTTTTGTTTTTGTTTTTGTTTTTGTTTTTGTTTTTGTTTTTG
>CCCTCA Primate simple repeat pattern
GGGTGAGGGTGAGGGTGAGGGTGAGGGTGAGGGTGAGGGTGAGGGTGAGGGTGAGGGTGAGGGTGAGGG
>GCCCCC Primate simple repeat pattern
GGCGGGGGCGGGGGCGGGGGCGGGGGCGGGGGCGGGGGCGGGGGCGGGGGCGGGGGCGGGGGCGGGGGC
>GAAAAA Primate simple repeat pattern
TTCTTTTTCTTTTTCTTTTTCTTTTTCTTTTTCTTTTTCTTTTTCTTTTTCTTTTTCTTTTTCTTTTTC
>GGAGAA Primate simple repeat pattern
TCCTTCTCCTTCTCCTTCTCCTTCTCCTTCTCCTTCTCCTTCTCCTTCTCCTTCTCCTTCTCCTTCTCC
>CCCCCA Primate simple repeat pattern
GGGTGGGGGTGGGGGTGGGGGTGGGGGTGGGGGTGGGGGTGGGGGTGGGGGTGGGGGTGGGGGTGGGGG
>TAAAAA Primate simple repeat pattern
TTATTTTTATTTTTATTTTTATTTTTATTTTTATTTTTATTTTTATTTTTATTTTTATTTTTATTTTTA
>GGGAGA Primate simple repeat pattern
CCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCCTCTCCC
>GCCCCA Primate simple repeat pattern
GGCTGGGGCTGGGGCTGGGGCTGGGGCTGGGGCTGGGGCTGGGGCTGGGGCTGGGGCTGGGGCTGGGGC
>GGGGGA Primate simple repeat pattern
CCCTCCCCCTCCCCCTCCCCCTCCCCCTCCCCCTCCCCCTCCCCCTCCCCCTCCCCCTCCCCCTCCCCC
>GAGACA Primate simple repeat pattern
CTCTGTCTCTGTCTCTGTCTCTGTCTCTGTCTCTGTCTCTGTCTCTGTCTCTGTCTCTGTCTCTGTCTC
primer3-py-2.3.1/primer3/src/libprimer3/klib/ 0000775 0000000 0000000 00000000000 15247271707 0020701 5 ustar 00root root 0000000 0000000 primer3-py-2.3.1/primer3/src/libprimer3/klib/.gitignore 0000664 0000000 0000000 00000000726 15247271707 0022676 0 ustar 00root root 0000000 0000000 # General
*.a
*.dSYM/
*.la
*.lo
*.o
*.opensdf
*.orig
*.sdf
*.suo
*.swp
*.tests
*.vcxproj.filters
*.vcxproj.user
*~
.git
TAGS
# Mac/Xcode-specfic
xcuserdata
contents.xcworkspacedata
.DS_Store
._*
# Test byproducts
test/kbtree_test
test/khash_keith
test/khash_keith2
test/khash_test
test/klist_test
test/kmin_test
test/kseq_bench
test/kseq_bench2
test/kseq_test
test/ksort_test
test/ksort_test-stl
test/kstring_bench
test/kstring_bench2
test/kstring_test
test/kvec_test
primer3-py-2.3.1/primer3/src/libprimer3/klib/README.md 0000664 0000000 0000000 00000025334 15247271707 0022167 0 ustar 00root root 0000000 0000000 #Klib: a Generic Library in C
##Overview
Klib is a standalone and lightweight C library distributed under [MIT/X11
license][1]. Most components are independent of external libraries, except the
standard C library, and independent of each other. To use a component of this
library, you only need to copy a couple of files to your source code tree
without worrying about library dependencies.
Klib strives for efficiency and a small memory footprint. Some components, such
as khash.h, kbtree.h, ksort.h and kvec.h, are among the most efficient
implementations of similar algorithms or data structures in all programming
languages, in terms of both speed and memory use.
####Common components
* khash.h: generic hash table based on [double hashing][2].
* kbtree.h: generic search tree based on [B-tree][3].
* ksort.h: generic sort, including [introsort][4], [merge sort][5], [heap sort][6], [comb sort][7], [Knuth shuffle][8] and the [k-small][9] algorithm.
* kseq.h: generic stream buffer and a [FASTA][10]/[FASTQ][11] format parser.
* kvec.h: generic dynamic array.
* klist.h: generic single-linked list and [memory pool][12].
* kstring.{h,c}: basic string library.
* kmath.{h,c}: numerical routines including [MT19937-64][13] [pseudorandom generator][14], basic [nonlinear programming][15] and a few special math functions.
####Components for more specific use cases
* ksa.c: constructing [suffix arrays][16] for strings with multiple sentinels, based on a revised [SAIS algorithm][17].
* knetfile.{h,c}: random access to remote files on HTTP or FTP.
* kopen.c: smart stream opening.
* khmm.{h,c}: basic [HMM][18] library.
* ksw.(h,c}: Striped [Smith-Waterman algorithm][19].
* knhx.{h,c}: [Newick tree format][20] parser.
##Methodology
For the implementation of generic [containers][21], klib extensively uses C
macros. To use these data structures, we usually need to instantiate methods by
expanding a long macro. This makes the source code look unusual or even ugly
and adds difficulty to debugging. Unfortunately, for efficient generic
programming in C that lacks [template][22], using macros is the only
solution. Only with macros, we can write a generic container which, once
instantiated, compete with a type-specific container in efficiency. Some
generic libraries in C, such as [Glib][23], use the `void*` type to implement
containers. These implementations are usually slower and use more memory than
klib (see [this benchmark][31]).
To effectively use klib, it is important to understand how it achieves generic
programming. We will use the hash table library as an example:
#include "khash.h"
KHASH_MAP_INIT_INT(m32, char) // instantiate structs and methods
int main() {
int ret, is_missing;
khint_t k;
khash_t(m32) *h = kh_init(m32); // allocate a hash table
k = kh_put(m32, h, 5, &ret); // insert a key to the hash table
if (!ret) kh_del(m32, h, k);
kh_value(h, k) = 10; // set the value
k = kh_get(m32, h, 10); // query the hash table
is_missing = (k == kh_end(h)); // test if the key is present
k = kh_get(m32, h, 5);
kh_del(m32, h, k); // remove a key-value pair
for (k = kh_begin(h); k != kh_end(h); ++k) // traverse
if (kh_exist(h, k)) // test if a bucket contains data
kh_value(h, k) = 1;
kh_destroy(m32, h); // deallocate the hash table
return 0;
}
In this example, the second line instantiates a hash table with `unsigned` as
the key type and `char` as the value type. `m32` names such a type of hash table.
All types and functions associated with this name are macros, which will be
explained later. Macro `kh_init()` initiates a hash table and `kh_destroy()`
frees it. `kh_put()` inserts a key and returns the iterator (or the position)
in the hash table. `kh_get()` and `kh_del()` get a key and delete an element,
respectively. Macro `kh_exist()` tests if an iterator (or a position) is filled
with data.
An immediate question is this piece of code does not look like a valid C
program (e.g. lacking semicolon, assignment to an _apparent_ function call and
_apparent_ undefined `m32` 'variable'). To understand why the code is correct,
let's go a bit further into the source code of `khash.h`, whose skeleton looks
like:
#define KHASH_INIT(name, SCOPE, key_t, val_t, is_map, _hashf, _hasheq) \
typedef struct { \
int n_buckets, size, n_occupied, upper_bound; \
unsigned *flags; \
key_t *keys; \
val_t *vals; \
} kh_##name##_t; \
SCOPE inline kh_##name##_t *init_##name() { \
return (kh_##name##_t*)calloc(1, sizeof(kh_##name##_t)); \
} \
SCOPE inline int get_##name(kh_##name##_t *h, key_t k) \
... \
SCOPE inline void destroy_##name(kh_##name##_t *h) { \
if (h) { \
free(h->keys); free(h->flags); free(h->vals); free(h); \
} \
}
#define _int_hf(key) (unsigned)(key)
#define _int_heq(a, b) (a == b)
#define khash_t(name) kh_##name##_t
#define kh_value(h, k) ((h)->vals[k])
#define kh_begin(h, k) 0
#define kh_end(h) ((h)->n_buckets)
#define kh_init(name) init_##name()
#define kh_get(name, h, k) get_##name(h, k)
#define kh_destroy(name, h) destroy_##name(h)
...
#define KHASH_MAP_INIT_INT(name, val_t) \
KHASH_INIT(name, static, unsigned, val_t, is_map, _int_hf, _int_heq)
`KHASH_INIT()` is a huge macro defining all the structs and methods. When this
macro is called, all the code inside it will be inserted by the [C
preprocess][37] to the place where it is called. If the macro is called
multiple times, multiple copies of the code will be inserted. To avoid naming
conflict of hash tables with different key-value types, the library uses [token
concatenation][36], which is a preprocessor feature whereby we can substitute
part of a symbol based on the parameter of the macro. In the end, the C
preprocessor will generate the following code and feed it to the compiler
(macro `kh_exist(h,k)` is a little complex and not expanded for simplicity):
typedef struct {
int n_buckets, size, n_occupied, upper_bound;
unsigned *flags;
unsigned *keys;
char *vals;
} kh_m32_t;
static inline kh_m32_t *init_m32() {
return (kh_m32_t*)calloc(1, sizeof(kh_m32_t));
}
static inline int get_m32(kh_m32_t *h, unsigned k)
...
static inline void destroy_m32(kh_m32_t *h) {
if (h) {
free(h->keys); free(h->flags); free(h->vals); free(h);
}
}
int main() {
int ret, is_missing;
khint_t k;
kh_m32_t *h = init_m32();
k = put_m32(h, 5, &ret);
if (!ret) del_m32(h, k);
h->vals[k] = 10;
k = get_m32(h, 10);
is_missing = (k == h->n_buckets);
k = get_m32(h, 5);
del_m32(h, k);
for (k = 0; k != h->n_buckets; ++k)
if (kh_exist(h, k)) h->vals[k] = 1;
destroy_m32(h);
return 0;
}
This is the C program we know.
From this example, we can see that macros and the C preprocessor plays a key
role in klib. Klib is fast partly because the compiler knows the key-value
type at the compile time and is able to optimize the code to the same level
as type-specific code. A generic library written with `void*` will not get such
performance boost.
Massively inserting code upon instantiation may remind us of C++'s slow
compiling speed and huge binary size when STL/boost is in use. Klib is much
better in this respect due to its small code size and component independency.
Inserting several hundreds lines of code won't make compiling obviously slower.
##Resources
* Library documentation, if present, is available in the header files. Examples
can be found in the [test/][24] directory.
* **Obsolete** documentation of the hash table library can be found at
[SourceForge][25]. This README is partly adapted from the old documentation.
* [Blog post][26] describing the hash table library.
* [Blog post][27] on why using `void*` for generic programming may be inefficient.
* [Blog post][28] on the generic stream buffer.
* [Blog post][29] evaluating the performance of `kvec.h`.
* [Blog post][30] arguing B-tree may be a better data structure than a binary search tree.
* [Blog post][31] evaluating the performance of `khash.h` and `kbtree.h` among many other implementations.
[An older version][33] of the benchmark is also available.
* [Blog post][34] benchmarking internal sorting algorithms and implementations.
* [Blog post][32] on the k-small algorithm.
* [Blog post][35] on the Hooke-Jeeve's algorithm for nonlinear programming.
[1]: http://en.wikipedia.org/wiki/MIT_License
[2]: http://en.wikipedia.org/wiki/Double_hashing
[3]: http://en.wikipedia.org/wiki/B-tree
[4]: http://en.wikipedia.org/wiki/Introsort
[5]: http://en.wikipedia.org/wiki/Merge_sort
[6]: http://en.wikipedia.org/wiki/Heapsort
[7]: http://en.wikipedia.org/wiki/Comb_sort
[8]: http://en.wikipedia.org/wiki/Fisher-Yates_shuffle
[9]: http://en.wikipedia.org/wiki/Selection_algorithm
[10]: http://en.wikipedia.org/wiki/FASTA_format
[11]: http://en.wikipedia.org/wiki/FASTQ_format
[12]: http://en.wikipedia.org/wiki/Memory_pool
[13]: http://en.wikipedia.org/wiki/Mersenne_twister
[14]: http://en.wikipedia.org/wiki/Pseudorandom_generator
[15]: http://en.wikipedia.org/wiki/Nonlinear_programming
[16]: http://en.wikipedia.org/wiki/Suffix_array
[17]: https://sites.google.com/site/yuta256/sais
[18]: http://en.wikipedia.org/wiki/Hidden_Markov_model
[19]: http://en.wikipedia.org/wiki/Smith-Waterman_algorithm
[20]: http://en.wikipedia.org/wiki/Newick_format
[21]: http://en.wikipedia.org/wiki/Container_(abstract_data_type)
[22]: http://en.wikipedia.org/wiki/Template_(C%2B%2B)
[23]: http://en.wikipedia.org/wiki/GLib
[24]: https://github.com/attractivechaos/klib/tree/master/test
[25]: http://klib.sourceforge.net/
[26]: http://attractivechaos.wordpress.com/2008/09/02/implementing-generic-hash-library-in-c/
[27]: http://attractivechaos.wordpress.com/2008/10/02/using-void-in-generic-c-programming-may-be-inefficient/
[28]: http://attractivechaos.wordpress.com/2008/10/11/a-generic-buffered-stream-wrapper/
[29]: http://attractivechaos.wordpress.com/2008/09/19/c-array-vs-c-vector/
[30]: http://attractivechaos.wordpress.com/2008/09/24/b-tree-vs-binary-search-tree/
[31]: http://attractivechaos.wordpress.com/2008/10/07/another-look-at-my-old-benchmark/
[32]: http://attractivechaos.wordpress.com/2008/09/13/calculating-median/
[33]: http://attractivechaos.wordpress.com/2008/08/28/comparison-of-hash-table-libraries/
[34]: http://attractivechaos.wordpress.com/2008/08/28/comparison-of-internal-sorting-algorithms/
[35]: http://attractivechaos.wordpress.com/2008/08/24/derivative-free-optimization-dfo/
[36]: http://en.wikipedia.org/wiki/C_preprocessor#Token_concatenation
[37]: http://en.wikipedia.org/wiki/C_preprocessor
primer3-py-2.3.1/primer3/src/libprimer3/klib/khash.h 0000664 0000000 0000000 00000051350 15247271707 0022154 0 ustar 00root root 0000000 0000000 /* The MIT License
Copyright (c) 2008, 2009, 2011 by Attractive Chaos
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
/*
An example:
#include "khash.h"
KHASH_MAP_INIT_INT(32, char)
int main() {
int ret, is_missing;
khiter_t k;
khash_t(32) *h = kh_init(32);
k = kh_put(32, h, 5, &ret);
kh_value(h, k) = 10;
k = kh_get(32, h, 10);
is_missing = (k == kh_end(h));
k = kh_get(32, h, 5);
kh_del(32, h, k);
for (k = kh_begin(h); k != kh_end(h); ++k)
if (kh_exist(h, k)) kh_value(h, k) = 1;
kh_destroy(32, h);
return 0;
}
*/
/*
2013-05-02 (0.2.8):
* Use quadratic probing. When the capacity is power of 2, stepping function
i*(i+1)/2 guarantees to traverse each bucket. It is better than double
hashing on cache performance and is more robust than linear probing.
In theory, double hashing should be more robust than quadratic probing.
However, my implementation is probably not for large hash tables, because
the second hash function is closely tied to the first hash function,
which reduce the effectiveness of double hashing.
Reference: http://research.cs.vt.edu/AVresearch/hashing/quadratic.php
2011-12-29 (0.2.7):
* Minor code clean up; no actual effect.
2011-09-16 (0.2.6):
* The capacity is a power of 2. This seems to dramatically improve the
speed for simple keys. Thank Zilong Tan for the suggestion. Reference:
- http://code.google.com/p/ulib/
- http://nothings.org/computer/judy/
* Allow to optionally use linear probing which usually has better
performance for random input. Double hashing is still the default as it
is more robust to certain non-random input.
* Added Wang's integer hash function (not used by default). This hash
function is more robust to certain non-random input.
2011-02-14 (0.2.5):
* Allow to declare global functions.
2009-09-26 (0.2.4):
* Improve portability
2008-09-19 (0.2.3):
* Corrected the example
* Improved interfaces
2008-09-11 (0.2.2):
* Improved speed a little in kh_put()
2008-09-10 (0.2.1):
* Added kh_clear()
* Fixed a compiling error
2008-09-02 (0.2.0):
* Changed to token concatenation which increases flexibility.
2008-08-31 (0.1.2):
* Fixed a bug in kh_get(), which has not been tested previously.
2008-08-31 (0.1.1):
* Added destructor
*/
#ifndef __AC_KHASH_H
#define __AC_KHASH_H
/*!
@header
Generic hash table library.
*/
#define AC_VERSION_KHASH_H "0.2.8"
#include
#include
#include
/* compiler specific configuration */
#if UINT_MAX == 0xffffffffu
typedef unsigned int khint32_t;
#elif ULONG_MAX == 0xffffffffu
typedef unsigned long khint32_t;
#endif
#if ULONG_MAX == ULLONG_MAX
typedef unsigned long khint64_t;
#else
typedef unsigned long long khint64_t;
#endif
#ifdef _MSC_VER
#define kh_inline __inline
#else
#define kh_inline inline
#endif
typedef khint32_t khint_t;
typedef khint_t khiter_t;
#define __ac_isempty(flag, i) ((flag[i>>4]>>((i&0xfU)<<1))&2)
#define __ac_isdel(flag, i) ((flag[i>>4]>>((i&0xfU)<<1))&1)
#define __ac_iseither(flag, i) ((flag[i>>4]>>((i&0xfU)<<1))&3)
#define __ac_set_isdel_false(flag, i) (flag[i>>4]&=~(1ul<<((i&0xfU)<<1)))
#define __ac_set_isempty_false(flag, i) (flag[i>>4]&=~(2ul<<((i&0xfU)<<1)))
#define __ac_set_isboth_false(flag, i) (flag[i>>4]&=~(3ul<<((i&0xfU)<<1)))
#define __ac_set_isdel_true(flag, i) (flag[i>>4]|=1ul<<((i&0xfU)<<1))
#define __ac_fsize(m) ((m) < 16? 1 : (m)>>4)
#ifndef kroundup32
#define kroundup32(x) (--(x), (x)|=(x)>>1, (x)|=(x)>>2, (x)|=(x)>>4, (x)|=(x)>>8, (x)|=(x)>>16, ++(x))
#endif
#ifndef kcalloc
#define kcalloc(N,Z) calloc(N,Z)
#endif
#ifndef kmalloc
#define kmalloc(Z) malloc(Z)
#endif
#ifndef krealloc
#define krealloc(P,Z) realloc(P,Z)
#endif
#ifndef kfree
#define kfree(P) free(P)
#endif
static const double __ac_HASH_UPPER = 0.77;
#define __KHASH_TYPE(name, khkey_t, khval_t) \
typedef struct { \
khint_t n_buckets, size, n_occupied, upper_bound; \
khint32_t *flags; \
khkey_t *keys; \
khval_t *vals; \
} kh_##name##_t;
#define __KHASH_PROTOTYPES(name, khkey_t, khval_t) \
extern kh_##name##_t *kh_init_##name(void); \
extern void kh_destroy_##name(kh_##name##_t *h); \
extern void kh_clear_##name(kh_##name##_t *h); \
extern khint_t kh_get_##name(const kh_##name##_t *h, khkey_t key); \
extern int kh_resize_##name(kh_##name##_t *h, khint_t new_n_buckets); \
extern khint_t kh_put_##name(kh_##name##_t *h, khkey_t key, int *ret); \
extern void kh_del_##name(kh_##name##_t *h, khint_t x);
#define __KHASH_IMPL(name, SCOPE, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal) \
SCOPE kh_##name##_t *kh_init_##name(void) { \
return (kh_##name##_t*)kcalloc(1, sizeof(kh_##name##_t)); \
} \
SCOPE void kh_destroy_##name(kh_##name##_t *h) \
{ \
if (h) { \
kfree((void *)h->keys); kfree(h->flags); \
kfree((void *)h->vals); \
kfree(h); \
} \
} \
SCOPE void kh_clear_##name(kh_##name##_t *h) \
{ \
if (h && h->flags) { \
memset(h->flags, 0xaa, __ac_fsize(h->n_buckets) * sizeof(khint32_t)); \
h->size = h->n_occupied = 0; \
} \
} \
SCOPE khint_t kh_get_##name(const kh_##name##_t *h, khkey_t key) \
{ \
if (h->n_buckets) { \
khint_t k, i, last, mask, step = 0; \
mask = h->n_buckets - 1; \
k = __hash_func(key); i = k & mask; \
last = i; \
while (!__ac_isempty(h->flags, i) && (__ac_isdel(h->flags, i) || !__hash_equal(h->keys[i], key))) { \
i = (i + (++step)) & mask; \
if (i == last) return h->n_buckets; \
} \
return __ac_iseither(h->flags, i)? h->n_buckets : i; \
} else return 0; \
} \
SCOPE int kh_resize_##name(kh_##name##_t *h, khint_t new_n_buckets) \
{ /* This function uses 0.25*n_buckets bytes of working space instead of [sizeof(key_t+val_t)+.25]*n_buckets. */ \
khint32_t *new_flags = 0; \
khint_t j = 1; \
{ \
kroundup32(new_n_buckets); \
if (new_n_buckets < 4) new_n_buckets = 4; \
if (h->size >= (khint_t)(new_n_buckets * __ac_HASH_UPPER + 0.5)) j = 0; /* requested size is too small */ \
else { /* hash table size to be changed (shrink or expand); rehash */ \
new_flags = (khint32_t*)kmalloc(__ac_fsize(new_n_buckets) * sizeof(khint32_t)); \
if (!new_flags) return -1; \
memset(new_flags, 0xaa, __ac_fsize(new_n_buckets) * sizeof(khint32_t)); \
if (h->n_buckets < new_n_buckets) { /* expand */ \
khkey_t *new_keys = (khkey_t*)krealloc((void *)h->keys, new_n_buckets * sizeof(khkey_t)); \
if (!new_keys) return -1; \
h->keys = new_keys; \
if (kh_is_map) { \
khval_t *new_vals = (khval_t*)krealloc((void *)h->vals, new_n_buckets * sizeof(khval_t)); \
if (!new_vals) return -1; \
h->vals = new_vals; \
} \
} /* otherwise shrink */ \
} \
} \
if (j) { /* rehashing is needed */ \
for (j = 0; j != h->n_buckets; ++j) { \
if (__ac_iseither(h->flags, j) == 0) { \
khkey_t key = h->keys[j]; \
khval_t val; \
khint_t new_mask; \
new_mask = new_n_buckets - 1; \
if (kh_is_map) val = h->vals[j]; \
__ac_set_isdel_true(h->flags, j); \
while (1) { /* kick-out process; sort of like in Cuckoo hashing */ \
khint_t k, i, step = 0; \
k = __hash_func(key); \
i = k & new_mask; \
while (!__ac_isempty(new_flags, i)) i = (i + (++step)) & new_mask; \
__ac_set_isempty_false(new_flags, i); \
if (i < h->n_buckets && __ac_iseither(h->flags, i) == 0) { /* kick out the existing element */ \
{ khkey_t tmp = h->keys[i]; h->keys[i] = key; key = tmp; } \
if (kh_is_map) { khval_t tmp = h->vals[i]; h->vals[i] = val; val = tmp; } \
__ac_set_isdel_true(h->flags, i); /* mark it as deleted in the old hash table */ \
} else { /* write the element and jump out of the loop */ \
h->keys[i] = key; \
if (kh_is_map) h->vals[i] = val; \
break; \
} \
} \
} \
} \
if (h->n_buckets > new_n_buckets) { /* shrink the hash table */ \
h->keys = (khkey_t*)krealloc((void *)h->keys, new_n_buckets * sizeof(khkey_t)); \
if (kh_is_map) h->vals = (khval_t*)krealloc((void *)h->vals, new_n_buckets * sizeof(khval_t)); \
} \
kfree(h->flags); /* free the working space */ \
h->flags = new_flags; \
h->n_buckets = new_n_buckets; \
h->n_occupied = h->size; \
h->upper_bound = (khint_t)(h->n_buckets * __ac_HASH_UPPER + 0.5); \
} \
return 0; \
} \
SCOPE khint_t kh_put_##name(kh_##name##_t *h, khkey_t key, int *ret) \
{ \
khint_t x; \
if (h->n_occupied >= h->upper_bound) { /* update the hash table */ \
if (h->n_buckets > (h->size<<1)) { \
if (kh_resize_##name(h, h->n_buckets - 1) < 0) { /* clear "deleted" elements */ \
*ret = -1; return h->n_buckets; \
} \
} else if (kh_resize_##name(h, h->n_buckets + 1) < 0) { /* expand the hash table */ \
*ret = -1; return h->n_buckets; \
} \
} /* TODO: to implement automatically shrinking; resize() already support shrinking */ \
{ \
khint_t k, i, site, last, mask = h->n_buckets - 1, step = 0; \
x = site = h->n_buckets; k = __hash_func(key); i = k & mask; \
if (__ac_isempty(h->flags, i)) x = i; /* for speed up */ \
else { \
last = i; \
while (!__ac_isempty(h->flags, i) && (__ac_isdel(h->flags, i) || !__hash_equal(h->keys[i], key))) { \
if (__ac_isdel(h->flags, i)) site = i; \
i = (i + (++step)) & mask; \
if (i == last) { x = site; break; } \
} \
if (x == h->n_buckets) { \
if (__ac_isempty(h->flags, i) && site != h->n_buckets) x = site; \
else x = i; \
} \
} \
} \
if (__ac_isempty(h->flags, x)) { /* not present at all */ \
h->keys[x] = key; \
__ac_set_isboth_false(h->flags, x); \
++h->size; ++h->n_occupied; \
*ret = 1; \
} else if (__ac_isdel(h->flags, x)) { /* deleted */ \
h->keys[x] = key; \
__ac_set_isboth_false(h->flags, x); \
++h->size; \
*ret = 2; \
} else *ret = 0; /* Don't touch h->keys[x] if present and not deleted */ \
return x; \
} \
SCOPE void kh_del_##name(kh_##name##_t *h, khint_t x) \
{ \
if (x != h->n_buckets && !__ac_iseither(h->flags, x)) { \
__ac_set_isdel_true(h->flags, x); \
--h->size; \
} \
}
#define KHASH_DECLARE(name, khkey_t, khval_t) \
__KHASH_TYPE(name, khkey_t, khval_t) \
__KHASH_PROTOTYPES(name, khkey_t, khval_t)
#define KHASH_INIT2(name, SCOPE, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal) \
__KHASH_TYPE(name, khkey_t, khval_t) \
__KHASH_IMPL(name, SCOPE, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal)
#define KHASH_INIT(name, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal) \
KHASH_INIT2(name, static kh_inline, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal)
/* --- BEGIN OF HASH FUNCTIONS --- */
/*! @function
@abstract Integer hash function
@param key The integer [khint32_t]
@return The hash value [khint_t]
*/
#define kh_int_hash_func(key) (khint32_t)(key)
/*! @function
@abstract Integer comparison function
*/
#define kh_int_hash_equal(a, b) ((a) == (b))
/*! @function
@abstract 64-bit integer hash function
@param key The integer [khint64_t]
@return The hash value [khint_t]
*/
#define kh_int64_hash_func(key) (khint32_t)((key)>>33^(key)^(key)<<11)
/*! @function
@abstract 64-bit integer comparison function
*/
#define kh_int64_hash_equal(a, b) ((a) == (b))
/*! @function
@abstract const char* hash function
@param s Pointer to a null terminated string
@return The hash value
*/
static kh_inline khint_t __ac_X31_hash_string(const char *s)
{
khint_t h = (khint_t)*s;
if (h) for (++s ; *s; ++s) h = (h << 5) - h + (khint_t)*s;
return h;
}
/*! @function
@abstract Another interface to const char* hash function
@param key Pointer to a null terminated string [const char*]
@return The hash value [khint_t]
*/
#define kh_str_hash_func(key) __ac_X31_hash_string(key)
/*! @function
@abstract Const char* comparison function
*/
#define kh_str_hash_equal(a, b) (strcmp(a, b) == 0)
static kh_inline khint_t __ac_Wang_hash(khint_t key)
{
key += ~(key << 15);
key ^= (key >> 10);
key += (key << 3);
key ^= (key >> 6);
key += ~(key << 11);
key ^= (key >> 16);
return key;
}
#define kh_int_hash_func2(k) __ac_Wang_hash((khint_t)key)
/* --- END OF HASH FUNCTIONS --- */
/* Other convenient macros... */
/*!
@abstract Type of the hash table.
@param name Name of the hash table [symbol]
*/
#define khash_t(name) kh_##name##_t
/*! @function
@abstract Initiate a hash table.
@param name Name of the hash table [symbol]
@return Pointer to the hash table [khash_t(name)*]
*/
#define kh_init(name) kh_init_##name()
/*! @function
@abstract Destroy a hash table.
@param name Name of the hash table [symbol]
@param h Pointer to the hash table [khash_t(name)*]
*/
#define kh_destroy(name, h) kh_destroy_##name(h)
/*! @function
@abstract Reset a hash table without deallocating memory.
@param name Name of the hash table [symbol]
@param h Pointer to the hash table [khash_t(name)*]
*/
#define kh_clear(name, h) kh_clear_##name(h)
/*! @function
@abstract Resize a hash table.
@param name Name of the hash table [symbol]
@param h Pointer to the hash table [khash_t(name)*]
@param s New size [khint_t]
*/
#define kh_resize(name, h, s) kh_resize_##name(h, s)
/*! @function
@abstract Insert a key to the hash table.
@param name Name of the hash table [symbol]
@param h Pointer to the hash table [khash_t(name)*]
@param k Key [type of keys]
@param r Extra return code: -1 if the operation failed;
0 if the key is present in the hash table;
1 if the bucket is empty (never used); 2 if the element in
the bucket has been deleted [int*]
@return Iterator to the inserted element [khint_t]
*/
#define kh_put(name, h, k, r) kh_put_##name(h, k, r)
/*! @function
@abstract Retrieve a key from the hash table.
@param name Name of the hash table [symbol]
@param h Pointer to the hash table [khash_t(name)*]
@param k Key [type of keys]
@return Iterator to the found element, or kh_end(h) if the element is absent [khint_t]
*/
#define kh_get(name, h, k) kh_get_##name(h, k)
/*! @function
@abstract Remove a key from the hash table.
@param name Name of the hash table [symbol]
@param h Pointer to the hash table [khash_t(name)*]
@param k Iterator to the element to be deleted [khint_t]
*/
#define kh_del(name, h, k) kh_del_##name(h, k)
/*! @function
@abstract Test whether a bucket contains data.
@param h Pointer to the hash table [khash_t(name)*]
@param x Iterator to the bucket [khint_t]
@return 1 if containing data; 0 otherwise [int]
*/
#define kh_exist(h, x) (!__ac_iseither((h)->flags, (x)))
/*! @function
@abstract Get key given an iterator
@param h Pointer to the hash table [khash_t(name)*]
@param x Iterator to the bucket [khint_t]
@return Key [type of keys]
*/
#define kh_key(h, x) ((h)->keys[x])
/*! @function
@abstract Get value given an iterator
@param h Pointer to the hash table [khash_t(name)*]
@param x Iterator to the bucket [khint_t]
@return Value [type of values]
@discussion For hash sets, calling this results in segfault.
*/
#define kh_val(h, x) ((h)->vals[x])
/*! @function
@abstract Alias of kh_val()
*/
#define kh_value(h, x) ((h)->vals[x])
/*! @function
@abstract Get the start iterator
@param h Pointer to the hash table [khash_t(name)*]
@return The start iterator [khint_t]
*/
#define kh_begin(h) (khint_t)(0)
/*! @function
@abstract Get the end iterator
@param h Pointer to the hash table [khash_t(name)*]
@return The end iterator [khint_t]
*/
#define kh_end(h) ((h)->n_buckets)
/*! @function
@abstract Get the number of elements in the hash table
@param h Pointer to the hash table [khash_t(name)*]
@return Number of elements in the hash table [khint_t]
*/
#define kh_size(h) ((h)->size)
/*! @function
@abstract Get the number of buckets in the hash table
@param h Pointer to the hash table [khash_t(name)*]
@return Number of buckets in the hash table [khint_t]
*/
#define kh_n_buckets(h) ((h)->n_buckets)
/*! @function
@abstract Iterate over the entries in the hash table
@param h Pointer to the hash table [khash_t(name)*]
@param kvar Variable to which key will be assigned
@param vvar Variable to which value will be assigned
@param code Block of code to execute
*/
#define kh_foreach(h, kvar, vvar, code) { khint_t __i; \
for (__i = kh_begin(h); __i != kh_end(h); ++__i) { \
if (!kh_exist(h,__i)) continue; \
(kvar) = kh_key(h,__i); \
(vvar) = kh_val(h,__i); \
code; \
} }
/*! @function
@abstract Iterate over the values in the hash table
@param h Pointer to the hash table [khash_t(name)*]
@param vvar Variable to which value will be assigned
@param code Block of code to execute
*/
#define kh_foreach_value(h, vvar, code) { khint_t __i; \
for (__i = kh_begin(h); __i != kh_end(h); ++__i) { \
if (!kh_exist(h,__i)) continue; \
(vvar) = kh_val(h,__i); \
code; \
} }
/* More conenient interfaces */
/*! @function
@abstract Instantiate a hash set containing integer keys
@param name Name of the hash table [symbol]
*/
#define KHASH_SET_INIT_INT(name) \
KHASH_INIT(name, khint32_t, char, 0, kh_int_hash_func, kh_int_hash_equal)
/*! @function
@abstract Instantiate a hash map containing integer keys
@param name Name of the hash table [symbol]
@param khval_t Type of values [type]
*/
#define KHASH_MAP_INIT_INT(name, khval_t) \
KHASH_INIT(name, khint32_t, khval_t, 1, kh_int_hash_func, kh_int_hash_equal)
/*! @function
@abstract Instantiate a hash map containing 64-bit integer keys
@param name Name of the hash table [symbol]
*/
#define KHASH_SET_INIT_INT64(name) \
KHASH_INIT(name, khint64_t, char, 0, kh_int64_hash_func, kh_int64_hash_equal)
/*! @function
@abstract Instantiate a hash map containing 64-bit integer keys
@param name Name of the hash table [symbol]
@param khval_t Type of values [type]
*/
#define KHASH_MAP_INIT_INT64(name, khval_t) \
KHASH_INIT(name, khint64_t, khval_t, 1, kh_int64_hash_func, kh_int64_hash_equal)
typedef const char *kh_cstr_t;
/*! @function
@abstract Instantiate a hash map containing const char* keys
@param name Name of the hash table [symbol]
*/
#define KHASH_SET_INIT_STR(name) \
KHASH_INIT(name, kh_cstr_t, char, 0, kh_str_hash_func, kh_str_hash_equal)
/*! @function
@abstract Instantiate a hash map containing const char* keys
@param name Name of the hash table [symbol]
@param khval_t Type of values [type]
*/
#define KHASH_MAP_INIT_STR(name, khval_t) \
KHASH_INIT(name, kh_cstr_t, khval_t, 1, kh_str_hash_func, kh_str_hash_equal)
#endif /* __AC_KHASH_H */
primer3-py-2.3.1/primer3/src/libprimer3/klib/test/ 0000775 0000000 0000000 00000000000 15247271707 0021660 5 ustar 00root root 0000000 0000000 primer3-py-2.3.1/primer3/src/libprimer3/klib/test/Makefile 0000664 0000000 0000000 00000000343 15247271707 0023320 0 ustar 00root root 0000000 0000000 CC=gcc
CXX=g++
CFLAGS=-g -Wall -O2 -I..
CXXFLAGS=$(CFLAGS)
PROGS=khash_keith khash_keith2 khash_test
all:$(PROGS)
clean:
rm -fr $(PROGS) *.dSYM a.out
khash_test:khash_test.c ../khash.h
$(CC) $(CFLAGS) -o $@ khash_test.c
primer3-py-2.3.1/primer3/src/libprimer3/klib/test/khash_keith.c 0000664 0000000 0000000 00000004750 15247271707 0024314 0 ustar 00root root 0000000 0000000 /*
* This is an optimized version of the following C++ program:
*
* http://keithlea.com/javabench/src/cpp/hash.cpp
*
* Keith in his benchmark (http://keithlea.com/javabench/data) showed that the
* Java implementation is twice as fast as the C++ version. In fact, this is
* only because the C++ implementation is substandard. Most importantly, Keith
* is using "sprintf()" to convert an integer to a string, which is known to be
* extremely inefficient.
*/
#include
#include "khash.h"
KHASH_MAP_INIT_STR(str, int)
inline void int2str(int c, int base, char *ret)
{
const char *tab = "0123456789abcdef";
if (c == 0) ret[0] = '0', ret[1] = 0;
else {
int l, x, y;
char buf[16];
for (l = 0, x = c < 0? -c : c; x > 0; x /= base) buf[l++] = tab[x%base];
if (c < 0) buf[l++] = '-';
for (x = l - 1, y = 0; x >= 0; --x) ret[y++] = buf[x];
ret[y] = 0;
}
}
#ifndef _USE_STRDUP
#define BLOCK_SIZE 0x100000
int main(int argc, char *argv[])
{
char **mem = 0;
int i, l, n = 1000000, ret, block_end = 0, curr = 0, c = 0;
khash_t(str) *h;
h = kh_init(str);
if (argc > 1) n = atoi(argv[1]);
mem = malloc(sizeof(void*));
mem[0] = malloc(BLOCK_SIZE); // memory buffer to avoid memory fragmentation
curr = block_end = 0;
for (i = 1; i <= n; ++i) {
char buf[16];
int2str(i, 16, buf);
khint_t k = kh_put(str, h, buf, &ret);
l = strlen(buf) + 1;
if (block_end + l > BLOCK_SIZE) {
++curr; block_end = 0;
mem = realloc(mem, (curr + 1) * sizeof(void*));
mem[curr] = malloc(BLOCK_SIZE);
}
memcpy(mem[curr] + block_end, buf, l);
kh_key(h, k) = mem[curr] + block_end;
block_end += l;
kh_val(h, k) = i;
}
for (i = 1; i <= n; ++i) {
char buf[16];
int2str(i, 10, buf);
khint_t k = kh_get(str, h, buf);
if (k != kh_end(h)) ++c;
}
printf("%d\n", c);
for (ret = 0; ret <= curr; ++ret) free(mem[ret]);
free(mem);
kh_destroy(str, h);
return 0;
}
#else // _USE_STRDUP
int main(int argc, char *argv[])
{
int i, l, n = 1000000, ret, c = 0;
khash_t(str) *h;
khint_t k;
h = kh_init(str);
if (argc > 1) n = atoi(argv[1]);
for (i = 1; i <= n; ++i) {
char buf[16];
int2str(i, 16, buf);
k = kh_put(str, h, strdup(buf), &ret);
kh_val(h, k) = i;
}
for (i = 1; i <= n; ++i) {
char buf[16];
int2str(i, 10, buf);
k = kh_get(str, h, buf);
if (k != kh_end(h)) ++c;
}
for (k = kh_begin(h); k != kh_end(h); ++k) // explicitly freeing memory takes 10-20% CPU time.
if (kh_exist(h, k)) free((char*)kh_key(h, k));
printf("%d\n", c);
kh_destroy(str, h);
return 0;
}
#endif
primer3-py-2.3.1/primer3/src/libprimer3/klib/test/khash_keith2.c 0000664 0000000 0000000 00000003742 15247271707 0024376 0 ustar 00root root 0000000 0000000 /*
* This is an optimized version of the following C++ program:
*
* http://keithlea.com/javabench/src/cpp/hash.cpp
*
* Keith in his benchmark (http://keithlea.com/javabench/data) showed that the
* Java implementation is twice as fast as the C++ version. In fact, this is
* only because the C++ implementation is substandard. Most importantly, Keith
* is using "sprintf()" to convert an integer to a string, which is known to be
* extremely inefficient.
*/
#include
#include "khash.h"
KHASH_MAP_INIT_STR(str, int)
inline void int2str(int c, int base, char *ret)
{
const char *tab = "0123456789abcdef";
if (c == 0) ret[0] = '0', ret[1] = 0;
else {
int l, x, y;
char buf[16];
for (l = 0, x = c < 0? -c : c; x > 0; x /= base) buf[l++] = tab[x%base];
if (c < 0) buf[l++] = '-';
for (x = l - 1, y = 0; x >= 0; --x) ret[y++] = buf[x];
ret[y] = 0;
}
}
int main(int argc, char *argv[])
{
int i, l, n = 1000, ret;
khash_t(str) *h, *h2;
khint_t k;
h = kh_init(str);
h2 = kh_init(str);
if (argc > 1) n = atoi(argv[1]);
for (i = 0; i < 10000; ++i) {
char buf[32];
strcpy(buf, "foo_");
int2str(i, 10, buf+4);
k = kh_put(str, h, strdup(buf), &ret);
kh_val(h, k) = i;
}
for (i = 0; i < n; ++i) {
for (k = kh_begin(h); k != kh_end(h); ++k) {
if (kh_exist(h, k)) {
khint_t k2 = kh_put(str, h2, kh_key(h, k), &ret);
if (ret) { // absent
kh_key(h2, k2) = strdup(kh_key(h, k));
kh_val(h2, k2) = kh_val(h, k);
} else kh_val(h2, k2) += kh_val(h, k);
}
}
}
k = kh_get(str, h, "foo_1"); printf("%d", kh_val(h, k));
k = kh_get(str, h, "foo_9999"); printf(" %d", kh_val(h, k));
k = kh_get(str, h2, "foo_1"); printf(" %d", kh_val(h2, k));
k = kh_get(str, h2, "foo_9999"); printf(" %d\n", kh_val(h2, k));
for (k = kh_begin(h); k != kh_end(h); ++k)
if (kh_exist(h, k)) free((char*)kh_key(h, k));
for (k = kh_begin(h2); k != kh_end(h2); ++k)
if (kh_exist(h2, k)) free((char*)kh_key(h2, k));
kh_destroy(str, h);
kh_destroy(str, h2);
return 0;
}
primer3-py-2.3.1/primer3/src/libprimer3/klib/test/khash_test.c 0000664 0000000 0000000 00000005615 15247271707 0024170 0 ustar 00root root 0000000 0000000 #include
#include
#include
#include
#include
#include "khash.h"
KHASH_SET_INIT_STR(str)
KHASH_MAP_INIT_INT(int, unsigned char)
typedef struct {
unsigned key;
unsigned char val;
} int_unpack_t;
typedef struct {
unsigned key;
unsigned char val;
} __attribute__ ((__packed__)) int_packed_t;
#define hash_eq(a, b) ((a).key == (b).key)
#define hash_func(a) ((a).key)
KHASH_INIT(iun, int_unpack_t, char, 0, hash_func, hash_eq)
KHASH_INIT(ipk, int_packed_t, char, 0, hash_func, hash_eq)
static int data_size = 5000000;
static unsigned *int_data;
static char **str_data;
void ht_init_data()
{
int i;
char buf[256];
khint32_t x = 11;
printf("--- generating data... ");
int_data = (unsigned*)calloc(data_size, sizeof(unsigned));
str_data = (char**)calloc(data_size, sizeof(char*));
for (i = 0; i < data_size; ++i) {
int_data[i] = (unsigned)(data_size * ((double)x / UINT_MAX) / 4) * 271828183u;
sprintf(buf, "%x", int_data[i]);
str_data[i] = strdup(buf);
x = 1664525L * x + 1013904223L;
}
printf("done!\n");
}
void ht_destroy_data()
{
int i;
for (i = 0; i < data_size; ++i) free(str_data[i]);
free(str_data); free(int_data);
}
void ht_khash_int()
{
int i, ret;
unsigned *data = int_data;
khash_t(int) *h;
unsigned k;
h = kh_init(int);
for (i = 0; i < data_size; ++i) {
k = kh_put(int, h, data[i], &ret);
kh_val(h, k) = i&0xff;
if (!ret) kh_del(int, h, k);
}
printf("[ht_khash_int] size: %u\n", kh_size(h));
kh_destroy(int, h);
}
void ht_khash_str()
{
int i, ret;
char **data = str_data;
khash_t(str) *h;
unsigned k;
h = kh_init(str);
for (i = 0; i < data_size; ++i) {
k = kh_put(str, h, data[i], &ret);
if (!ret) kh_del(str, h, k);
}
printf("[ht_khash_int] size: %u\n", kh_size(h));
kh_destroy(str, h);
}
void ht_khash_unpack()
{
int i, ret;
unsigned *data = int_data;
khash_t(iun) *h;
unsigned k;
h = kh_init(iun);
for (i = 0; i < data_size; ++i) {
int_unpack_t x;
x.key = data[i]; x.val = i&0xff;
k = kh_put(iun, h, x, &ret);
if (!ret) kh_del(iun, h, k);
}
printf("[ht_khash_unpack] size: %u (sizeof=%ld)\n", kh_size(h), sizeof(int_unpack_t));
kh_destroy(iun, h);
}
void ht_khash_packed()
{
int i, ret;
unsigned *data = int_data;
khash_t(ipk) *h;
unsigned k;
h = kh_init(ipk);
for (i = 0; i < data_size; ++i) {
int_packed_t x;
x.key = data[i]; x.val = i&0xff;
k = kh_put(ipk, h, x, &ret);
if (!ret) kh_del(ipk, h, k);
}
printf("[ht_khash_packed] size: %u (sizeof=%ld)\n", kh_size(h), sizeof(int_packed_t));
kh_destroy(ipk, h);
}
void ht_timing(void (*f)(void))
{
clock_t t = clock();
(*f)();
printf("[ht_timing] %.3lf sec\n", (double)(clock() - t) / CLOCKS_PER_SEC);
}
int main(int argc, char *argv[])
{
if (argc > 1) data_size = atoi(argv[1]);
ht_init_data();
ht_timing(ht_khash_int);
ht_timing(ht_khash_str);
ht_timing(ht_khash_unpack);
ht_timing(ht_khash_packed);
ht_destroy_data();
return 0;
}
primer3-py-2.3.1/primer3/src/libprimer3/libprimer3.c 0000664 0000000 0000000 00001253134 15247271707 0022205 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2014-2016
Ben Pruitt, Nick Conway; Wyss Institute for Biologically Inspired
Engineering.
This work is a derivative of the original Primer3 library, also
covered under the GPLv2:
Copyright (c) 1996,1997,1998,1999,2000,2001,2004,2006,2007,2008,2009,
2010,2011,2012,2016
Whitehead Institute for Biomedical Research, Steve Rozen
(http://purl.com/STEVEROZEN/), Andreas Untergasser and Helen Skaletsky.
All rights reserved.
This file is part of the primer3 suite and libraries.
The primer3 suite and libraries are free software;
you can redistribute them and/or modify them under the terms
of the GNU General Public License as published by the Free
Software Foundation; either version 2 of the License, or (at
your option) any later version.
This software is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this software (file gpl-2.0.txt in the source
distribution); if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* NOTE: primer3-py. This library is C only and does not use C++ as the
* upstream libprimer3.cc does. It uses the `klib/khash.h` library to do this
* avoiding C++ complexity and keeping the build for the Cython code simple.
* this only affects lines that use hash maps such as the **pairs global variable
* C++ code replaced is intentionally commented out as a reference for future
* code comparisons. in older code this replaced `std::hash_map` from
* and `#include ` as of primer3 2.6.1 now replaces
* `std::unordered_map` from `#include `
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include /* toupper */
/* NOTE: primer3-py specific include to enable C only code for hash maps */
#include "khash.h"
/* Check on which OS we compile */
#if defined(_WIN32) || defined(WIN32) || defined (__WIN32__) || defined(__CYGWIN__) || defined(__MINGW32__)
#define OS_WIN
#endif
#include "dpal.h"
#include "thal.h"
#include "oligotm.h"
#include "libprimer3.h"
KHASH_MAP_INIT_INT(primer_pair_map, primer_pair *)
/* #define's */
/*
* OPTIMIZE_OK_REGIONS 1 allows _optimize_ok_regions_list() to use the
* max/min product size info and the max/min oligo length to reduce
* the sizes of the ok regions (while still generating the same primer
* pairs in the same order). Set OPTIMIZE_OK_REGIONS to 0 confirm
* that the results do not change. (The output tags
* PRIMER_{LEFT,RIGHT,PAIR}_EXPLAIN _will_ likely change.)
*/
#define OPTIMIZE_OK_REGIONS 1
#ifndef MAX_PRIMER_LENGTH
#define MAX_PRIMER_LENGTH 36
#endif
#if (MAX_PRIMER_LENGTH > DPAL_MAX_ALIGN)
#error "MAX_PRIMER_LENGTH must be <= DPAL_MAX_ALIGN"
#endif
#if (MAX_PRIMER_LENGTH > THAL_MAX_ALIGN)
# error "MAX_PRIMER_LENGTH must be <= THAL_MAX_ALIGN"
#endif
#define MAX_NN_TM_LENGTH 36 /* The maxium length for which to use the
nearest neighbor model when calculating
oligo Tms. */
#define MACRO_CAT_2(A,B) A##B
#define MACRO_VALUE_AS_STRING(A) MACRO_STRING(A)
#define PR_POSITION_PENALTY_IS_NULL(PA) \
(PR_DEFAULT_INSIDE_PENALTY == (PA)->inside_penalty \
&& PR_DEFAULT_OUTSIDE_PENALTY == (PA)->outside_penalty)
#define INITIAL_LIST_LEN 2000 /* Initial size of oligo lists. */
#define INITIAL_NUM_RETURN 5 /* Initial space to allocate for pairs to
return. */
#define PAIR_OK 1
#define PAIR_FAILED 0
#define OK_OR_MUST_USE(H) (!p3_ol_has_any_problem(H) || (H)->must_use)
#define PR_UNDEFINED_INT_OPT INT_MIN
#define PR_UNDEFINED_DBL_OPT DBL_MIN
/* Undefined value for alignment score (meaning do not check) used for
maximum template mispriming or mishyb. */
#define PR_UNDEFINED_ALIGN_OPT -100.0
#define TRIMMED_SEQ_LEN(X) ((X)->incl_l)
/* primer3-py additional variable for code clarity */
#define DO_PRINTOUT 1
typedef struct dpal_arg_holder {
dpal_args *local;
dpal_args *end;
dpal_args *local_end;
dpal_args *local_ambig;
dpal_args *local_end_ambig;
} dpal_arg_holder;
typedef struct thal_arg_holder {
thal_args *any;
thal_args *end1;
thal_args *end2;
thal_args *hairpin_th;
} thal_arg_holder;
static jmp_buf _jmp_buf;
static int thermodynamic_alignment_length_error = 0;
static char *thermodynamic_alignment_length_error_msg = NULL;
/* Variables needed in choose_pair_or_triple, need to be global
for memory de-allocation reasons. Full description given in the function. */
static int *max_j_seen = NULL;
// static std::hash_map **pairs;
static khash_t(primer_pair_map) **pairs;
/* Function declarations. */
static void pr_set_default_global_args_1(p3_global_settings *);
static void pr_set_default_global_args_2(p3_global_settings *);
static void _adjust_seq_args(const p3_global_settings *pa,
seq_args_t* sa,
pr_append_str *nonfatal_err,
pr_append_str *warning);
static void _optimize_ok_regions_list(const p3_global_settings *pa,
seq_args_t* sa);
static int any_5_prime_ol_extension_has_problem(const primer_rec *);
static int p3_ol_is_uninitialized(const primer_rec *);
static int fake_a_sequence(seq_args_t* sa, const p3_global_settings *pa);
static int _pr_data_control(const p3_global_settings *,
const seq_args_t* ,
pr_append_str *glob_err,
pr_append_str *nonfatal_err,
pr_append_str *warning);
static int _pr_need_pair_template_mispriming(const p3_global_settings *pa);
static int _pr_need_pair_template_mispriming_thermod(const p3_global_settings *pa);
static int _pr_need_template_mispriming(const p3_global_settings *);
static int _pr_need_template_mispriming_thermod(const p3_global_settings *);
static void _pr_substr(const char *, int, int, char *);
static void _pr_shift_substr(const char *, int, int, int, char *);
static int _pr_violates_poly_x(const char *oligo_seq, int max_poly_x);
static int _check_and_adjust_intervals(seq_args_t* sa,
int seq_len,
int first_index,
pr_append_str * nonfatal_err,
pr_append_str *warning);
static int _check_and_adjust_overlap_pos(seq_args_t* sa,
int *list,
int *count,
const char *tag,
int seq_len,
int first_index,
pr_append_str * nonfatal_err,
pr_append_str *warning);
static int _check_and_adjust_1_interval(const char *,
int num,
interval_array_t,
int,
int first_index,
pr_append_str *err,
seq_args_t* ,
pr_append_str
*warning, int);
static void sort_primer_array(oligo_array *);
static void add_pair(const primer_pair *, pair_array_t *);
static double align(const char *, const char*, const dpal_args *a);
static double align_thermod(const char *, const char *, const thal_args *a);
void destroy_primer_sec_struct(primer_rec *p_rec);
void destroy_pair_sec_struct(primer_pair *ppair);
void save_overwrite_sec_struct(char **base, char *inp);
void recalc_secundary_structures(const p3_global_settings *pa,
const seq_args_t* sa,
const dpal_arg_holder *dpal_arg_to_use,
const thal_arg_holder *thal_arg_to_use,
const thal_arg_holder *thal_oligo_arg_to_use,
p3retval *retval);
void recalc_primer_sec_struct(primer_rec *p_rec,
const int rev,
const p3_global_settings *pa,
const seq_args_t* sa,
const dpal_arg_holder *dpal_arg_to_use,
const thal_arg_holder *thal_arg_to_use);
void recalc_pair_sec_struct(primer_pair *ppair,
const p3_global_settings *pa,
const seq_args_t* sa,
const dpal_arg_holder *dpal_arg_to_use,
const thal_arg_holder *thal_arg_to_use);
static int characterize_pair(p3retval *p,
const p3_global_settings *,
const seq_args_t* ,
int, int, int,
primer_pair *,
const dpal_arg_holder*,
const thal_arg_holder*,
int update_stats);
static void choose_pair_or_triple(p3retval *,
const p3_global_settings *,
const seq_args_t* ,
const dpal_arg_holder *,
const thal_arg_holder *,
const thal_arg_holder *,
pair_array_t *);
static int sequence_quality_is_ok(const p3_global_settings *, primer_rec *,
oligo_type,
const seq_args_t* , int, int,
oligo_stats *global_oligo_stats,
const args_for_one_oligo_or_primer *);
static int choose_internal_oligo(p3retval *,
const primer_rec *, const primer_rec *,
int *,
int *,
const seq_args_t* ,
const p3_global_settings *,
const dpal_arg_holder *,
const thal_arg_holder *);
void compute_position_penalty(const p3_global_settings *,
const seq_args_t* ,
primer_rec *, oligo_type);
dpal_arg_holder *create_dpal_arg_holder(void);
void destroy_dpal_arg_holder(dpal_arg_holder *h);
thal_arg_holder *create_thal_arg_holder(const args_for_one_oligo_or_primer *po_args);
void destroy_thal_arg_holder(thal_arg_holder *h);
static p3retval *create_p3retval(void);
static char dna_to_upper(char *, int);
static int find_stop_codon(const char *, int, int);
static void gc_and_n_content(int, int, const char *, primer_rec *);
static int make_detection_primer_lists(p3retval *,
const p3_global_settings *,
const seq_args_t* ,
const dpal_arg_holder *,
const thal_arg_holder *);
static int make_complete_primer_lists(p3retval *retval,
const p3_global_settings *pa,
const seq_args_t* sa,
const dpal_arg_holder *dpal_arg_to_use,
const thal_arg_holder *thal_arg_to_use,
const thal_arg_holder *thal_oligo_arg_to_use);
static int add_primers_to_check(p3retval *retval,
const p3_global_settings *pa,
const seq_args_t* sa,
const dpal_arg_holder *dpal_arg_to_use,
const thal_arg_holder *thal_arg_to_use,
const thal_arg_holder *thal_oligo_arg_to_use);
static int pick_sequencing_primer_list(p3retval *retval,
const p3_global_settings *pa,
const seq_args_t* sa,
const dpal_arg_holder *dpal_arg_to_use,
const thal_arg_holder *thal_arg_to_use);
static int make_internal_oligo_list(p3retval *,
const p3_global_settings *,
const seq_args_t* ,
const dpal_arg_holder *,
const thal_arg_holder *);
static int pick_only_best_primer(const int, const int,
oligo_array *,
const p3_global_settings *,
const seq_args_t* ,
const dpal_arg_holder *,
const thal_arg_holder *,
p3retval *);
static int pick_primer_range(const int, const int, int *,
oligo_array *,
const p3_global_settings *,
const seq_args_t* ,
const dpal_arg_holder *,
const thal_arg_holder *,
p3retval *retval);
static int add_one_primer(const char *, int *, oligo_array *,
const p3_global_settings *,
const seq_args_t* ,
const dpal_arg_holder *,
const thal_arg_holder *,
p3retval *);
static int add_one_primer_by_position(int, int, int *,
oligo_array *,
const p3_global_settings *,
const seq_args_t* ,
const dpal_arg_holder *,
const thal_arg_holder *,
p3retval *);
static int pick_primers_by_position(const int, const int,
int *,
oligo_array *,
const p3_global_settings *,
const seq_args_t* ,
const dpal_arg_holder *,
const thal_arg_holder *,
p3retval *);
static double obj_fn(const p3_global_settings *, primer_pair *);
static int left_oligo_in_pair_overlaps_used_oligo(const primer_rec *left,
const primer_pair *best_pair,
int min_dist);
static int intl_oligo_in_pair_overlaps_used_oligo(const primer_rec *left,
const primer_pair *best_pair,
int min_dist);
static int right_oligo_in_pair_overlaps_used_oligo(const primer_rec *right,
const primer_pair *best_pair,
int min_dist);
static int oligo_overlaps_interval(int, int,
const interval_array_t, int);
static void calc_and_check_oligo_features(const p3_global_settings *pa,
primer_rec *,
oligo_type,
const dpal_arg_holder*,
const thal_arg_holder*,
const seq_args_t* , oligo_stats *,
p3retval *,
const char *);
static void pr_append(pr_append_str *, const char *);
static void pr_append_new_chunk(pr_append_str *x, const char *s);
static int pair_spans_target(const primer_pair *, const seq_args_t* );
static void pr_append_w_sep(pr_append_str *, const char *, const char *);
static void* pr_safe_malloc(size_t x);
static void* pr_safe_realloc(void *p, size_t x);
static int compare_primer_pair(const void *, const void*);
static int primer_rec_comp(const void *, const void *);
static int print_list_header(FILE *, oligo_type, int, int, int);
static int print_oligo(FILE *, const seq_args_t* , int, const primer_rec *,
oligo_type, int, int,int);
static char *strstr_nocase(char *, char *);
static double p_obj_fn(const p3_global_settings *, primer_rec *, int );
static void oligo_compl(primer_rec *,
const args_for_one_oligo_or_primer *po_args,
oligo_stats *,
const dpal_arg_holder *,
const char *oligo_seq,
const char *revc_oligo_seq
);
static void oligo_compl_thermod(primer_rec *, /* TO DO 2012-06-01 -- update by removing last argument. */
const args_for_one_oligo_or_primer *po_args,
oligo_stats *,
const thal_arg_holder *,
const char *oligo_seq,
const char *revc_oligo_seq
);
static void oligo_hairpin(primer_rec *,
const args_for_one_oligo_or_primer *po_args,
oligo_stats *,
const thal_arg_holder *,
const char *oligo_seq
);
static void oligo_compute_sequence_and_reverse(primer_rec *,
const seq_args_t* ,
oligo_type,
int*, int*,
char*, char*);
static void oligo_repeat_library_mispriming(primer_rec *,
const p3_global_settings *,
const seq_args_t* ,
oligo_type,
oligo_stats *,
const dpal_arg_holder *,
pr_append_str *);
static void oligo_template_mispriming(primer_rec *,
const p3_global_settings *,
const seq_args_t* ,
oligo_type,
oligo_stats *,
const dpal_args *,
const thal_args *);
static int pair_repeat_sim(primer_pair *, const p3_global_settings *);
static void free_repeat_sim_score(p3retval *);
static void free_primer_repeat_sim_score(primer_rec *);
/* edited by T. Koressaar for lowercase masking: */
static int is_lowercase_masked(int position,
const char *sequence,
primer_rec *h,
oligo_stats *);
static int primer_must_match(const p3_global_settings *pa,
primer_rec *h,
oligo_stats *stats,
const char *input_oligo_seq,
char *match_three_prime,
char *match_five_prime);
static int compare_nucleotides(const char a, const char b);
static int test_must_match_parameters(char *test);
static void set_retval_both_stop_codons(const seq_args_t* sa, p3retval *retval);
/* Functions to set bitfield parameters for oligos (or primers) */
static void bf_set_overlaps_target(primer_rec *, int);
static int bf_get_overlaps_target(const primer_rec *);
static void bf_set_overlaps_excl_region(primer_rec *, int);
static int bf_get_overlaps_excl_region(const primer_rec *);
static void bf_set_infinite_pos_penalty(primer_rec *, int);
static int bf_get_infinite_pos_penalty(const primer_rec *);
/* Functions to record problems with oligos (or primers) */
static void initialize_op(primer_rec *);
static void op_set_completely_written(primer_rec *);
static void op_set_must_match_err(primer_rec *);
static void op_set_too_many_ns(primer_rec *);
static void op_set_overlaps_target(primer_rec *);
static void op_set_high_gc_content(primer_rec *);
static void op_set_low_gc_content(primer_rec *);
static void op_set_high_tm(primer_rec *);
static void op_set_low_tm(primer_rec *);
static void op_set_high_bound(primer_rec *);
static void op_set_low_bound(primer_rec *);
static void op_set_overlaps_excluded_region(primer_rec *);
static void op_set_not_in_any_ok_region(primer_rec *);
static void op_set_high_self_any(primer_rec *oligo);
static void op_set_high_self_end(primer_rec *oligo);
static void op_set_high_hairpin_th(primer_rec *oligo);
static void op_set_no_gc_glamp(primer_rec *);
static void op_set_too_many_gc_at_end(primer_rec *);
static void op_set_high_end_stability(primer_rec *);
static void op_set_high_poly_x(primer_rec *);
static void op_set_low_sequence_quality(primer_rec *);
static void op_set_low_end_sequence_quality(primer_rec *oligo);
static void op_set_high_similarity_to_non_template_seq(primer_rec *);
static void op_set_high_similarity_to_multiple_template_sites(primer_rec *);
static void op_set_overlaps_masked_sequence(primer_rec *);
static void op_set_too_long(primer_rec *);
static void op_set_too_short(primer_rec *);
static void op_set_does_not_amplify_orf(primer_rec *);
/* End functions to set problems in oligos */
/* Global static variables. */
static const char *primer3_copyright_char_star = "\n"
"Copyright (c) 1996-2022\n"
"Whitehead Institute for Biomedical Research, Steve Rozen\n"
"(http://purl.com/STEVEROZEN/), Andreas Untergasser and Helen Skaletsky\n"
"All rights reserved.\n"
"\n"
" This file is part of the primer3 suite and libraries.\n"
"\n"
" The primer3 suite and libraries are free software;\n"
" you can redistribute them and/or modify them under the terms\n"
" of the GNU General Public License as published by the Free\n"
" Software Foundation; either version 2 of the License, or (at\n"
" your option) any later version.\n"
"\n"
" This software is distributed in the hope that it will be useful,\n"
" but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
" GNU General Public License for more details.\n"
"\n"
" You should have received a copy of the GNU General Public License\n"
" along with this software (file gpl-2.0.txt in the source\n"
" distribution); if not, write to the Free Software\n"
" Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA\n"
"\n"
"THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n"
"\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n"
"LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n"
"A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n"
"OWNERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n"
"SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n"
"LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n"
"DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n"
"THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n"
"(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n"
"OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
"\n";
static const char *pr_program_name = "probably primer3_core";
static const int use_end_for_th_template_mispriming = 1;
#define DEFAULT_OPT_GC_PERCENT PR_UNDEFINED_INT_OPT
/* Set the program name */
void
p3_set_program_name(const char *pname)
{
pr_program_name = pname;
}
/* ============================================================ */
/* BEGIN functions for global settings */
/* ============================================================ */
/* Allocate space for global settings and fill in defaults */
p3_global_settings *
p3_create_global_settings(void)
{
p3_global_settings *r;
// if (!(r = (p3_global_settings *) malloc(sizeof(*r)))) {
if ( (r = (p3_global_settings *) malloc(sizeof(p3_global_settings))) == NULL) {
return NULL;
}
pr_set_default_global_args_2(r);
return r;
}
/* Allocate space for global settings and fill in defaults */
p3_global_settings *
p3_create_global_settings_default_version_1(void)
{
p3_global_settings *r;
// if (!(r = (p3_global_settings *) malloc(sizeof(*r)))) {
if ((r = (p3_global_settings *) malloc(sizeof(p3_global_settings))) == NULL) {
return NULL;
}
pr_set_default_global_args_1(r);
return r;
}
/* Free the space of global settings */
void
p3_destroy_global_settings(p3_global_settings *a)
{
if (NULL != a) {
if (NULL != a->p_args.must_match_five_prime) {
free(a->p_args.must_match_five_prime);
a->p_args.must_match_five_prime = NULL;
}
if (NULL != a->p_args.must_match_three_prime) {
free(a->p_args.must_match_three_prime);
a->p_args.must_match_three_prime = NULL;
}
if (NULL != a->o_args.must_match_five_prime) {
free(a->o_args.must_match_five_prime);
a->o_args.must_match_five_prime = NULL;
}
if (NULL != a->o_args.must_match_three_prime) {
free(a->o_args.must_match_three_prime);
a->o_args.must_match_three_prime = NULL;
}
thal_free_parameters(&a->thermodynamic_parameters);
if (NULL != a->mp.list_prefix) {
free(a->mp.list_prefix);
a->mp.list_prefix = NULL;
}
if (a->log_settings_path != NULL) {
free(a->log_settings_path);
a->log_settings_path = NULL;
}
destroy_seq_lib(a->p_args.repeat_lib);
destroy_seq_lib(a->o_args.repeat_lib);
free(a);
a = NULL;
}
}
static void
pr_set_default_global_args_2(p3_global_settings *a)
/* Write the default values for default_values=2 into
the p3_global_settings struct */
{
pr_set_default_global_args_1(a);
a->tm_santalucia = santalucia_auto;
a->salt_corrections = santalucia;
a->thermodynamic_oligo_alignment = 1;
a->thermodynamic_template_alignment = 0;
a->p_args.divalent_conc = 1.5;
a->p_args.dntp_conc = 0.6;
a->lib_ambiguity_codes_consensus = 0;
}
/* Write the default values for default_values=1 into
the p3_global_settings struct */
static void
pr_set_default_global_args_1(p3_global_settings *a)
{
// memset(a, 0, sizeof(*a));
memset(a, 0, sizeof(p3_global_settings));
/* Arguments for primers ================================= */
a->p_args.opt_size = 20;
a->p_args.min_size = 18;
a->p_args.max_size = 27;
a->p_args.opt_tm = 60.0;
a->p_args.min_tm = 57.0;
a->p_args.max_tm = 63.0;
a->p_args.opt_bound = 97.0;
a->p_args.min_bound = -10.0;
a->p_args.max_bound = 110.0;
a->p_args.min_gc = 20.0;
a->p_args.opt_gc_content = DEFAULT_OPT_GC_PERCENT;
a->p_args.max_gc = 80.0;
a->p_args.salt_conc = 50.0;
a->p_args.divalent_conc = 0.0;
a->p_args.dntp_conc = 0.0;
a->p_args.dna_conc = 50.0;
a->p_args.dmso_conc = 0.0;
a->p_args.dmso_fact = 0.6;
a->p_args.formamide_conc = 0.0;
a->p_args.num_ns_accepted = 0;
a->p_args.max_self_any = 8.0;
a->p_args.max_self_end = 3.0;
a->p_args.max_self_any_th = 47.0;
a->p_args.max_self_end_th = 47.0;
a->p_args.max_hairpin_th = 47.0;
a->p_args.max_poly_x = 5;
a->p_args.max_repeat_compl = 12.0;
a->p_args.min_quality = 0;
a->p_args.min_end_quality = 0;
a->p_args.max_template_mispriming = PR_UNDEFINED_ALIGN_OPT;
a->p_args.max_template_mispriming_th = PR_UNDEFINED_ALIGN_OPT;
/* The following apply only to primers (and not to internal
oligos). */
a->gc_clamp = 0;
a->max_end_gc = 5;
/* Weights for objective functions for oligos and pairs. */
a->p_args.weights.compl_any = 0;
a->p_args.weights.compl_any_th = 0;
a->p_args.weights.compl_end = 0;
a->p_args.weights.compl_end_th = 0;
a->p_args.weights.end_quality = 0;
a->p_args.weights.end_stability = 0;
a->p_args.weights.gc_content_gt = 0;
a->p_args.weights.gc_content_lt = 0;
a->p_args.weights.hairpin_th = 0;
a->p_args.weights.length_gt = 1;
a->p_args.weights.length_lt = 1;
a->p_args.weights.num_ns = 0;
a->p_args.weights.pos_penalty = 1;
a->p_args.weights.repeat_sim = 0;
a->p_args.weights.seq_quality = 0;
a->p_args.weights.temp_cutoff = 5;
a->p_args.weights.temp_gt = 1;
a->p_args.weights.temp_lt = 1;
a->p_args.weights.bound_gt = 0;
a->p_args.weights.bound_lt = 0;
a->p_args.weights.template_mispriming = 0.0;
a->p_args.weights.template_mispriming_th = 0.0;
a->p_args.must_match_five_prime = NULL;
a->p_args.must_match_three_prime = NULL;
/* End of weights for objective functions for oligos and pairs. */
/* End of arguments for primers =========================== */
a->max_diff_tm = 100.0;
a->tm_santalucia = breslauer_auto;
a->salt_corrections = schildkraut;
a->annealing_temp = -10.0;
a->pair_compl_any = 8.0;
a->pair_compl_end = 3.0;
a->pair_compl_any_th = 47.0;
a->pair_compl_end_th = 47.0;
a->thermodynamic_oligo_alignment = 0;
a->thermodynamic_template_alignment = 0;
thal_set_null_parameters(&a->thermodynamic_parameters);
set_default_thal_parameters(&a->thermodynamic_parameters);
a->show_secondary_structure_alignment = 0;
a->liberal_base = 0;
a->primer_task = generic_p3;
a->pick_left_primer = 1;
a->pick_right_primer = 1;
a->pick_internal_oligo = 0;
a->first_base_index = 0;
a->num_return = 5;
a->pr_min[0] = 100;
a->pr_max[0] = 300;
a->num_intervals = 1;
a->pair_repeat_compl = 24.0;
a->quality_range_min = 0;
a->quality_range_max = 100;
a->outside_penalty = PR_DEFAULT_OUTSIDE_PENALTY;
a->inside_penalty = PR_DEFAULT_INSIDE_PENALTY;
a->max_end_stability = 100.0;
a->lowercase_masking = 0;
a->product_max_tm = PR_DEFAULT_PRODUCT_MAX_TM;
a->product_min_tm = PR_DEFAULT_PRODUCT_MIN_TM;
a->product_opt_tm = PR_UNDEFINED_DBL_OPT;
a->product_opt_size = PR_UNDEFINED_INT_OPT;
a->pair_max_template_mispriming = PR_UNDEFINED_ALIGN_OPT;
a->pair_max_template_mispriming_th = PR_UNDEFINED_ALIGN_OPT;
a->o_args.opt_size = 20;
a->o_args.min_size = 18;
a->o_args.max_size = 27;
a->o_args.opt_tm = 60.0;
a->o_args.min_tm = 57.0;
a->o_args.max_tm = 63.0;
a->o_args.opt_bound = 97.0;
a->o_args.min_bound = -10.0;
a->o_args.max_bound = 110.0;
a->o_args.min_gc = 20.0;
a->o_args.max_gc = 80.0;
a->o_args.opt_gc_content = DEFAULT_OPT_GC_PERCENT;
a->o_args.max_poly_x = 5;
a->o_args.salt_conc = 50.0;
a->o_args.divalent_conc = 0.0;
a->o_args.dntp_conc = 0.0;
a->o_args.dna_conc = 50.0;
a->o_args.dmso_conc = 0.0;
a->o_args.dmso_fact = 0.6;
a->o_args.formamide_conc = 0.0;
a->o_args.num_ns_accepted = 0;
a->o_args.max_self_any = 12.0;
a->o_args.max_self_end = 12.0;
a->o_args.max_self_any_th = 47.0;
a->o_args.max_self_end_th = 47.0;
a->o_args.max_hairpin_th = 47.0;
a->o_args.max_repeat_compl= 12.0;
a->o_args.min_quality = 0;
a->o_args.min_end_quality = 0;
a->o_args.max_template_mispriming = PR_UNDEFINED_ALIGN_OPT;
a->o_args.max_template_mispriming_th = PR_UNDEFINED_ALIGN_OPT;
a->o_args.weights.temp_gt = 1;
a->o_args.weights.temp_lt = 1;
a->o_args.weights.bound_gt = 0;
a->o_args.weights.bound_lt = 0;
a->o_args.weights.length_gt = 1;
a->o_args.weights.length_lt = 1;
a->o_args.weights.gc_content_gt = 0;
a->o_args.weights.gc_content_lt = 0;
a->o_args.weights.compl_any = 0;
a->o_args.weights.compl_end = 0;
a->o_args.weights.compl_any_th = 0;
a->o_args.weights.compl_end_th = 0;
a->o_args.weights.hairpin_th = 0;
a->o_args.weights.num_ns = 0;
a->o_args.weights.repeat_sim = 0;
a->o_args.weights.seq_quality = 0;
a->o_args.weights.end_quality = 0;
a->o_args.must_match_five_prime = NULL;
a->o_args.must_match_three_prime = NULL;
a->pr_pair_weights.primer_quality = 1;
a->pr_pair_weights.io_quality = 0;
a->pr_pair_weights.diff_tm = 0;
a->pr_pair_weights.compl_any = 0;
a->pr_pair_weights.compl_end = 0;
a->pr_pair_weights.compl_any_th = 0;
a->pr_pair_weights.compl_end_th = 0;
a->pr_pair_weights.temp_cutoff = 5;
a->pr_pair_weights.repeat_sim = 0;
a->pr_pair_weights.product_tm_lt = 0;
a->pr_pair_weights.product_tm_gt = 0;
a->pr_pair_weights.product_size_lt = 0;
a->pr_pair_weights.product_size_gt = 0;
a->lib_ambiguity_codes_consensus = 1;
/* Set to 1 for backward compatibility. This _NOT_ what
one normally wants, since many libraries contain
strings of N, which then match every oligo (very bad).
*/
a->min_left_three_prime_distance = -1;
a->min_internal_three_prime_distance = -1;
a->min_right_three_prime_distance = -1;
a->sequencing.lead = 50;
a->sequencing.spacing = 500;
a->sequencing.interval = 250;
a->sequencing.accuracy = 20;
a->p_args.min_5_prime_overlap_of_junction = 7;
a->p_args.min_3_prime_overlap_of_junction = 4;
a->o_args.min_5_prime_overlap_of_junction = 3;
a->o_args.min_3_prime_overlap_of_junction = 3;
a->mask_template = 0;
a->masking_parameters_changed = 0;
a->mp.mdir = both_separately;
a->mp.failure_rate = 0.1;
a->mp.nucl_masked_in_5p_direction = 1;
a->mp.nucl_masked_in_3p_direction = 0;
a->mp.print_sequence = 0;
a->mp.do_soft_masking = 1;
a->mp.nlists = DEFAULT_NLISTS;
a->mp.list_prefix = (char *) pr_safe_malloc (strlen (DEFAULT_LIST_FILE_PREFIX) + 1);
strcpy (a->mp.list_prefix, DEFAULT_LIST_FILE_PREFIX);
a->mp.fp = NULL;
a->mp.formula_intercept = DEFAULT_INTERCEPT;
}
/* Add a pair of integers to an array of intervals */
int
p3_add_to_interval_array(interval_array_t2 *interval_arr, int i1, int i2)
{
int c = interval_arr->count;
if (c >= PR_MAX_INTERVAL_ARRAY) return 1;
interval_arr->pairs[c][0] = i1;
interval_arr->pairs[c][1] = i2;
interval_arr->count++;
return 0;
}
/* Add 2 pairs of integers to an array of 2 intervals */
int
p3_add_to_2_interval_array(interval_array_t4 *interval_arr, int i1, int i2, int i3, int i4)
{
int c = interval_arr->count;
if (c >= PR_MAX_INTERVAL_ARRAY) return 1;
/* for a region either both values are given, or none is given */
if (((i1 == -1) && (i2 != -1)) || ((i1 != -1) && (i2 == -1)))
return 2;
if (((i3 == -1) && (i4 != -1)) || ((i3 != -1) && (i4 == -1)))
return 2;
interval_arr->left_pairs[c][0] = i1;
interval_arr->left_pairs[c][1] = i2;
interval_arr->right_pairs[c][0] = i3;
interval_arr->right_pairs[c][1] = i4;
if ((i1 == -1) && (i2 == -1))
interval_arr->any_left = 1;
if ((i3 == -1) && (i4 == -1))
interval_arr->any_right = 1;
if ((i1 == -1) && (i2 == -1) && (i3 == -1) && (i4 == -1))
interval_arr->any_pair = 1;
interval_arr->count++;
return 0;
}
/* ============================================================ */
/* END functions for global settings */
/* ============================================================ */
int
interval_array_t2_count(const interval_array_t2 *array)
{
return array->count;
}
const int *
interval_array_t2_get_pair(const interval_array_t2 *array, int i)
{
if (i > array->count) abort();
if (i < 0) abort();
return array->pairs[i];
}
/* ============================================================ */
/* BEGIN functions for p3retval */
/* ============================================================ */
/* Allocate a new primer3 state. Return NULL if out of memory. Assuming
malloc sets errno to ENOMEM according to Unix98, set errno to ENOMEM
on out-of-memory error. */
static p3retval *
create_p3retval(void)
{
// p3retval *state = (p3retval *)malloc(sizeof(*state));
p3retval *state = (p3retval *)malloc(sizeof(p3retval));
if (!state)
return NULL;
// state->fwd.oligo
// = (primer_rec *) malloc(sizeof(*state->fwd.oligo) * INITIAL_LIST_LEN);
state->fwd.oligo
= (primer_rec *) malloc(sizeof(primer_rec) * INITIAL_LIST_LEN);
// state->rev.oligo
// = (primer_rec *) malloc(sizeof(*state->rev.oligo) * INITIAL_LIST_LEN);
state->rev.oligo
= (primer_rec *) malloc(sizeof(primer_rec) * INITIAL_LIST_LEN);
// state->intl.oligo
// = (primer_rec *) malloc(sizeof(*state->intl.oligo) * INITIAL_LIST_LEN);
state->intl.oligo
= (primer_rec *) malloc(sizeof(primer_rec) * INITIAL_LIST_LEN);
if (state->fwd.oligo == NULL
|| state->rev.oligo == NULL
|| state->intl.oligo == NULL) {
free(state);
state = NULL;
return NULL;
}
state->fwd.storage_size = INITIAL_LIST_LEN;
state->rev.storage_size = INITIAL_LIST_LEN;
state->intl.storage_size = INITIAL_LIST_LEN;
state->fwd.num_elem = 0;
state->rev.num_elem = 0;
state->intl.num_elem = 0;
state->fwd.type = OT_LEFT;
state->intl.type = OT_INTL;
state->rev.type = OT_RIGHT;
state->best_pairs.storage_size = 0;
state->best_pairs.pairs = NULL;
state->best_pairs.num_pairs = 0;
init_pr_append_str(&state->glob_err);
init_pr_append_str(&state->per_sequence_err);
init_pr_append_str(&state->warnings);
memset(&state->fwd.expl, 0, sizeof(state->fwd.expl));
memset(&state->rev.expl, 0, sizeof(state->rev.expl));
memset(&state->intl.expl, 0, sizeof(state->intl.expl));
memset(&state->best_pairs.expl, 0, sizeof(state->best_pairs.expl));
return state;
}
/* ============================================================ */
/* BEGIN functions for dpal_arg_holder */
/* ============================================================ */
/* Create the dpal arg holder */
dpal_arg_holder *
create_dpal_arg_holder ()
{
dpal_arg_holder *h
= (dpal_arg_holder *) pr_safe_malloc(sizeof(dpal_arg_holder));
// h->local = (dpal_args *) pr_safe_malloc(sizeof(*h->local));
h->local = (dpal_args *) pr_safe_malloc(sizeof(dpal_args));
set_dpal_args(h->local);
h->local->flag = DPAL_LOCAL;
// h->end = (dpal_args *) pr_safe_malloc(sizeof(*h->end));
h->end = (dpal_args *) pr_safe_malloc(sizeof(dpal_args));
set_dpal_args(h->end);
h->end->flag = DPAL_GLOBAL_END;
// h->local_end = (dpal_args *) pr_safe_malloc(sizeof(*h->local_end));
h->local_end = (dpal_args *) pr_safe_malloc(sizeof(dpal_args));
set_dpal_args(h->local_end);
h->local_end->flag = DPAL_LOCAL_END;
// h->local_ambig = (dpal_args *) pr_safe_malloc(sizeof(*h->local_ambig));
h->local_ambig = (dpal_args *) pr_safe_malloc(sizeof(dpal_args));
*h->local_ambig = *h->local;
PR_ASSERT(dpal_set_ambiguity_code_matrix(h->local_ambig));
// h->local_end_ambig = (dpal_args *) pr_safe_malloc(sizeof(*h->local_end_ambig));
h->local_end_ambig = (dpal_args *) pr_safe_malloc(sizeof(dpal_args));
*h->local_end_ambig = *h->local_end;
PR_ASSERT(dpal_set_ambiguity_code_matrix(h->local_end_ambig));
return h;
}
/* Free the dpal arg holder */
void
destroy_dpal_arg_holder(dpal_arg_holder *h)
{
if (NULL != h) {
free(h->local);
free(h->end);
free(h->local_end);
free(h->local_ambig);
free(h->local_end_ambig);
free(h);
h = NULL;
}
}
/* This is a static variable that is initialized once
in choose_primers(). We make this variable have
'file' scope, we do not have to remember to free the associated
storage after each call to choose_primers(). */
static dpal_arg_holder *dpal_arg_to_use = NULL;
/* ============================================================ */
/* END functions for dpal_arg_holder */
/* ============================================================ */
/* ============================================================ */
/* BEGIN functions for thal_arg_holder */
/* ============================================================ */
/* Create the thal arg holder */
thal_arg_holder *
create_thal_arg_holder (const args_for_one_oligo_or_primer *po_args)
{
thal_arg_holder *h
= (thal_arg_holder *) pr_safe_malloc(sizeof(thal_arg_holder));
// h->any = (thal_args *) pr_safe_malloc(sizeof(*h->any));
h->any = (thal_args *) pr_safe_malloc(sizeof(thal_args));
set_thal_default_args(h->any);
h->any->type = thal_any;
h->any->mv = po_args->salt_conc;
h->any->dv = po_args->divalent_conc;
h->any->dntp = po_args->dntp_conc;
h->any->dna_conc = po_args->dna_conc;
// h->end1 = (thal_args *) pr_safe_malloc(sizeof(*h->end1));
h->end1 = (thal_args *) pr_safe_malloc(sizeof(thal_args));
set_thal_default_args(h->end1);
h->end1->type = thal_end1;
h->end1->mv = po_args->salt_conc;
h->end1->dv = po_args->divalent_conc;
h->end1->dntp = po_args->dntp_conc;
h->end1->dna_conc = po_args->dna_conc;
// h->end2 = (thal_args *) pr_safe_malloc(sizeof(*h->end2));
h->end2 = (thal_args *) pr_safe_malloc(sizeof(thal_args));
set_thal_default_args(h->end2);
h->end2->type = thal_end2;
h->end2->mv = po_args->salt_conc;
h->end2->dv = po_args->divalent_conc;
h->end2->dntp = po_args->dntp_conc;
h->end2->dna_conc = po_args->dna_conc;
// h->hairpin_th = (thal_args *) pr_safe_malloc(sizeof(*h->hairpin_th));
h->hairpin_th = (thal_args *) pr_safe_malloc(sizeof(thal_args));
set_thal_default_args(h->hairpin_th);
h->hairpin_th->type = thal_hairpin;
h->hairpin_th->mv = po_args->salt_conc;
h->hairpin_th->dv = po_args->divalent_conc;
h->hairpin_th->dntp = po_args->dntp_conc;
h->hairpin_th->dna_conc = po_args->dna_conc;
h->hairpin_th->dimer = 0;
return h;
}
/* Free the thal arg holder */
void
destroy_thal_arg_holder(thal_arg_holder *h)
{
if (h != NULL) {
free(h->any);
free(h->end1);
free(h->end2);
free(h->hairpin_th);
free(h);
h = NULL;
}
}
static thal_arg_holder *thal_arg_to_use = NULL;
static thal_arg_holder *thal_oligo_arg_to_use = NULL;
/* ============================================================ */
/* END functions for thal_arg_holder */
/* ============================================================ */
/* Deallocate a primer3 state */
void
destroy_p3retval(p3retval *state)
{
if (!state)
return;
free_repeat_sim_score(state);
free(state->fwd.oligo);
free(state->rev.oligo);
free(state->intl.oligo);
if (state->best_pairs.storage_size != 0 && state->best_pairs.pairs)
free(state->best_pairs.pairs);
destroy_pr_append_str_data(&state->glob_err);
destroy_pr_append_str_data(&state->per_sequence_err);
destroy_pr_append_str_data(&state->warnings);
free(state);
state = NULL;
}
void
destroy_dpal_thal_arg_holder() {
if(dpal_arg_to_use != NULL) {
destroy_dpal_arg_holder(dpal_arg_to_use);
dpal_arg_to_use = NULL;
}
if(thal_arg_to_use != NULL) {
destroy_thal_arg_holder(thal_arg_to_use);
thal_arg_to_use = NULL;
}
if(thal_oligo_arg_to_use != NULL) {
destroy_thal_arg_holder(thal_oligo_arg_to_use);
thal_oligo_arg_to_use = NULL;
}
}
const oligo_array *
p3_get_rv_fwd(const p3retval *r) {
return &r->fwd;
}
const oligo_array *
p3_get_rv_intl(const p3retval *r) {
return &r->intl;
}
const oligo_array *
p3_get_rv_rev(const p3retval *r) {
return &r->rev;
}
const pair_array_t *
p3_get_rv_best_pairs(const p3retval *r) {
return &r->best_pairs;
}
/* ============================================================ */
/* END functions for p3retval */
/* ============================================================ */
/* ============================================================ */
/* BEGIN functions for seq_arg_holder */
/* ============================================================ */
/* Create and initialize a seq_args data structure */
seq_args_t*
create_seq_arg()
{
// seq_args_t* r = (seq_args_t* ) malloc(sizeof(*r));
seq_args_t* r = (seq_args_t* ) malloc(sizeof(seq_args_t));
if (r == NULL) return NULL; /* Out of memory */
memset(r, 0, sizeof(seq_args_t));
r->start_codon_pos = PR_DEFAULT_START_CODON_POS;
r->start_codon_seq[0] = 'A';
r->start_codon_seq[1] = 'T';
r->start_codon_seq[2] = 'G';
r->start_codon_seq[3] = '\0';
r->incl_l = -1; /* Indicates logical NULL. */
r->force_left_start = PR_NULL_FORCE_POSITION; /* Indicates logical NULL. */
r->force_left_end = PR_NULL_FORCE_POSITION; /* Indicates logical NULL. */
r->force_right_start = PR_NULL_FORCE_POSITION; /* Indicates logical NULL. */
r->force_right_end = PR_NULL_FORCE_POSITION; /* Indicates logical NULL. */
r->primer_overlap_junctions_count = 0;
r->intl_overlap_junctions_count = 0;
r->n_quality = 0;
r->quality = NULL;
r->overhang_left = NULL;
r->overhang_right = NULL;
r->overhang_right_rv = NULL;
return r;
}
/* Free a seq_arg data structure */
void
destroy_seq_args(seq_args_t* sa)
{
if (sa == NULL) return;
free(sa->internal_input);
free(sa->left_input);
free(sa->right_input);
free(sa->sequence);
free(sa->quality);
free(sa->trimmed_seq);
free(sa->overhang_left);
free(sa->overhang_right);
free(sa->overhang_right_rv);
/* edited by T. Koressaar for lowercase masking */
free(sa->trimmed_orig_seq);
free(sa->trimmed_masked_seq_r);
free(sa->trimmed_masked_seq);
free(sa->upcased_seq);
free(sa->upcased_seq_r);
free(sa->sequence_name);
free(sa);
sa = NULL;
}
/* ============================================================ */
/* END functions for seq_arg_holder */
/* ============================================================ */
/* Function used to de-allocate the memory used by the hash maps
allocated in choose_pair_or_triple. */
static void free_pair_memory(int rev_num_elem)
{
// std::hash_map *hmap;
// std::hash_map::iterator it;
khash_t(primer_pair_map) *hmap = NULL;
khiter_t it;
primer_pair *pp = NULL;
int i;
if (max_j_seen != NULL) {
free( max_j_seen );
max_j_seen = NULL;
}
for (i=0; i < rev_num_elem; i++) {
hmap = pairs[i];
if (hmap != NULL) {
// for (it=hmap->begin(); it!=hmap->end(); it++) {
for (it = kh_begin(hmap); it != kh_end(hmap); ++it) {
// pp = it->second;
// if (pp != NULL) {
// // delete pp;
// }
if (kh_exist(hmap, it)) {
pp = kh_value(hmap, it);
if (pp != NULL) {
free(pp);
kh_value(hmap, it) = NULL;
}
}
}
// delete hmap;
kh_destroy(primer_pair_map, hmap);
}
}
if (pairs != NULL) {
free(pairs);
pairs = NULL;
}
}
void print_masking_parameters(const masker_parameters *mp, FILE* fd);
/* ============================================================ */
/* BEGIN choose_primers() */
/* The main primer3 interface */
/* See libprimer3.h for documentation. */
/* ============================================================ */
p3retval *
choose_primers(const p3_global_settings *pa,
seq_args_t* sa)
{
/* Create retval and set were to find the results */
p3retval *retval = create_p3retval();
if (retval == NULL) return NULL;
PR_ASSERT(NULL != pa);
PR_ASSERT(NULL != sa);
/* NOTE: primer3-py added to debugging arguments `pa` and `sa` */
if (pa->do_log_settings) {
FILE* logf_ptr = fopen(pa->log_settings_path, "ab");
if (logf_ptr == NULL) {
printf("Error opening file %s\n", pa->log_settings_path);
fflush(stdout);
exit(1);
}
p3_print_args_fd(pa, sa, logf_ptr);
print_masking_parameters(&(pa->mp), logf_ptr);
fclose(logf_ptr);
}
if (pa->dump) {
printf("Start of choose_primers:\n");
p3_print_args(pa, sa) ;
}
/* Set the general output type */
if (pa->pick_left_primer && pa->pick_right_primer) {
retval->output_type = primer_pairs;
} else {
retval->output_type = primer_list;
}
if (pa->primer_task == pick_primer_list ||
pa->primer_task == pick_sequencing_primers) {
retval->output_type = primer_list;
}
/*
* For catching ENOMEM. WARNING: We can only use longjmp to escape
* from errors that have been called through choose_primers().
* Therefore, if we subsequently update other static functions in
* this file to have external linkage then we need to check whether
* they call (or use functions that in turn call) longjmp to handle
* ENOMEM.
*/
if (setjmp(_jmp_buf) != 0) {
/* Check if this was a thermodynamic alignment length error. */
if (thermodynamic_alignment_length_error == 1) {
thermodynamic_alignment_length_error = 0;
/* Set per sequence error */
pr_append_new_chunk(&retval->per_sequence_err,
thermodynamic_alignment_length_error_msg);
if (thermodynamic_alignment_length_error_msg != NULL) {
free(thermodynamic_alignment_length_error_msg);
thermodynamic_alignment_length_error_msg = NULL;
}
/* Other necessary cleanup. */
free_pair_memory(retval->rev.num_elem);
return retval;
}
/* This was a memory error. */
destroy_p3retval(retval);
return NULL; /* If we get here, that means errno should be ENOMEM. */
}
/* Change some parameters to fit the task */
_adjust_seq_args(pa, sa, &retval->per_sequence_err,&retval->warnings);
if (pa->dump) {
printf("After _adjust_seq_args\n");
p3_print_args(pa, sa) ;
}
if (!pr_is_empty(&retval->per_sequence_err)) return retval;
/* TO DO -- move the check below to pr_data_control and issue a
warning if it fails. */
/* if (pa->p_args.min_quality != 0
&& pa->p_args.min_end_quality < pa->p_args.min_quality)
... issue warning ...
pa->p_args.min_end_quality = pa->p_args.min_quality; */
/* Check if the input in sa and pa makes sense */
if (_pr_data_control(pa, sa,
&retval->glob_err, /* Fatal errors */
&retval->per_sequence_err, /* Non-fatal errors */
&retval->warnings
) !=0 ) {
return retval;
}
set_retval_both_stop_codons(sa, retval);
/* Set the parameters for alignment functions
if dpal_arg_to_use, a static variable that has 'file'
scope, has not yet been initialized. */
if (dpal_arg_to_use == NULL) {
dpal_arg_to_use = create_dpal_arg_holder();
}
if(thal_arg_to_use == NULL) {
thal_arg_to_use = create_thal_arg_holder(&pa->p_args);
} else {
destroy_thal_arg_holder(thal_arg_to_use);
thal_arg_to_use = create_thal_arg_holder(&pa->p_args);
}
if(thal_oligo_arg_to_use == NULL) {
thal_oligo_arg_to_use = create_thal_arg_holder(&pa->o_args);
} else {
destroy_thal_arg_holder(thal_oligo_arg_to_use);
thal_oligo_arg_to_use = create_thal_arg_holder(&pa->o_args);
}
if (pa->primer_task == pick_primer_list) {
make_complete_primer_lists(retval, pa, sa,
dpal_arg_to_use,thal_arg_to_use,thal_oligo_arg_to_use);
} else if (pa->primer_task == pick_sequencing_primers) {
pick_sequencing_primer_list(retval, pa, sa,
dpal_arg_to_use,thal_arg_to_use);
} else if (pa->primer_task == check_primers) {
add_primers_to_check(retval, pa, sa,
dpal_arg_to_use, thal_arg_to_use, thal_oligo_arg_to_use);
} else { /* The general way to pick primers */
/* Populate the forward and reverse primer lists */
if (make_detection_primer_lists(retval, pa, sa,
dpal_arg_to_use,thal_arg_to_use) != 0) {
/* There was an error */
return retval;
}
/* Populate the internal oligo lists */
if ( pa->pick_internal_oligo) {
if (make_internal_oligo_list(retval, pa, sa,
dpal_arg_to_use,thal_oligo_arg_to_use) != 0) {
/* There was an error*/
return retval;
}
}
}
if (pa->pick_right_primer &&
(pa->primer_task != pick_sequencing_primers)) {
sort_primer_array(&retval->rev);
}
if (pa->pick_left_primer &&
(pa->primer_task != pick_sequencing_primers)) {
sort_primer_array(&retval->fwd);
}
/* If we are returning a list of internal oligos, sort them by their
'goodness'. We do not care if these are sorted if we end up in
choose_pair_or_triple(), since this calls
choose_internal_oligo(), which selects the best internal oligo
for a given primer pair. */
if (retval->output_type == primer_list && pa->pick_internal_oligo == 1) {
sort_primer_array(&retval->intl);
}
/* Select primer pairs if needed */
if (retval->output_type == primer_pairs) {
choose_pair_or_triple(retval, pa, sa, dpal_arg_to_use, thal_arg_to_use,
thal_oligo_arg_to_use, &retval->best_pairs);
}
/* Calculate secondary structures only for the selected primers */
if (pa->show_secondary_structure_alignment == 1) {
recalc_secundary_structures(pa, sa, dpal_arg_to_use, thal_arg_to_use,
thal_oligo_arg_to_use, retval);
}
if (pa->dump) {
printf("End of choose_primers:\n");
p3_print_args(pa, sa) ;
}
return retval;
}
/* ============================================================ */
/* END choose_primers() */
/* ============================================================ */
/* ============================================================ */
/* BEGIN choose_pair_or_triple
This function uses retval->fwd and retval->rev and
updates the oligos in these array.
This function posibly uses retval->intl and updates its
elements via choose_internal_oligo().
This function examines primer pairs or triples to find
pa->num_return pairs or triples to return.
Results are returned in best_pairs and in
retval->best_pairs.expl */
/* ============================================================ */
static void
choose_pair_or_triple(p3retval *retval,
const p3_global_settings *pa,
const seq_args_t* sa,
const dpal_arg_holder *dpal_arg_to_use,
const thal_arg_holder *thal_arg_to_use,
const thal_arg_holder *thal_oligo_arg_to_use,
pair_array_t *best_pairs) {
int i, j; /* Loop index. */
int n_int; /* Index of the internal oligo */
int more_intl_oligos = 1;
int valid_intl;
/*int *max_j_seen; */ /* The maximum value of j (loop index for forward primers)
that has been examined for every reverse primer
index (i) -- global variable now */
int update_stats = 1; /* Flag to indicate whether pair_stats
should be updated. */
primer_pair h; /* The current pair which is being evaluated. */
primer_pair the_best_pair; /* The best pair is being "remembered". */
pair_stats *pair_expl = &retval->best_pairs.expl; /* For statistics */
int product_size_range_index = 0;
int trace_me = 0;
int the_best_i, the_best_j;
/* Hash maps used to store pairs that were computed */
/* std::hash_map **pairs; */
/* pairs is an array of pointers to hash maps. It will be indexed
by the indices of the reverse primers in retval->rev. -- global var now */
// std::hash_map *hmap, *best_hmap = NULL;
khash_t(primer_pair_map) *hmap = NULL;
khash_t(primer_pair_map) *best_hmap = NULL;
/* hmap and best_hmap will be pointers to hash maps also pointed to
by elements of pairs. */
// std::hash_map::iterator it;
khiter_t it; // khash iterator / key hybrid type
int ret; // return value for error code on khash
primer_pair *pp = NULL;
primer_pair *best_pp = NULL;
int pair_found = 0;
kh_clear(primer_pair_map, hmap); // only to avoid compiler warning for unused function
// pairs =
// (std::hash_map**)
// calloc (retval->rev.num_elem,
// sizeof(std::hash_map*));
pairs = (khash_t(primer_pair_map) **) calloc (retval->rev.num_elem,
sizeof(khash_t(primer_pair_map) *));
if (!pairs) { longjmp(_jmp_buf, 1); }
memset(&the_best_pair, 0, sizeof(the_best_pair));
max_j_seen = (int *) malloc(sizeof(int) * retval->rev.num_elem);
for (i = 0; i < retval->rev.num_elem; i++) { max_j_seen[i] = -1; }
/* Pick pairs till we have enough. */
while(1) {
/* FIX ME, is this memset really needed? Apparently slow */
memset(&the_best_pair, 0, sizeof(the_best_pair));
the_best_i = -1;
the_best_j = -1;
/* To start put penalty to the maximum */
the_best_pair.pair_quality = DBL_MAX;
/* Iterate over the reverse primers. */
for (i = 0; i < retval->rev.num_elem; i++) {
hmap = pairs[i];
/* Pairs[i] is NULL if there has never been an assignment to
pairs[i] because pairs was allocated by calloc, which
sets the allocated memory to 0. */
/* Only use a primer that *might be* legal or that the caller
has provided and specified as "must use". Primers are *NOT*
FULLY ASSESSED until the call to characterize_pair(), in
order to avoid expensive computations (mostly alignments)
unless necessary. */
if (!OK_OR_MUST_USE(&retval->rev.oligo[i])) {
/* Can free the memory used by the hmap associated to this
reverse primer */
if (hmap) {
// for (it=hmap->begin(); it!=hmap->end(); it++) {
for (it = kh_begin(hmap); it != kh_end(hmap); ++it) {
/* it->second is the second element (i.e. the 'value', as
opposed to the 'key'). */
// pp = it->second;
// delete pp;{
if (kh_exist(hmap, it)) {
pp = kh_value(hmap, it);
if (pp != NULL) {
free(pp);
kh_value(hmap, it) = NULL;
}
}
}
if (hmap == best_hmap) { best_hmap = NULL; }
// delete hmap;
kh_destroy(primer_pair_map, hmap);
hmap = NULL;
pairs[i] = NULL;
}
continue;
}
/* If the pair cannot be better than the one already
* selected, then we can skip remaining reverse primers */
if (pa->pr_pair_weights.primer_quality *
(retval->rev.oligo[i].quality + retval->fwd.oligo[0].quality)
> the_best_pair.pair_quality) {
break;
}
if (!more_intl_oligos) {
break;
}
if (retval->rev.oligo[i].overlaps) {
/* The stats will not keep track of the pair correctly
after the first pass, because an oligo might
have been legal on one pass but become illegal on
a subsequent pass. */
if (update_stats) {
if (trace_me) {
fprintf(stderr,
"i=%d, j=%d, overlaps_oligo_in_better_pair++\n",
i, j);
}
pair_expl->overlaps_oligo_in_better_pair++;
}
/* Can free the memory used by the hmap associated to this reverse primer */
if (hmap) {
// for (it=hmap->begin(); it!=hmap->end(); it++) {
for (it = kh_begin(hmap); it != kh_end(hmap); ++it) {
/* it->second is the second element (i.e. the 'value', as
opposed to the 'key'). */
// pp = it->second;
// delete pp;
if (kh_exist(hmap, it)) {
pp = kh_value(hmap, it);
if (pp != NULL) {
free(pp);
kh_value(hmap, it) = NULL;
}
}
}
if (hmap == best_hmap) { best_hmap = NULL; }
// delete hmap;
kh_destroy(primer_pair_map, hmap);
hmap = NULL;
pairs[i] = NULL;
}
continue;
}
/* Loop over forward primers */
for (j = 0; j < retval->fwd.num_elem; j++) {
int must_use;
double product_size;
/* We check the reverse oligo again, because we may
have determined that it is "not ok", even though
(as a far as we knew), it was ok above. */
if (!OK_OR_MUST_USE(&retval->rev.oligo[i])) {
/* Can free the memory used by the hmap associated to this reverse primer */
if (hmap) {
// for (it=hmap->begin(); it!=hmap->end(); it++) {
for (it = kh_begin(hmap); it != kh_end(hmap); ++it) {
/* it->second is the second element (i.e. the 'value', as
opposed to the 'key'). */
// pp = it->second;
// delete pp;
if (kh_exist(hmap, it)) {
pp = kh_value(hmap, it);
if (pp != NULL) {
free(pp);
kh_value(hmap, it) = NULL;
}
}
}
if (hmap == best_hmap) { best_hmap = NULL; }
// delete hmap;
kh_destroy(primer_pair_map, hmap);
hmap = NULL;
pairs[i] = NULL;
}
break;
}
/* Only use a primer that is legal, or that the caller
has provided and specified as "must use". */
if (!OK_OR_MUST_USE(&retval->fwd.oligo[j])) continue;
/* If the pair cannot be better than the one already
* selected, then we can skip remaining forward primers
* for this reverse primer */
if (pa->pr_pair_weights.primer_quality *
(retval->fwd.oligo[j].quality + retval->rev.oligo[i].quality)
> the_best_pair.pair_quality) {
break;
}
if (!more_intl_oligos) {
break;
}
/* Need to have this here because if we break just above, then,
at a later iteration, we may need to examine the oligo
pair with reverse oligo at i and forward oligo at j. */
update_stats = 0;
if (j > max_j_seen[i]) {
if (trace_me) {
fprintf(stderr,
"updates ON: i=%d, j=%d, max_j_seen[%d]=%d\n",
i, j, i, max_j_seen[i]);
}
max_j_seen[i] = j;
if (trace_me) {
fprintf(stderr, "max_j_seen[%d] --> %d\n", i, max_j_seen[i]);
}
if (trace_me) { fprintf(stderr, "updates on\n"); }
update_stats = 1;
}
if (retval->fwd.oligo[j].overlaps) {
/* The stats will not keep track of the pair correctly
after the first pass, because an oligo might
have been legal on one pass but become illegal on
a subsequent pass. */
if (update_stats) {
if (trace_me) {
fprintf(stderr,
"i=%d, j=%d, overlaps_oligo_in_better_pair++\n",
i, j);
}
pair_expl->overlaps_oligo_in_better_pair++;
}
continue;
}
/* Some simple checks first, before searching the hashmap */
must_use = 0;
if ((pa->primer_task == check_primers) ||
((retval->fwd.oligo[j].must_use != 0) &&
(retval->rev.oligo[i].must_use != 0))) {
must_use = 1;
}
/* Determine if overlap with an overlap point is required, and
if so, whether one of the primers in the pairs overlaps
that point. */
if ((sa->primer_overlap_junctions_count > 0)
&& !(retval->rev.oligo[i].overlaps_overlap_position
|| retval->fwd.oligo[j].overlaps_overlap_position)
) {
if (update_stats) {
pair_expl->considered++;
pair_expl->does_not_overlap_a_required_point++;
}
if (!must_use) continue;
}
/* Check product size now */
product_size
= retval->rev.oligo[i].start - retval->fwd.oligo[j].start+1;
if (product_size < pa->pr_min[product_size_range_index] ||
product_size > pa->pr_max[product_size_range_index]) {
if (update_stats) {
/* This line NEW */
if (!must_use) {
pair_expl->considered++;
}
pair_expl->product++;
}
if (!must_use) { continue; }
}
/* Check if pair was already computed */
pair_found = 0;
if (hmap) {
// it = hmap->find(j);
it = kh_get(primer_pair_map, hmap, j);
// if (it != hmap->end()) {
if (it != kh_end(hmap)) {
pair_found = 1;
/* it->second is the second element (i.e. the 'value', as
opposed to the 'key'). */
// pp = it->second;
pp = kh_value(hmap, it);
if (pp) {
/* The pair was computed, it isn't illegal and it wasn't
selected yet */
if (update_stats) {
pair_expl->considered++;
if (trace_me) {
fprintf(stderr, "ok++\n");
}
pair_expl->ok++;
}
/* Check if this is a better pair */
if (compare_primer_pair(pp, &the_best_pair) < 0) {
the_best_pair = *pp;
the_best_i = i;
the_best_j = j;
best_hmap = hmap;
best_pp = pp;
}
/* There cannot be a better pair */
if (the_best_pair.pair_quality == 0) {
break;
}
} /* else - pp is NULL - it's illegal or already selected */
}
} else {
/* Create this hashmap */
// hmap = new std::hash_map;
hmap = kh_init(primer_pair_map);
if (!hmap) {
longjmp(_jmp_buf, 1);
}
pairs[i] = hmap;
}
if (!pair_found) {
/* Characterize the pair. h is initialized by this
call. */
int tmp = 0;
tmp = characterize_pair(retval, pa, sa, j, i,
product_size_range_index,
&h, dpal_arg_to_use,
thal_arg_to_use,
update_stats);
if (tmp == PAIR_OK) {
/* Choose internal oligo if needed */
if (pa->pick_right_primer && pa->pick_left_primer
&& pa->pick_internal_oligo) {
if (choose_internal_oligo(retval, h.left, h.right,
&n_int, &more_intl_oligos, sa, pa,
dpal_arg_to_use, thal_oligo_arg_to_use)!=0) {
/* We were UNable to choose an internal oligo. */
if (update_stats) {
pair_expl->internal++;
}
/* Mark the pair as not good - the entry in the hash
map will be a NULL */
// (*hmap)[j] = NULL;
it = kh_get(primer_pair_map, hmap, j);
if (it == kh_end(hmap)) {
it = kh_put(primer_pair_map, hmap, j, &ret);
if (!ret) { kh_del(primer_pair_map, hmap, it); }
}
kh_value(hmap, it) = NULL;
continue;
} else {
/* We DID choose an internal oligo, and we
set h.intl to point to it. */
h.intl = &retval->intl.oligo[n_int];
}
}
if (update_stats) {
if (trace_me) {
fprintf(stderr, "ok++\n");
}
pair_expl->ok++;
}
/* Calculate the pair penalty */
h.pair_quality = obj_fn(pa, &h);
PR_ASSERT(h.pair_quality >= 0.0);
/* Save the pair */
// pp = new primer_pair;
pp = (primer_pair *) malloc(sizeof(primer_pair));
if (!pp) {
longjmp(_jmp_buf, 1);
}
*pp = h;
// (*hmap)[j] = pp;
it = kh_get(primer_pair_map, hmap, j);
if (it == kh_end(hmap)) {
it = kh_put(primer_pair_map, hmap, j, &ret);
}
kh_value(hmap, it) = pp;
/* The current pair (h) is the new best pair if it is
better than the best pair so far. */
if (compare_primer_pair(&h, &the_best_pair) < 0) {
the_best_pair = h;
the_best_i = i;
the_best_j = j;
best_hmap = hmap;
best_pp = pp;
}
/* There cannot be a better pair */
if (the_best_pair.pair_quality == 0) {
break;
}
} else if (tmp == PAIR_FAILED) {
/* Illegal pair */
// (*hmap)[j] = NULL;
it = kh_get(primer_pair_map, hmap, j);
if (it == kh_end(hmap)) {
it = kh_put(primer_pair_map, hmap, j, &ret);
}
kh_value(hmap, it) = NULL;
}
}
} /* for (j=0; jfwd.num_elem; j++) -- inner loop */
/* Check if there cannot be a better pair than best found */
if (the_best_pair.pair_quality == 0) {
break;
}
} /* for (i = 0; i < retval->rev.num_elem; i++) --- outer loop */
if (!more_intl_oligos) {
/* No more internal oligos left */
break;
}
if (the_best_pair.pair_quality == DBL_MAX) {
/* No pair was found. Try another product-size-range,
if one exists. */
product_size_range_index++;
/* Re-set the high-water marks for the indices
for reverse and forward primers: */
for (i = 0; i < retval->rev.num_elem; i++) max_j_seen[i] = -1;
if (!(product_size_range_index < pa->num_intervals)) {
/* We ran out of product-size-ranges. Exit the while loop. */
break;
/* Our bookkeeping was incorrect unless the assertion below is
true. If num_intervals > 1 or min_three_*_prime_distance >
-1 the assertion below might not be true. */
PR_ASSERT(!((pa->num_intervals == 1) &&
((pa->min_left_three_prime_distance == -1) ||
(pa->min_right_three_prime_distance == -1)))
|| (best_pairs->num_pairs == pair_expl->ok));
}
} else {
/* Store the best primer for output */
if (trace_me) {
fprintf(stderr, "ADD pair i=%d, j=%d\n", the_best_i, the_best_j);
}
if (!pa->pick_internal_oligo || !(sa->intl_overlap_junctions_count > 0)) {
add_pair(&the_best_pair, best_pairs);
} else {
valid_intl = 1;
for (j = 0; j < best_pairs->num_pairs; j++) {
if (intl_oligo_in_pair_overlaps_used_oligo(best_pairs->pairs[j].intl,
&the_best_pair,
pa->min_internal_three_prime_distance)) {
valid_intl = 0;
}
}
if (valid_intl) {
add_pair(&the_best_pair, best_pairs);
}
}
/* Mark the pair as already selected */
// delete best_pp;
// (*best_hmap)[the_best_j] = NULL;
if (best_pp != NULL) {
free(best_pp);
best_pp = NULL;
}
it = kh_get(primer_pair_map, best_hmap, the_best_j);
if (it == kh_end(best_hmap)) {
it = kh_put(primer_pair_map, best_hmap, the_best_j, &ret);
}
kh_value(best_hmap, it) = NULL;
/* Update the overlaps flags */
for (i = 0; i < retval->rev.num_elem; i++) {
if (right_oligo_in_pair_overlaps_used_oligo(&retval->rev.oligo[i],
&the_best_pair,
pa->min_right_three_prime_distance)) {
retval->rev.oligo[i].overlaps = 1;
}
}
for (j = 0; j < retval->fwd.num_elem; j++) {
if (left_oligo_in_pair_overlaps_used_oligo(&retval->fwd.oligo[j],
&the_best_pair,
pa->min_left_three_prime_distance)) {
retval->fwd.oligo[j].overlaps = 1;
}
}
/* Only exclude oligos if a overlap position is given */
if ((pa->pick_internal_oligo) && (sa->intl_overlap_junctions_count > 0)) {
for (j = 0; j < retval->intl.num_elem; j++) {
if (intl_oligo_in_pair_overlaps_used_oligo(&retval->intl.oligo[j],
&the_best_pair,
pa->min_internal_three_prime_distance)) {
retval->intl.oligo[j].overlaps = 1;
}
}
}
/* If we have enough then stop the while loop */
if (pa->num_return == best_pairs->num_pairs) {
break;
}
}
} /* end of while(continue_trying == 1) */
/* Final cleanup of dynamically allocated storage for this
function. */
free_pair_memory(retval->rev.num_elem);
}
/* ============================================================ */
/* END choose_pair_or_triple */
/* ============================================================ */
/* ============================================================ */
/* BEGIN choose_internal_oligo */
/* Choose best internal oligo for given pair of left and right
primers. */
/* ============================================================ */
static int
choose_internal_oligo(p3retval *retval,
const primer_rec *left,
const primer_rec *right,
int *nm,
int *more_intl_oligos,
const seq_args_t* sa,
const p3_global_settings *pa,
const dpal_arg_holder *dpal_arg_to_use,
const thal_arg_holder *thal_arg_to_use
)
{
int i,k;
double min;
char oligo_seq[MAX_PRIMER_LENGTH+1], revc_oligo_seq[MAX_PRIMER_LENGTH+1];
primer_rec *h;
min = 1000000.;
i = -1;
*more_intl_oligos = 0;
for (k=0; k < retval->intl.num_elem; k++) {
h = &retval->intl.oligo[k]; /* h is the record for the oligo currently
under consideration */
if (h->overlaps) {
if (!(h)->must_use) continue;
} else {
*more_intl_oligos = 1;
}
if ((h->start > (left->start + (left->length-1)))
&& ((h->start + (h->length-1))
< (right->start-right->length+1))
&& (h->quality < min)
&& (OK_OR_MUST_USE(h))) {
if (h->self_any == ALIGN_SCORE_UNDEF && pa->thermodynamic_oligo_alignment==0) {
_pr_substr(sa->trimmed_seq, h->start, h->length, oligo_seq);
p3_reverse_complement(oligo_seq, revc_oligo_seq);
oligo_compl(h, &pa->o_args, &retval->intl.expl,
dpal_arg_to_use, oligo_seq, revc_oligo_seq);
if (!OK_OR_MUST_USE(h)) { continue; }
}
if (h->self_any == ALIGN_SCORE_UNDEF && pa->thermodynamic_oligo_alignment==1) {
_pr_substr(sa->trimmed_seq, h->start, h->length, oligo_seq);
p3_reverse_complement(oligo_seq, revc_oligo_seq);
oligo_compl_thermod(h, &pa->o_args, &retval->intl.expl,
thal_oligo_arg_to_use, oligo_seq, oligo_seq);
if (!OK_OR_MUST_USE(h)) { continue; }
}
if(h->hairpin_th == ALIGN_SCORE_UNDEF && pa->thermodynamic_oligo_alignment==1) {
_pr_substr(sa->trimmed_seq, h->start, h->length, oligo_seq);
oligo_hairpin(h, &pa->o_args,
&retval->intl.expl, thal_oligo_arg_to_use,
oligo_seq);
if (!OK_OR_MUST_USE(h)) { continue; }
}
if (h->repeat_sim.score == NULL) {
oligo_repeat_library_mispriming(h, pa, sa, OT_INTL, &retval->intl.expl,
dpal_arg_to_use, &retval->glob_err);
if (!OK_OR_MUST_USE(h)) { continue; }
}
min = h->quality;
i = k;
} /* if ((h->start.... */
} /* for (k=0;..... */
*nm = i;
if(*nm < 0) return 1;
return 0;
}
/* ============================================================ */
/* END choose_internal_oligo */
/* ============================================================ */
/*
Translate the values in the stats struct into an warning string.
Call this function only if the 'stat's contains the _errors_
associated with a given primer i.e. that primer was supplied by the
caller and pick_anyway is set.
*/
void
add_must_use_warnings(pr_append_str *warning,
const char* text,
const oligo_stats *stats)
{
const char *sep = "/";
pr_append_str s;
s.data = NULL;
s.storage_size = 0;
if (stats->size_min) {pr_append_w_sep(&s, sep, "Too short");}
if (stats->size_max) {pr_append_w_sep(&s, sep, "Too long");}
if (stats->ns) {pr_append_w_sep(&s, sep, "Too many Ns");}
if (stats->target) {pr_append_w_sep(&s, sep, "Overlaps Target");}
if (stats->excluded) {pr_append_w_sep(&s, sep, "Overlaps Excluded Region");}
if (stats->gc) {pr_append_w_sep(&s, sep, "Unacceptable GC content");}
if (stats->gc_clamp) {pr_append_w_sep(&s, sep, "No GC clamp");}
if (stats->temp_min) {pr_append_w_sep(&s, sep, "Tm too low");}
if (stats->temp_max) {pr_append_w_sep(&s, sep, "Tm too high");}
if (stats->bound_min) pr_append_w_sep(&s, sep, "Fraction bound too low");
if (stats->bound_max) pr_append_w_sep(&s, sep, "Fraction bound too high");
if (stats->compl_any) {pr_append_w_sep(&s, sep, "High self complementarity");}
if (stats->compl_end)
{pr_append_w_sep(&s, sep, "High end self complementarity");}
if (stats->hairpin_th) {pr_append_w_sep(&s, sep, "High hairpin stability (thermod. approach)");}
if (stats->repeat_score)
{pr_append_w_sep(&s, sep, "High similarity to mispriming or mishyb library");}
if (stats->poly_x) {pr_append_w_sep(&s, sep, "Long poly-X");}
if (stats->seq_quality) {pr_append_w_sep(&s, sep, "Low sequence quality");}
if (stats->stability) {pr_append_w_sep(&s, sep, "High 3' stability");}
if (stats->no_orf) {pr_append_w_sep(&s, sep, "Would not amplify any ORF");}
if (stats->not_in_any_left_ok_region) {pr_append_w_sep(&s, sep, "Not in any ok left region");}
if (stats->not_in_any_right_ok_region) {pr_append_w_sep(&s, sep, "Not in any ok right region");}
/* edited by T. Koressaar for lowercase masking: */
if (stats->gmasked)
{pr_append_w_sep(&s, sep, "Masked with lowercase letter");}
if (stats->must_match_fail)
{pr_append_w_sep(&s, sep, "Failed must_match requirements");}
if (s.data) {
pr_append_new_chunk(warning, text);
pr_append(warning, " is unacceptable: ");
pr_append(warning, s.data);
free(s.data);
s.data = NULL;
}
}
/*
Also see the documentation in librimer3.h,
p3_global_settings.min_{left/right_}three_prime_distance.
If min_dist == -1, return 0
If min_dist == 0:
Return 1 if the left or the right
primer is identical to the left or right
primer (respectively) in best_pair.
Otherwise return 0.
If min_dist > 0:
Return 1 if EITHER:
(1) The 3' end of the left primer in pair is
< min_dist from the 3' end of the left primer
in best_pair
OR
(2) The 3' end of the right primer in pair is
< min_dist from the 3' end of the right primer
in best_pair
*/
static int
right_oligo_in_pair_overlaps_used_oligo(const primer_rec *right,
const primer_pair *best_pair,
int min_dist)
{
int best_pos, pair_pos;
if (min_dist == -1) {
return 0;
}
best_pos = best_pair->right->start - best_pair->right->length + 1;
pair_pos = right->start - right->length + 1;
if ((abs(best_pos - pair_pos) < min_dist)
&& (min_dist != 0)) { return 1; }
if ((best_pair->right->length == right->length)
&& (best_pair->right->start == right->start)
&& (min_dist == 0)) {
return 1;
}
return 0;
}
static int
left_oligo_in_pair_overlaps_used_oligo(const primer_rec *left,
const primer_pair *best_pair,
int min_dist)
{
int best_pos, pair_pos;
if (min_dist == -1) {
return 0;
}
best_pos = best_pair->left->start + best_pair->left->length - 1;
pair_pos = left->start + left->length - 1;
if ((abs(best_pos - pair_pos) < min_dist)
&& (min_dist != 0)) { return 1; }
if ((best_pair->left->length == left->length)
&& (best_pair->left->start == left->start)
&& (min_dist == 0)) {
return 1;
}
return 0;
}
static int
intl_oligo_in_pair_overlaps_used_oligo(const primer_rec *left,
const primer_pair *best_pair,
int min_dist)
{
int best_pos, pair_pos;
if (min_dist == -1)
return 0;
best_pos = best_pair->intl->start + best_pair->intl->length - 1;
pair_pos = left->start + left->length - 1;
if ((abs(best_pos - pair_pos) < min_dist)
&& (min_dist != 0)) { return 1; }
if ((best_pair->intl->length == left->length)
&& (best_pair->intl->start == left->start)
&& (min_dist == 0)) {
return 1;
}
return 0;
}
/* Add 'pair' to 'retpair'; always appends. */
static void
add_pair(const primer_pair *pair,
pair_array_t *retpair)
{
/* If array is not initialised, initialise it with the size of pairs
to return */
if (0 == retpair->storage_size) {
retpair->storage_size = INITIAL_NUM_RETURN;
// retpair->pairs
// = (primer_pair *)
// pr_safe_malloc(retpair->storage_size * sizeof(*retpair->pairs));
retpair->pairs
= (primer_pair *)
pr_safe_malloc(retpair->storage_size * sizeof(primer_pair));
} else {
if (retpair->storage_size == retpair->num_pairs) {
/* We need more space, so realloc double the space*/
retpair->storage_size *= 2;
// retpair->pairs
// = (primer_pair *)
// pr_safe_realloc(retpair->pairs,
// retpair->storage_size * sizeof(*retpair->pairs));
retpair->pairs
= (primer_pair *)
pr_safe_realloc(retpair->pairs,
retpair->storage_size * sizeof(primer_pair));
}
}
/* Copy the pair into the storage place */
retpair->pairs[retpair->num_pairs] = *pair;
retpair->num_pairs++;
}
/*
* Make lists of acceptable left and right primers. After return, the
* lists are stored in retval->fwd.oligo and retval->rev.oligo and the
* coresponding list sizes are stored in retval->fwd.num_elem and
* retval->rev.num_elem. Return 1 if one of lists is empty or if
* leftmost left primer and rightmost right primer do not provide
* sufficient product size.
*/
static int
make_detection_primer_lists(p3retval *retval,
const p3_global_settings *pa,
const seq_args_t* sa,
const dpal_arg_holder *dpal_arg_to_use,
const thal_arg_holder *thal_arg_to_use)
{
int left, right;
int length, start;
int i,n,/*k,*/ pr_min;
int tar_l, tar_r, f_b, r_b;
pair_stats *pair_expl = &retval->best_pairs.expl; /* To store the statistics for pairs */
/* Var to save the very left and very right primer */
left = right = 0;
/* Set pr_min to the very smallest
allowable product size. */
pr_min = INT_MAX;
for (i=0; i < pa->num_intervals; i++) {
if(pa->pr_min[i] < pr_min) {
pr_min = pa->pr_min[i];
}
}
/* Get the length of the sequence */
PR_ASSERT(INT_MAX > (n=(int)strlen(sa->trimmed_seq)));
tar_r = 0; /* Target start position */
tar_l = n; /* Target length */
/* Iterate over target array */
for (i=0; i < sa->tar2.count; i++) {
/* Select the rightmost target start */
if (sa->tar2.pairs[i][0] > tar_r) {
tar_r = sa->tar2.pairs[i][0];
}
/* Select the rightmost target end */
if (sa->tar2.pairs[i][0] + sa->tar2.pairs[i][1] - 1 < tar_l) {
tar_l = sa->tar2.pairs[i][0] + sa->tar2.pairs[i][1] - 1;
}
}
if (_PR_DEFAULT_POSITION_PENALTIES(pa)) {
if (0 == tar_r){ tar_r = n;}
if (tar_l == n) {tar_l = 0;}
} else {
tar_r = n;
tar_l = 0;
}
/* We use some global information to restrict the region
of the input sequence in which we generate candidate
oligos. */
if (retval->output_type == primer_list && pa->pick_left_primer == 1) {
f_b = n - 1;
} else if (tar_r - 1 < n - pr_min + pa->p_args.max_size - 1
&& !(pa->pick_anyway && sa->left_input)) {
f_b=tar_r - 1;
} else {
f_b = n - pr_min + pa->p_args.max_size-1;
}
if (pa->pick_left_primer) {
/* We will need a left primer. */
left=n; right=0;
length = f_b - pa->p_args.min_size + 1;
start = pa->p_args.min_size - 1;
/* Use the primer provided */
if (sa->left_input) {
add_one_primer(sa->left_input, &left, &retval->fwd,
pa, sa, dpal_arg_to_use, thal_arg_to_use, retval);
}
/* Pick primers at one position */
else if(sa->force_left_start > -1 ||
sa->force_left_end > -1) {
pick_primers_by_position(sa->force_left_start, sa->force_left_end,
&left, &retval->fwd, pa, sa,
dpal_arg_to_use, thal_arg_to_use, retval);
}
/* Or pick all good in the given range */
else {
pick_primer_range(start, length, &left, &retval->fwd,
pa, sa, dpal_arg_to_use, thal_arg_to_use, retval);
}
} /* if (pa->pick_left_primer) */
if (retval->output_type == primer_list && pa->pick_right_primer == 1) {
r_b = 0;
} else if (tar_l+1>pr_min - pa->p_args.max_size
&& !(pa->pick_anyway && sa->right_input)) {
r_b = tar_l+1;
} else {
r_b = pr_min - pa->p_args.max_size;
}
if ( pa->pick_right_primer ) {
/* We will need a right primer */
length = n-pa->p_args.min_size - r_b + 1;
start = r_b;
/* Use the primer provided */
if (sa->right_input) {
add_one_primer(sa->right_input, &right, &retval->rev,
pa, sa, dpal_arg_to_use, thal_arg_to_use, retval);
/* pick_right_primers(start, length, &right, &retval->rev,
pa, sa, dpal_arg_to_use, retval);*/
}
/* Pick primers at one position */
else if(sa->force_right_start > -1 ||
sa->force_right_end > -1) {
pick_primers_by_position(sa->force_right_start, sa->force_right_end,
&right, &retval->rev, pa, sa,
dpal_arg_to_use, thal_arg_to_use, retval);
}
/* Or pick all good in the given range */
else {
pick_primer_range(start, length, &right, &retval->rev,
pa, sa, dpal_arg_to_use, thal_arg_to_use, retval);
}
}
/*
* Return 1 if either the left primer list or the right primer
* list is empty or if leftmost left primer and
* rightmost right primer do not provide sufficient product size.
*/
if ((pa->pick_left_primer && 0 == retval->fwd.num_elem)
|| ((pa->pick_right_primer) && 0 == retval->rev.num_elem)) {
return 1;
} else if (!((sa->right_input)
&& (sa->left_input))
&& pa->pick_left_primer
&& pa->pick_right_primer
&& (right - left) < (pr_min - 1)) {
pair_expl->product = 1;
pair_expl->considered = 1;
return 1;
} else { return 0; }
} /* make_detection_primer_lists */
/*
* Make complete list of acceptable internal oligos in retval->intl.oligo.
* and place the number of valid elements in mid in retval->intl.num_elem. Return 1 if
* there are no acceptable internal oligos; otherwise return 0.
*/
static int
make_internal_oligo_list(p3retval *retval,
const p3_global_settings *pa,
const seq_args_t* sa,
const dpal_arg_holder *dpal_arg_to_use,
const thal_arg_holder *thal_arg_to_use)
{
int ret;
int left = 0;
/* Use the primer provided */
if ((sa->internal_input) || (pa->primer_task == check_primers)){
ret = add_one_primer(sa->internal_input, &left, &retval->intl,
pa, sa, dpal_arg_to_use, thal_arg_to_use, retval);
}
else {
/* Pick all good in the given range */
/* Use the settings to select a proper range */
int length = (int)strlen(sa->trimmed_seq) - pa->o_args.min_size;
int start = pa->o_args.min_size - 1;
int left = 0;
ret = pick_primer_range(start, length, &left, &retval->intl,
pa, sa, dpal_arg_to_use, thal_arg_to_use,
retval);
}
return ret;
} /* make_internal_oligo_list */
/*
* Make lists of acceptable left and right primers. After return, the
* lists are stored in retval->fwd.oligo and retval->rev.oligo and the
* coresponding list sizes are stored in retval->fwd.num_elem and
* retval->rev.num_elem. Return 1 if one of lists is empty or if
* leftmost left primer and rightmost right primer do not provide
* sufficient product size.
*/
static int
make_complete_primer_lists(p3retval *retval,
const p3_global_settings *pa,
const seq_args_t* sa,
const dpal_arg_holder *dpal_arg_to_use,
const thal_arg_holder *thal_arg_to_use,
const thal_arg_holder *thal_oligo_arg_to_use)
{
int extreme;
int length, start;
int n;
/* Get the length of the sequence */
PR_ASSERT(INT_MAX > (n=(int)strlen(sa->trimmed_seq)));
if (pa->pick_left_primer) {
/* We will need a left primer. */
extreme = 0;
length = n - pa->p_args.min_size;
start = pa->p_args.min_size - 1;
/* Pick all good in the given range */
pick_primer_range(start, length, &extreme, &retval->fwd,
pa, sa, dpal_arg_to_use, thal_arg_to_use, retval);
} /* if (pa->pick_left_primer) */
if ( pa->pick_right_primer ) {
/* We will need a right primer */
extreme = n;
length = n - pa->p_args.min_size + 1;
start = 0;
/* Pick all good in the given range */
pick_primer_range(start, length, &extreme, &retval->rev,
pa, sa, dpal_arg_to_use, thal_arg_to_use, retval);
}
if ( pa->pick_internal_oligo ) {
/* We will need a internal oligo */
length = n - pa->o_args.min_size;
start = pa->o_args.min_size - 1;
extreme = 0;
/* Pick all good in the given range */
pick_primer_range(start, length, &extreme, &retval->intl,
pa, sa, dpal_arg_to_use, thal_oligo_arg_to_use, retval);
}
return 0;
} /* make_complete_primer_lists */
/*
* Add caller-specified primers to retval->fwd, retval->rev, and/or
* retval->intl. The primers do not have to be "legal". It is possible
* to add more than one primer to retval->fwd, etc, if the input
* primer is found in multiple locations in the template. Similar to
* make_complete_primer_lists.
*/
static int
add_primers_to_check(p3retval *retval,
const p3_global_settings *pa,
const seq_args_t* sa,
const dpal_arg_holder *dpal_arg_to_use,
const thal_arg_holder *thal_arg_to_use,
const thal_arg_holder *thal_oligo_arg_to_use)
{
int extreme = 0; /* Required when calling add_one_primer
but not used in the current function. */
if (sa->left_input) {
add_one_primer(sa->left_input, &extreme, &retval->fwd,
pa, sa, dpal_arg_to_use, thal_arg_to_use, retval);
}
if (sa->right_input) {
add_one_primer(sa->right_input, &extreme, &retval->rev,
pa, sa, dpal_arg_to_use, thal_arg_to_use, retval);
}
if (sa->internal_input) {
add_one_primer(sa->internal_input, &extreme, &retval->intl,
pa, sa, dpal_arg_to_use, thal_oligo_arg_to_use, retval);
}
return 0;
} /* add_primers_to_check */
/*
* Make lists of acceptable left and right primers. After return, the
* lists are stored in retval->fwd.oligo and retval->rev.oligo and the
* coresponding list sizes are stored in retval->fwd.num_elem and
* retval->rev.num_elem. Return 1 if one of lists is empty or if
* leftmost left primer and rightmost right primer do not provide
* sufficient product size.
*/
static int
pick_sequencing_primer_list(p3retval *retval,
const p3_global_settings *pa,
const seq_args_t* sa,
const dpal_arg_holder *dpal_arg_to_use,
const thal_arg_holder *thal_arg_to_use)
{
int length, start;
int n, rest_accuracy;
int primer_nr; /* number of primers we need to pick */
int tar_n; /* counter for the targets */
int step_nr; /* counter to step through the targets */
int sequenced_len; /* bp sequenced in good quality */
int extra_seq; /* bp sequenced additionally on both sides */
/* best location for the 3' end of the fwd primer: */
int pr_position_f;
/* best location for the 3' end of the rev primer: */
int pr_position_r;
/* Get the length of the sequence */
PR_ASSERT(INT_MAX > (n=(int)strlen(sa->trimmed_seq)));
/* For each target needed loop*/
for (tar_n=0; tar_n < sa->tar2.count; tar_n++) {
/* Calculate the amount of primers needed */
primer_nr = 1;
if ((pa->pick_left_primer) && (pa->pick_right_primer)) {
sequenced_len = pa->sequencing.interval;
while(sequenced_len < sa->tar2.pairs[tar_n][1]) {
primer_nr++;
sequenced_len = pa->sequencing.spacing * (primer_nr - 1)
+ pa->sequencing.interval;
}
} else {
sequenced_len = pa->sequencing.spacing;
while(sequenced_len < sa->tar2.pairs[tar_n][1]) {
primer_nr++;
sequenced_len = pa->sequencing.spacing * primer_nr;
}
}
/* Calculate the overlap on the sides */
extra_seq = (sequenced_len - sa->tar2.pairs[tar_n][1]) / 2;
/* Pick primers for each position */
for ( step_nr = 0 ; step_nr < primer_nr ; step_nr++ ) {
pr_position_f = sa->tar2.pairs[tar_n][0] - extra_seq
+ ( pa->sequencing.spacing * step_nr )
- pa->sequencing.lead;
if ((pa->pick_left_primer) && (pa->pick_right_primer)) {
pr_position_r = sa->tar2.pairs[tar_n][0] - extra_seq
+ ( pa->sequencing.spacing * step_nr )
+ pa->sequencing.interval
+ pa->sequencing.lead;
} else {
pr_position_r = sa->tar2.pairs[tar_n][0] - extra_seq
+ ( pa->sequencing.spacing * (step_nr+1))
+ pa->sequencing.lead;
}
/* Check if calculated positions make sense */
/* position_f cannot be outside included region */
if (pr_position_f < (pa->p_args.min_size -1)) {
pr_position_f = pa->p_args.min_size - 1;
}
if (pr_position_f > (n - pa->p_args.min_size - 1)) {
pr_position_f = n - pa->p_args.min_size - 1;
/* Actually this should never happen */
pr_append_new_chunk(&retval->warnings,
"Calculation error in forward "
"sequencing position calculation");
}
/* position_r cannot be outside included region */
if (pr_position_r < (pa->p_args.min_size - 1)) {
pr_position_r = pa->p_args.min_size - 1;
/* Actually this should never happen */
pr_append_new_chunk(&retval->warnings,
"Calculation error in reverse "
"sequencing position calculation");
}
if (pr_position_r > (n - pa->p_args.min_size - 1)) {
pr_position_r = n - pa->p_args.min_size - 1;
}
/* Now all pr_positions are within the sequence */
if (pa->pick_left_primer) {
/* Set the start and length for the regions */
start = pr_position_f - pa->sequencing.accuracy;
if (start < 0) {
rest_accuracy = pr_position_f + 1;
start = 0;
} else {
rest_accuracy = pa->sequencing.accuracy;
}
length = rest_accuracy + pa->sequencing.accuracy ;
if ((start + length) > n) {
length = n - start;
}
/* Pick all good in the given range */
retval->fwd.expl.sequencing_location++;
pick_only_best_primer(start, length, &retval->fwd,
pa, sa, dpal_arg_to_use, thal_arg_to_use, retval);
}
if (pa->pick_right_primer) {
start = pr_position_r - pa->sequencing.accuracy;
if (start < 0) {
rest_accuracy = pr_position_r + 1;
start = 0;
} else {
rest_accuracy = pa->sequencing.accuracy;
}
length = rest_accuracy + pa->sequencing.accuracy ;
if ((start + length) > n) {
length = n - start;
}
/* Pick all good in the given range */
retval->rev.expl.sequencing_location++;
pick_only_best_primer(start, length, &retval->rev,
pa, sa, dpal_arg_to_use, thal_arg_to_use, retval);
}
}
} /* End of Target Loop */
retval->fwd.expl.ok = retval->fwd.num_elem;
retval->rev.expl.ok = retval->rev.num_elem;
/* Print an error if not all primers will be printed */
if (retval->fwd.num_elem > pa->num_return
|| retval->rev.num_elem > pa->num_return) {
pr_append_new_chunk( &retval->warnings,
"Increase PRIMER_NUM_RETURN to obtain all sequencing primers");
}
return 0;
} /* pick_sequencing_primer_list */
static void
add_oligo_to_oligo_array(oligo_array *oarray, primer_rec orec) {
/* Allocate some space for primers if needed */
if (NULL == oarray->oligo) {
oarray->storage_size = INITIAL_LIST_LEN;
// oarray->oligo
// = (primer_rec *)
// pr_safe_malloc(sizeof(*oarray->oligo) * oarray->storage_size);
oarray->oligo
= (primer_rec *)
pr_safe_malloc(sizeof(primer_rec) * oarray->storage_size);
}
/* If there is no space on the array, allocate new space */
if ((oarray->num_elem + 1) >= oarray->storage_size) { /* TO DO, is +1 really needed? */
oarray->storage_size += (oarray->storage_size >> 1);
// oarray->oligo
// = (primer_rec *)
// pr_safe_realloc(oarray->oligo,
// oarray->storage_size * sizeof(*oarray->oligo));
oarray->oligo
= (primer_rec *)
pr_safe_realloc(oarray->oligo,
oarray->storage_size * sizeof(primer_rec));
}
oarray->oligo[oarray->num_elem] = orec;
oarray->num_elem++;
}
/* pick_primer_range picks all primers which have their 3' end in the range
* from start to start+length and store only the best *oligo */
static int
pick_only_best_primer(const int start,
const int length,
oligo_array *oligo,
const p3_global_settings *pa,
const seq_args_t* sa,
const dpal_arg_holder *dpal_arg_to_use,
const thal_arg_holder *thal_arg_to_use,
p3retval *retval)
{
/* Variables for the loop */
int i, j, primer_size_small, primer_size_large;
int n, found_primer;
char number[20];
char *p_number = &number[0];
int temp_value;
/* Array to store one primer sequences in */
char oligo_seq[MAX_PRIMER_LENGTH+1];
/* Struct to store the primer parameters in */
primer_rec h;
primer_rec best;
memset(&h, 0, sizeof(primer_rec));
memset(&best, 0, sizeof(primer_rec));
best.quality = 1000.00;
found_primer = 0;
/* Set n to the length of included region */
PR_ASSERT(INT_MAX > (n=(int)strlen(sa->trimmed_seq)));
/* Conditions for primer length */
if (oligo->type == OT_INTL) {
primer_size_small=pa->o_args.min_size;
primer_size_large=pa->o_args.max_size;
}
else {
primer_size_small=pa->p_args.min_size;
primer_size_large=pa->p_args.max_size;
}
/* Loop over locations in the sequence */
for(i = start + length - 1; i >= start; i--) {
oligo_seq[0] = '\0';
/* Loop over possible primer lengths, from min to max */
for (j = primer_size_small; j <= primer_size_large; j++) {
/* Set the length of the primer */
h.length = j;
/* Set repeat_sim to NULL as indicator that the repeat_sim
struct is not initialized. */
h.repeat_sim.score = NULL;
/* Figure out positions for left primers and internal oligos */
if (oligo->type != OT_RIGHT) {
/* Break if the primer is bigger than the sequence left */
if( (i - j) < -1) continue;
/* Set the start of the primer */
h.start = i - j + 1;
/* Put the real primer sequence in oligo_seq */
_pr_substr(sa->trimmed_seq, h.start, j, oligo_seq);
} else {
/* Figure out positions for reverse primers */
/* Break if the primer is bigger than the sequence left*/
if(i+j > n) continue;
/* Set the start of the primer */
h.start = i+j-1;
/* Put the real primer sequence in s */
_pr_substr(sa->trimmed_seq, i, j, oligo_seq);
}
/* Do not force primer3 to use this oligo */
h.must_use = 0;
h.overlaps = 0;
/* Add it to the considered statistics */
oligo->expl.considered++;
/* Calculate all the primer parameters */
calc_and_check_oligo_features(pa, &h, oligo->type, dpal_arg_to_use, thal_arg_to_use,
sa, &oligo->expl, retval, oligo_seq);
/* If primer has to be used or is OK */
if (OK_OR_MUST_USE(&h)) {
/* Calculate the penalty */
h.quality = p_obj_fn(pa, &h, oligo->type);
/* Save the primer in the array */
if (h.quality < best.quality) {
/* Free memory used by previous best primer. */
free_primer_repeat_sim_score(&best);
best = h;
found_primer = 1;
} else {
/* Free memory used by this primer. */
free_primer_repeat_sim_score(&h);
}
} else {
/* Free memory used by this primer. */
free_primer_repeat_sim_score(&h);
if (any_5_prime_ol_extension_has_problem(&h)) {
/* Break from the inner for loop, because there is no
legal longer oligo with the same 3' sequence. */
break;
}
}
} /* j: Loop over possible primer length from min to max */
} /* i: Loop over the sequence */
if (found_primer == 1) {
/* Add the best to the array */
add_oligo_to_oligo_array(oligo, best);
/* Update statistics with how many primers are good */
oligo->expl.ok = oligo->expl.ok + 1;
} else {
if (oligo->type == OT_RIGHT) {
pr_append_new_chunk(&retval->warnings, "No right primer found in range ");
} else {
pr_append_new_chunk(&retval->warnings, "No left primer found in range ");
}
temp_value = start + pa->first_base_index;
sprintf(p_number, "%d", temp_value);
pr_append(&retval->warnings, p_number);
pr_append(&retval->warnings, " - ");
temp_value = start + length + pa->first_base_index;
sprintf(p_number, "%d", temp_value);
pr_append(&retval->warnings, p_number);
}
if (oligo->num_elem == 0) { return 1; }
else { return 0; }
} /* pick_only_best_primer */
/* pick_primer_range picks all legal primers in the range from start
to start+length and stores them in *oligo */
static int
pick_primer_range(const int start, const int length, int *extreme,
oligo_array *oligo, const p3_global_settings *pa,
const seq_args_t* sa,
const dpal_arg_holder *dpal_arg_to_use,
const thal_arg_holder *thal_arg_to_use,
p3retval *retval)
{
/* Variables for the loop */
int i, j;
int primer_size_small, primer_size_large;
int pr_min, n;
/* Array to store one primer sequences in */
char oligo_seq[MAX_PRIMER_LENGTH+1];
/* Struct to store the primer parameters in */
primer_rec h;
memset(&h, 0, sizeof(primer_rec));
/* Set pr_min to the very smallest
allowable product size. */
pr_min = INT_MAX;
for (i=0; i < pa->num_intervals; i++) {
if(pa->pr_min[i] < pr_min) {
pr_min = pa->pr_min[i];
}
}
/* Set n to the length of included region */
PR_ASSERT(INT_MAX > (n=(int)strlen(sa->trimmed_seq)));
if (oligo->type == OT_INTL) {
primer_size_small=pa->o_args.min_size;
primer_size_large=pa->o_args.max_size;
} else {
primer_size_small=pa->p_args.min_size;
primer_size_large=pa->p_args.max_size;
}
/* Loop over locations in the sequence */
for(i = start + length; i >= start; i--) {
oligo_seq[0] = '\0';
/* Loop over possible primer lengths, from min to max */
for (j = primer_size_small; j <= primer_size_large; j++) {
/* Set the length of the primer */
h.length = j;
/* Figure out positions for left primers and internal oligos */
if (oligo->type != OT_RIGHT) {
/* Check if the product is of sufficient size */
if (i-j > n-pr_min-1 && retval->output_type == primer_pairs
&& oligo->type == OT_LEFT) continue;
/* Break if the primer is bigger than the sequence left */
if ( (i - j) < -1) break;
/* Set the start of the primer */
h.start = i - j + 1;
/* Put the real primer sequence in oligo_seq */
_pr_substr(sa->trimmed_seq, h.start, j, oligo_seq);
} else {
/* Figure out positions for reverse primers */
/* Check if the product is of sufficient size */
if (i+j < pr_min && retval->output_type == primer_pairs) { continue; }
/* Break if the primer is bigger than the sequence left*/
if ( (i + j) > n) { break; }
/* Set the start of the primer */
h.start = i + j - 1;
/* Put the real primer sequence in s */
_pr_substr(sa->trimmed_seq, i, j, oligo_seq);
}
/* Do not force primer3 to use this oligo */
h.must_use = 0;
h.overlaps = 0;
/* Add it to the considered statistics */
oligo->expl.considered++;
/* Calculate all the primer parameters */
calc_and_check_oligo_features(pa, &h, oligo->type, dpal_arg_to_use, thal_arg_to_use,
sa, &oligo->expl, retval, oligo_seq);
/* If primer has to be used or is OK */
if (OK_OR_MUST_USE(&h)) {
/* Calculate the penalty */
h.quality = p_obj_fn(pa, &h, oligo->type);
/* Save the primer in the array */
add_oligo_to_oligo_array(oligo, h);
/* Update the most extreme primer variable */
if (( h.start < *extreme) && (oligo->type != OT_RIGHT))
*extreme = h.start;
/* Update the most extreme primer variable */
if ((h.start > *extreme) && (oligo->type == OT_RIGHT))
*extreme = h.start;
} else {
/* Free memory used by this primer. */
free_primer_repeat_sim_score(&h);
if (any_5_prime_ol_extension_has_problem(&h)) {
/* Break from the inner for loop, because there is no
legal longer oligo with the same 3' sequence. */
break;
}
}
} /* j: Loop over possible primer length from min to max */
} /* i: Loop over the sequence */
/* Update statistics with how many primers are good */
oligo->expl.ok = oligo->num_elem;
if (oligo->num_elem == 0) { return 1; }
else { return 0; }
} /* pick_primer_range */
/* add_one_primer finds one primer in the trimmed sequence and stores
* it in *oligo The main difference to the general fuction is that it
* calculates its length and it will add a primer of any length to the
* list */
static int
add_one_primer(const char *primer, int *extreme, oligo_array *oligo,
const p3_global_settings *pa,
const seq_args_t* sa,
const dpal_arg_holder *dpal_arg_to_use,
const thal_arg_holder *thal_arg_to_use,
p3retval *retval) {
/* Variables for the loop */
int i, j;
int n;
/* Array to store one primer sequences in */
char oligo_seq[MAX_PRIMER_LENGTH+1] , test_oligo[MAX_PRIMER_LENGTH+1];
/* Struct to store the primer parameters in */
primer_rec h;
memset(&h, 0, sizeof(primer_rec));
/* Copy *primer into test_oligo */
test_oligo[0] = '\0';
if (oligo->type != OT_RIGHT) {
strncat(test_oligo, primer, MAX_PRIMER_LENGTH);
} else {
p3_reverse_complement(primer, test_oligo);
}
PR_ASSERT(INT_MAX > (n=(int)strlen(sa->trimmed_seq)));
/* This time we already know the size of the primer */
j = (int)strlen(primer);
/* Loop over the whole sequence */
for(i = (int)strlen(sa->trimmed_seq); i >= 0; i--) {
oligo_seq[0] = '\0';
/* Set the length of the primer */
h.length = j;
/* Figure out positions for forward primers */
if (oligo->type != OT_RIGHT) {
/* Break if the primer is bigger than the sequence left*/
if( (i - j) < -1) continue;
/* Set the start of the primer */
h.start = i - j +1;
/* Put the real primer sequence in s */
_pr_substr(sa->trimmed_seq, h.start, j, oligo_seq);
}
/* Figure out positions for reverse primers */
else {
/* Break if the primer is bigger than the sequence left*/
if((i + j) > n) continue;
/* Set the start of the primer */
h.start = (i + j) - 1;
/* Put the real primer sequence in s */
_pr_substr(sa->trimmed_seq, i, j, oligo_seq);
}
/* Compare the primer with the sequence */
if (strcmp_nocase(test_oligo, oligo_seq)) {
continue;
}
/* Force primer3 to use this oligo */
h.must_use = (1 && pa->pick_anyway);
h.overlaps = 0;
/* Add it to the considered statistics */
oligo->expl.considered++;
/* Calculate all the primer parameters */
calc_and_check_oligo_features(pa, &h, oligo->type, dpal_arg_to_use, thal_arg_to_use,
sa, &oligo->expl, retval, oligo_seq);
/* If primer has to be used or is OK */
if (OK_OR_MUST_USE(&h)) {
/* Calculate the penalty */
h.quality = p_obj_fn(pa, &h, oligo->type);
/* Save the primer in the array */
add_oligo_to_oligo_array(oligo, h);
/* Update the most extreme primer variable */
if ((h.start < *extreme) && (oligo->type != OT_RIGHT)) {
*extreme = h.start;
}
/* Update the most extreme primer variable */
if ((h.start > *extreme) && (oligo->type == OT_RIGHT)) {
*extreme = h.start;
}
} else {
/* Free memory used by this primer. */
free_primer_repeat_sim_score(&h);
}
} /* i: Loop over the sequence */
/* Update array with how many primers are good */
/* Update statistics with how many primers are good */
oligo->expl.ok = oligo->num_elem;
if (oligo->num_elem == 0) { return 1; }
else {
if (oligo->num_elem > 1) {
pr_append_new_chunk(&retval->warnings,
"More than one position in template for input oligo ");
pr_append(&retval->warnings, primer);
}
return 0; /* Success */
}
}
/* add_one_primer finds one primer in the trimmed sequence and stores
* it in *oligo The main difference to the general fuction is that it
* calculates its length and it will add a primer of any length to the
* list */
static int
add_one_primer_by_position(int start, int length, int *extreme, oligo_array *oligo,
const p3_global_settings *pa,
const seq_args_t* sa,
const dpal_arg_holder *dpal_arg_to_use,
const thal_arg_holder *thal_arg_to_use,
p3retval *retval) {
/* Variables for the loop */
int i;
int n, found_primer;
/* Array to store one primer sequences in */
char oligo_seq[MAX_PRIMER_LENGTH+1];
/* Struct to store the primer parameters in */
primer_rec h;
memset(&h, 0, sizeof(primer_rec));
/* Retun 1 for no primer found */
found_primer = 1;
PR_ASSERT(INT_MAX > (n=(int)strlen(sa->trimmed_seq)));
/* Just to be sure */
if (start < 0) {
return 1;
}
if (start >= n) {
return 1;
}
if (oligo->type != OT_RIGHT) {
if ((start + length) > n) {
return 1;
}
} else {
if ((start - length + 1) < 0) {
return 1;
}
}
oligo_seq[0] = '\0';
/* Set the length of the primer */
h.length = length;
/* Figure out positions for forward primers */
if (oligo->type != OT_RIGHT) {
/* Set the start of the primer */
h.start = start;
/* Put the real primer sequence in s */
_pr_substr(sa->trimmed_seq, h.start, length, oligo_seq);
}
/* Figure out positions for reverse primers */
else {
i = start - length + 1;
/* Set the start of the primer */
h.start = start;
/* Put the real primer sequence in s */
_pr_substr(sa->trimmed_seq, i, length, oligo_seq);
}
/* Force primer3 to use this oligo */
h.must_use = (1 && pa->pick_anyway);
h.overlaps = 0;
/* Add it to the considered statistics */
oligo->expl.considered++;
/* Calculate all the primer parameters */
calc_and_check_oligo_features(pa, &h, oligo->type, dpal_arg_to_use, thal_arg_to_use,
sa, &oligo->expl, retval, oligo_seq);
/* If primer has to be used or is OK */
if (OK_OR_MUST_USE(&h)) {
/* Calculate the penalty */
h.quality = p_obj_fn(pa, &h, oligo->type);
/* Save the primer in the array */
add_oligo_to_oligo_array(oligo, h);
found_primer = 0;
/* Update the most extreme primer variable */
if (( h.start < *extreme) &&
(oligo->type != OT_RIGHT)) {
*extreme = h.start;
}
/* Update the most extreme primer variable */
if (( h.start > *extreme) &&
(oligo->type == OT_RIGHT)) {
*extreme = h.start;
}
/* Update the number of primers */
} else {
/* Free memory used by this primer. */
free_primer_repeat_sim_score(&h);
}
/* Update array with how many primers are good */
/* Update statistics with how many primers are good */
oligo->expl.ok = oligo->num_elem;
/* return 0 for success */
return found_primer;
}
static int
pick_primers_by_position(const int start, const int end, int *extreme,
oligo_array *oligo, const p3_global_settings *pa,
const seq_args_t* sa,
const dpal_arg_holder *dpal_arg_to_use,
const thal_arg_holder *thal_arg_to_use,
p3retval *retval)
{
int found_primer, length, j, ret, new_start;
found_primer = 1;
ret = 1;
if(start > -1 && end > -1) {
if (oligo->type != OT_RIGHT) {
length = end - start + 1;
} else {
length = start - end + 1;
}
found_primer = add_one_primer_by_position(start, length, extreme, oligo,
pa, sa, dpal_arg_to_use, thal_arg_to_use, retval);
return found_primer;
} else if (start > -1) {
/* Loop over possible primer lengths, from min to max */
ret = 0;
for (j = pa->p_args.min_size; j <= pa->p_args.max_size; j++) {
ret += add_one_primer_by_position(start, j, extreme, oligo,
pa, sa, dpal_arg_to_use, thal_arg_to_use, retval);
if (ret == 0) {
found_primer = 0;
}
}
return found_primer;
} else if (end > -1) {
/* Loop over possible primer lengths, from min to max */
ret = 0;
for (j = pa->p_args.min_size; j <= pa->p_args.max_size; j++) {
if (oligo->type != OT_RIGHT) {
new_start = end - j + 1;
} else {
new_start = end + j - 1;
}
ret += add_one_primer_by_position(new_start, j, extreme, oligo,
pa, sa, dpal_arg_to_use, thal_arg_to_use, retval);
if (ret == 0) {
found_primer = 0;
}
}
return found_primer;
} else {
/* Actually this should never happen */
pr_append_new_chunk(&retval->warnings,
"Calculation error in forced primer position calculation");
return 1;
}
}
/*
* Compute various characteristics of the oligo, and determine
* if it is acceptable.
*/
#define OUTSIDE_START_WT 30.0
#define INSIDE_START_WT 20.0
#define INSIDE_STOP_WT 100.0
#define OUTSIDE_STOP_WT 0.5
static void
calc_and_check_oligo_features(const p3_global_settings *pa,
primer_rec *h,
oligo_type otype,
const dpal_arg_holder *dpal_arg_to_use,
const thal_arg_holder *thal_arg_to_use,
const seq_args_t* sa,
oligo_stats *stats,
p3retval *retval,
/* This is 5'->3' on the template sequence: */
const char *input_oligo_seq
)
{
int i, j, k, for_i, gc_count, overhang_len;
tm_ret tm_calc; /* structure with Tm and bound (primer fraction) */
int three_prime_pos; /* position of 3' base of oligo */
oligo_type l = otype;
int must_use = h->must_use;
int three_conditions
= (must_use || pa->file_flag || retval->output_type == primer_list);
const thal_args *thal_args_for_template_mispriming
= use_end_for_th_template_mispriming
? thal_arg_to_use->end1
: thal_arg_to_use->any;
char s1_rev[MAX_PRIMER_LENGTH+1];
const char *oligo_seq;
const char *revc_oligo_seq;
char oligo_seq_overhang[THAL_MAX_ALIGN+1];
char revc_oligo_seq_overhang[THAL_MAX_ALIGN+1];
const char *p_oligo_seq_overhang;
const char *p_revc_oligo_seq_overhang;
const args_for_one_oligo_or_primer *po_args;
#if !defined(OS_WIN)
oligo_pair op = {0};
#endif
/* Initialize slots in h */
initialize_op(h);
h->overlaps = 0;
/* Set repeat_sim to NULL as indicator that the repeat_sim
struct is not initialized. */
h->repeat_sim.score = NULL;
/* Set all struct to NULL, will be calculated later */
h->self_any_struct = NULL;
h->self_end_struct = NULL;
h->hairpin_struct = NULL;
h->template_mispriming_struct = NULL;
h->template_mispriming_r_struct = NULL;
h->gc_content = h->num_ns = 0;
h->overlaps_overlap_position = 0;
h->template_mispriming = h->template_mispriming_r = ALIGN_SCORE_UNDEF;
h->template_mispriming_ok = 0;
PR_ASSERT(OT_LEFT == l || OT_RIGHT == l || OT_INTL == l);
p3_reverse_complement(input_oligo_seq, s1_rev);
if (OT_RIGHT == l) {
oligo_seq = s1_rev;
revc_oligo_seq = input_oligo_seq;
} else {
oligo_seq = input_oligo_seq;
revc_oligo_seq = s1_rev;
}
if (OT_INTL == l) {
po_args = &pa->o_args;
} else {
po_args = &pa->p_args;
}
/* Set j and k, and sanity check */
if (OT_LEFT == otype || OT_INTL == otype) {
j = h->start;
three_prime_pos = k = j+h->length-1;
} else {
three_prime_pos = j = h->start-h->length+1;
k = h->start;
}
PR_ASSERT(k >= 0);
PR_ASSERT(k < TRIMMED_SEQ_LEN(sa));
if ((otype == OT_LEFT) && !PR_START_CODON_POS_IS_NULL(sa)
/* Make sure the primer would amplify at least part of
the ORF. */
&& (0 != (h->start - sa->start_codon_pos) % 3
|| (h->start <= retval->upstream_stop_codon)
|| ((retval->stop_codon_pos != -1)
&& (h->start >= retval->stop_codon_pos)))) {
stats->no_orf++;
op_set_does_not_amplify_orf(h);
if (!pa->pick_anyway) { return; }
}
/* edited by T. Koressaar and M. Lepamets for lowercase masking */
if(pa->lowercase_masking == 1) {
char *sequence_check = sa->trimmed_orig_seq;
if (pa->mask_template == 1) {
if (l == OT_LEFT) sequence_check = sa->trimmed_masked_seq;
else if (l == OT_RIGHT) sequence_check = sa->trimmed_masked_seq_r;
}
if (is_lowercase_masked(
three_prime_pos,
sequence_check,
h,
stats)
) {
if (!must_use) { return; }
}
} else if((pa->lowercase_masking == 0) && (pa->mask_template == 1)) {
pr_append_new_chunk(
&retval->warnings,
"Use PRIMER_LOWERCASE_MASKING=1 when using PRIMER_MASK_TEMPLATE=1."
);
return;
}
/* end T. Koressar's changes */
/* edited by A. Untergasser for forcing sequence use */
if ((po_args->must_match_five_prime != NULL) ||
(po_args->must_match_three_prime != NULL)) {
if (primer_must_match(pa, h, stats, oligo_seq,
po_args->must_match_three_prime,
po_args->must_match_five_prime)) {
if (!must_use) {
op_set_must_match_err(h);
return;
}
}
}
/* end A. Untergasser's changes */
gc_and_n_content(j, k-j+1, sa->trimmed_seq, h);
if (h->num_ns > po_args->num_ns_accepted) {
op_set_too_many_ns(h);
stats->ns++;
if (!must_use) { return; }
}
/* Upstream error checking has ensured that we use non-default position
penalties only when there is 0 or 1 target. */
PR_ASSERT(sa->tar2.count <= 1 || _PR_DEFAULT_POSITION_PENALTIES(pa));
if (pa->primer_task == pick_sequencing_primers) {
h->position_penalty = 0.0;
} else if (l != OT_INTL
&& _PR_DEFAULT_POSITION_PENALTIES(pa)
&& oligo_overlaps_interval(j, k-j+1, sa->tar2.pairs, sa->tar2.count)) {
h->position_penalty = 0.0;
bf_set_infinite_pos_penalty(h,1);
bf_set_overlaps_target(h,1);
} else if (l != OT_INTL && !_PR_DEFAULT_POSITION_PENALTIES(pa)
&& 1 == sa->tar2.count) {
compute_position_penalty(pa, sa, h, l);
if (bf_get_infinite_pos_penalty(h)) {
bf_set_overlaps_target(h,1);
}
} else {
h->position_penalty = 0.0;
bf_set_infinite_pos_penalty(h,0);
}
if (!PR_START_CODON_POS_IS_NULL(sa)) {
if (OT_LEFT == l) {
if (sa->start_codon_pos > h->start)
h->position_penalty
= (sa->start_codon_pos - h->start) * OUTSIDE_START_WT;
else
h->position_penalty
= (h->start - sa->start_codon_pos) * INSIDE_START_WT;
} else if (OT_RIGHT == l) {
if (-1 == retval->stop_codon_pos) {
h->position_penalty = (TRIMMED_SEQ_LEN(sa) - h->start - 1) * INSIDE_STOP_WT;
} else if (retval->stop_codon_pos < h->start) {
h->position_penalty
= (h->start - retval->stop_codon_pos) * OUTSIDE_STOP_WT;
} else {
h->position_penalty
= (retval->stop_codon_pos - h->start) * INSIDE_STOP_WT;
}
}
}
/* TO DO Simplify logic here */
if (l != OT_INTL
&& oligo_overlaps_interval(j, k-j+1, sa->excl2.pairs, sa->excl2.count)) {
bf_set_overlaps_excl_region(h,1);
}
if (l == OT_INTL
&& oligo_overlaps_interval(j, k-j+1, sa->excl_internal2.pairs,
sa->excl_internal2.count)) {
bf_set_overlaps_excl_region(h,1);
}
if(l != OT_INTL && bf_get_overlaps_target(h)) {
op_set_overlaps_target(h);
stats->target++;
if (!must_use) { return; }
}
if(bf_get_overlaps_excl_region(h)){
op_set_overlaps_excluded_region(h);
stats->excluded++;
if (!must_use) { return; }
}
/* Check if the oligo is included in any ok region */
if ((l == OT_LEFT) && (sa->ok_regions.count > 0) && (!sa->ok_regions.any_left)) {
int included = 0;
for (i=0; i < sa->ok_regions.count; i++) {
if ((j >= sa->ok_regions.left_pairs[i][0]) &&
(k <= sa->ok_regions.left_pairs[i][0] + sa->ok_regions.left_pairs[i][1] - 1)) {
included = 1;
break;
}
}
if (!included) {
op_set_not_in_any_ok_region(h);
stats->not_in_any_left_ok_region++;
if (!must_use) return;
}
}
if ((l == OT_RIGHT) && (sa->ok_regions.count > 0) && (!sa->ok_regions.any_right)) {
int included = 0;
for (i=0; i < sa->ok_regions.count; i++) {
if ((j >= sa->ok_regions.right_pairs[i][0]) &&
(k <= sa->ok_regions.right_pairs[i][0] + sa->ok_regions.right_pairs[i][1] - 1)) {
included = 1;
break;
}
}
if (!included) {
op_set_not_in_any_ok_region(h);
stats->not_in_any_right_ok_region++;
if (!must_use) return;
}
}
if (h->gc_content < po_args->min_gc) {
op_set_low_gc_content(h);
stats->gc++;
if (!must_use) return;
} else if (h->gc_content > po_args->max_gc) {
op_set_high_gc_content(h);
stats->gc++;
if (!must_use) return;
}
if (OT_LEFT == l || OT_RIGHT == l) {
/* gc_clamp is applicable only to primers (as opposed
to primers and hybridzations oligos. */
for (i = 0; i < pa->gc_clamp; i++) {
/* We want to look at the 3' end of the oligo being
assessed, so we look in the 5' end of its reverse-complement */
if (revc_oligo_seq[i] != 'G' && revc_oligo_seq[i] != 'C') {
op_set_no_gc_glamp(h);
stats->gc_clamp++;
if (!must_use) return; else break;
}
}
}
#if 0
/* Old code, works */
if(pa->gc_clamp != 0){
if(OT_LEFT == l) {
for(i=k-pa->gc_clamp+1; i<= k; i++)if(seq[i] !='G'&&seq[i] !='C'){
op_set_no_gc_glamp(h);
stats->gc_clamp++;
if (!must_use) return; else break;
}
}
if(OT_RIGHT == l){
for(i=j; igc_clamp; i++)if(seq[i] != 'G' && seq[i] != 'C'){
op_set_no_gc_glamp(h);
stats->gc_clamp++;
if (!must_use) return; else break;
}
}
}
#endif
if (pa->max_end_gc < 5
&& (OT_LEFT == l || OT_RIGHT == l)) {
/* The CGs are only counted in the END of primers (as opposed
to primers and hybridzations oligos. */
gc_count=0;
for (i = 0; i < 5; i++) {
/* We want to look at the 3' end of the oligo being
assessed, so we look in the 5' end of its reverse-complement */
if (revc_oligo_seq[i] == 'G' || revc_oligo_seq[i] == 'C') {
gc_count++;
}
}
if (gc_count > pa->max_end_gc) {
op_set_too_many_gc_at_end(h);
stats->gc_end_high++;
if (!must_use) return;
}
}
/* Tentative interface for generic oligo testing
function */
if (
(!sequence_quality_is_ok(pa, h, l, sa, j, k,
stats, po_args))
&& (!must_use)
) {
return;
}
if(_pr_violates_poly_x(oligo_seq, po_args->max_poly_x)) {
op_set_high_poly_x(h);
stats->poly_x++;
if (!must_use) { return; }
}
/* Oligo/primer melting temperature */
tm_calc = seqtm(
oligo_seq,
po_args->dna_conc,
po_args->salt_conc,
po_args->divalent_conc,
po_args->dntp_conc,
po_args->dmso_conc,
po_args->dmso_fact,
po_args->formamide_conc,
MAX_NN_TM_LENGTH,
pa->tm_santalucia,
pa->salt_corrections,
pa->annealing_temp
);
h->temp = tm_calc.Tm;
h->bound = tm_calc.bound;
if (h->temp < po_args->min_tm) {
op_set_low_tm(h);
stats->temp_min++;
if (!must_use) return;
}
if (h->temp > po_args->max_tm) {
op_set_high_tm(h);
stats->temp_max++;
if (!must_use) return;
}
if (pa->annealing_temp > 0.0) {
if (h->bound < po_args->min_bound) {
op_set_low_bound(h);
stats->bound_min++;
if (!must_use) { return; }
}
if (h->bound > po_args->max_bound) {
op_set_high_bound(h);
stats->bound_max++;
if (!must_use) { return; }
}
}
/* End stability is applicable only to primers
(not to oligos) */
if (OT_LEFT == l || OT_RIGHT == l) {
if ((h->end_stability = end_oligodg(oligo_seq, 5,
pa->tm_santalucia))
> pa->max_end_stability) {
/* Must not be called on a hybridization probe / internal oligo: */
op_set_high_end_stability(h);
stats->stability++;
if (!must_use) return;
}
}
p_oligo_seq_overhang = oligo_seq;
p_revc_oligo_seq_overhang = revc_oligo_seq;
if (OT_LEFT == l) {
if (NULL != sa->overhang_left) {
overhang_len = strlen(sa->overhang_left);
strcpy(oligo_seq_overhang, sa->overhang_left);
strcpy(oligo_seq_overhang + overhang_len, oligo_seq);
p3_reverse_complement(oligo_seq_overhang, revc_oligo_seq_overhang);
p_oligo_seq_overhang = oligo_seq_overhang;
p_revc_oligo_seq_overhang = revc_oligo_seq_overhang;
}
}
if (OT_RIGHT == l) {
if (NULL != sa->overhang_right) {
overhang_len = strlen(sa->overhang_right);
strcpy(oligo_seq_overhang, sa->overhang_right);
strcpy(oligo_seq_overhang + overhang_len, oligo_seq);
p3_reverse_complement(oligo_seq_overhang, revc_oligo_seq_overhang);
p_oligo_seq_overhang = oligo_seq_overhang;
p_revc_oligo_seq_overhang = revc_oligo_seq_overhang;
}
}
if ((must_use
|| pa->file_flag
|| retval->output_type == primer_list
|| po_args->weights.compl_any
|| po_args->weights.compl_end)
&& pa->thermodynamic_oligo_alignment==0) {
oligo_compl(h, po_args,
stats, dpal_arg_to_use,
p_oligo_seq_overhang, p_revc_oligo_seq_overhang);
/* oligo_seq, revc_oligo_seq); */
if ((!(p3_ol_is_uninitialized(h))) && !must_use) {
PR_ASSERT(!p3_ol_is_ok(h));
return;
}
} else {
/* Thermodynamical approach: for primers only */
if ((must_use
|| pa->file_flag
|| (retval->output_type == primer_list)
|| po_args->weights.compl_any_th
|| po_args->weights.compl_end_th)
&& (pa->thermodynamic_oligo_alignment == 1)
) {
oligo_compl_thermod(h, po_args,
stats, thal_arg_to_use,
p_oligo_seq_overhang, p_oligo_seq_overhang);
/* oligo_seq, oligo_seq); */
/* input_oligo_seq, input_oligo_seq);*/
/* oligo_seq, revc_oligo_seq); */
if ((!(p3_ol_is_uninitialized(h))) && !must_use) {
PR_ASSERT(!p3_ol_is_ok(h));
return;
}
} else {
h->self_any = h->self_end = ALIGN_SCORE_UNDEF;
}
}
if ((three_conditions
|| po_args->weights.hairpin_th
#if 0
|| po_args->weights.compl_any_th /* Triinu, is this needed? */
|| po_args->weights.compl_end_th /* Triinu, is this needed? */
#endif
)
&& (pa->thermodynamic_oligo_alignment == 1)
) {
oligo_hairpin(h, po_args,
stats, thal_arg_to_use,
p_oligo_seq_overhang);
/* oligo_seq); */
/* input_oligo_seq);*/
if ((!(p3_ol_is_uninitialized(h))) && !must_use) {
PR_ASSERT(!p3_ol_is_ok(h));
return;
}
} else {
/* This will get calculated later if necessary, in characterize_pair. */
h->hairpin_th = ALIGN_SCORE_UNDEF;
}
/* end of thermod. approach */
#if 0
/* FIX ME FIXME */
if (((must_use
|| pa->file_flag
|| retval->output_type == primer_list
|| po_args->weights.repeat_sim
|| ((OT_RIGHT == l || OT_LEFT == l)
&& pa->p_args.weights.template_mispriming))
&& pa->thermodynamic_oligo_alignment==0)
|| (pa->thermodynamic_oligo_alignment==1 && po_args->weights.repeat_sim)) {
oligo_repeat_library_mispriming(h, pa, sa, l, stats,
dpal_arg_to_use, &retval->glob_err);
if (pa->thermodynamic_template_alignment==0 && OK_OR_MUST_USE(h)) {
oligo_template_mispriming(h, pa, sa, l, stats,
dpal_arg_to_use->local_end,
thal_args_for_template_mispriming);
}
}
if ((must_use
|| pa->file_flag
|| retval->output_type == primer_list
|| ((OT_RIGHT == l || OT_LEFT == l)
&& pa->p_args.weights.template_mispriming_th))
&& pa->thermodynamic_template_alignment==1)
{
oligo_template_mispriming(h, pa, sa, l, stats,
dpal_arg_to_use->local_end,
thal_args_for_template_mispriming);
}
/* END FIX ME FIXME */
#else
if (three_conditions || po_args->weights.repeat_sim) {
oligo_repeat_library_mispriming(h, pa, sa, l, stats,
dpal_arg_to_use, &retval->glob_err);
}
if (!OK_OR_MUST_USE(h)) { return; }
if (three_conditions
||
( /* Do we need template mispriming for the penalty function? */
(OT_RIGHT == l || OT_LEFT == l)
&&
(
(pa->p_args.weights.template_mispriming && !pa->thermodynamic_template_alignment)
||
(pa->p_args.weights.template_mispriming_th && pa->thermodynamic_template_alignment)
)
)
) {
if (OK_OR_MUST_USE(h)) {
oligo_template_mispriming(h, pa, sa, l, stats,
dpal_arg_to_use->local_end,
thal_args_for_template_mispriming);
}
}
#endif
if (h->length > po_args->max_size ) {
op_set_too_long(h);
stats->size_max++;
if (!must_use) { return; }
}
if (h->length < po_args->min_size ) {
op_set_too_short(h);
stats->size_min++;
if (!must_use) { return; }
}
for (for_i=0; for_i < sa->primer_overlap_junctions_count; for_i++) {
if (OT_LEFT == l
&& ((h->start + pa->p_args.min_5_prime_overlap_of_junction - 1)
<= sa->primer_overlap_junctions[for_i])
&& ((h->start + h->length - pa->p_args.min_3_prime_overlap_of_junction))
> sa->primer_overlap_junctions[for_i]) {
h->overlaps_overlap_position = 1;
/* no need to continue checking for more overlaps */
break;
}
if (OT_RIGHT == l
&& ((h->start - h->length + pa->p_args.min_3_prime_overlap_of_junction)
<= sa->primer_overlap_junctions[for_i])
&& ((h->start - pa->p_args.min_5_prime_overlap_of_junction + 1))
> sa->primer_overlap_junctions[for_i]) {
h->overlaps_overlap_position = 1;
/* no need to continue checking for more overlaps */
break;
}
}
if ((OT_INTL == l) && (sa->intl_overlap_junctions_count > 0)) {
for (for_i=0; for_i < sa->intl_overlap_junctions_count; for_i++) {
if (((h->start + pa->o_args.min_5_prime_overlap_of_junction - 1)
<= sa->intl_overlap_junctions[for_i])
&& ((h->start + h->length - pa->o_args.min_3_prime_overlap_of_junction))
> sa->intl_overlap_junctions[for_i]) {
h->overlaps_overlap_position = 1;
/* no need to continue checking for more overlaps */
break;
}
}
if ((!h->overlaps_overlap_position) && (!must_use)) {
stats->does_not_overlap_a_required_point ++;
op_set_must_match_err(h);
return;
}
}
/* Calculate failure rate */
/* Added by M. Lepamets */
h->failure_rate = 0.0;
#if !defined(OS_WIN)
if (pa->mask_template && h->length >= pa->mp.window_size) {
op.fwd = string_to_word (oligo_seq, h->length, pa->mp.window_size);
op.rev = op.fwd; /* not used in this calculation */
calculate_scores (&op, &pa->mp, pa->mp.window_size);
h->failure_rate = op.score_fwd;
}
#endif
/* FIX ME FIXME Steve, is this really needed? */
op_set_completely_written(h);
} /* calc_and_check_oligo_features */
#undef OUTSIDE_START_WT
#undef INSIDE_START_WT
#undef INSIDE_STOP_WT
#undef OUTSIDE_STOP_WT
/* Calculate the minimum sequence quality and the minimum sequence
quality of the 3' end of a primer or oligo. Set h->seq_quality
and h->seq_end_quality with these values. Return 1 (== ok)
if sa->quality is undefined. Otherwise, return 1 (ok)
if h->seq_quality and h->seq_end_quality are within
range, or else return 0.
*/
static int
sequence_quality_is_ok(const p3_global_settings *pa,
primer_rec *h,
oligo_type l,
const seq_args_t* sa,
int j, int k,
oligo_stats *global_oligo_stats,
const args_for_one_oligo_or_primer *po_args) {
int i, min_q, min_q_end, m, q;
int retval = 1;
if (NULL == sa->quality) {
h->seq_end_quality = h->seq_quality = pa->quality_range_max;
return 1;
}
q = pa->quality_range_max;
min_q = po_args->min_quality;
if (OT_LEFT == l || OT_RIGHT == l) {
min_q_end = po_args->min_end_quality;
} else {
min_q_end = min_q;
}
if (OT_LEFT == l || OT_INTL == l) {
for(i = k - 4; i <= k; i++) {
if(i < j) { continue; }
m = sa->quality[i + sa->incl_s];
if (m < q) { q = m; }
}
min_q_end = q;
for(i = j; i <= k - 5; i++) {
m = sa->quality[i + sa->incl_s];
if (m < q) { q = m; }
}
min_q = q;
} else if (OT_RIGHT == l) {
for(i = j; i < j + 5; i++) {
if (i > k) { break; }
m = sa->quality[i + sa->incl_s];
if (m < q) { q = m; }
}
min_q_end = q;
for(i = j + 5; i <= k; i++) {
m = sa->quality[i + sa->incl_s];
if (m < q) { q = m; }
}
min_q = q;
} else {
PR_ASSERT(0); /* Programming error. */
}
h->seq_quality = min_q;
h->seq_end_quality = min_q_end;
if (h->seq_quality < po_args->min_quality) {
op_set_low_sequence_quality(h);
global_oligo_stats->seq_quality++;
retval = 0;
return retval;
}
if (OT_LEFT == l || OT_RIGHT == l) {
if (h->seq_end_quality < po_args->min_end_quality) {
op_set_low_end_sequence_quality(h);
global_oligo_stats->seq_quality++;
retval = 0;
}
}
return retval;
}
/*
* Set h->gc_content to the GC % of the 'len' bases starting at 'start' in
* 'sequence' (excluding 'N's). Set h->num_ns to the number of 'N's in that
* subsequence.
*/
static void
gc_and_n_content(int start, int len,
const char *sequence,
primer_rec *h)
{
const char* p = &sequence[start];
const char* stop = p + len;
int num_gc = 0, num_gcat = 0, num_n = 0;
while (p < stop) {
if ('N' == *p) {
num_n++;
} else {
num_gcat++;
if ('C' == *p || 'G' == *p) { num_gc++; }
}
p++;
}
h->num_ns = num_n;
if (0 == num_gcat) { h->gc_content = 0.0; }
else { h->gc_content = 100.0 * ((double)num_gc)/num_gcat; }
}
static int
oligo_overlaps_interval(int start,
int len,
const interval_array_t intervals,
int num_intervals)
{
int i;
int last = start + len - 1;
for (i = 0; i < num_intervals; i++) {
if (!(last < intervals[i][0]
|| start > (intervals[i][0] + intervals[i][1] - 1))) {
return 1;
}
}
return 0;
}
/* Calculate the part of the objective function due to one primer. */
static double
p_obj_fn(const p3_global_settings *pa,
primer_rec *h,
int j) {
double sum;
sum = 0;
if (j == OT_LEFT || j == OT_RIGHT) {
if(pa->p_args.weights.temp_gt && h->temp > pa->p_args.opt_tm) {
sum += pa->p_args.weights.temp_gt * (h->temp - pa->p_args.opt_tm);
}
if (pa->p_args.weights.temp_lt && h->temp < pa->p_args.opt_tm) {
sum += pa->p_args.weights.temp_lt * (pa->p_args.opt_tm - h->temp);
}
if (pa->annealing_temp > 0.0) {
if(pa->p_args.weights.bound_gt && h->bound > pa->p_args.opt_bound)
sum += pa->p_args.weights.bound_gt * (h->bound - pa->p_args.opt_bound);
if (pa->p_args.weights.bound_lt && h->bound < pa->p_args.opt_bound)
sum += pa->p_args.weights.bound_lt * (pa->p_args.opt_bound - h->bound);
}
if (pa->p_args.weights.gc_content_gt && h->gc_content > pa->p_args.opt_gc_content) {
sum += pa->p_args.weights.gc_content_gt
* (h->gc_content - pa->p_args.opt_gc_content);
}
if (pa->p_args.weights.gc_content_lt && h->gc_content < pa->p_args.opt_gc_content) {
sum += pa->p_args.weights.gc_content_lt
* (pa->p_args.opt_gc_content - h->gc_content);
}
if (pa->p_args.weights.length_lt && h->length < pa->p_args.opt_size) {
sum += pa->p_args.weights.length_lt * (pa->p_args.opt_size - h->length);
}
if (pa->p_args.weights.length_gt && h->length > pa->p_args.opt_size) {
sum += pa->p_args.weights.length_gt * (h->length - pa->p_args.opt_size);
}
/* edited by M. Lepamets */
if (pa->p_args.weights.failure_rate) {
sum += pa->p_args.weights.failure_rate * h->failure_rate;
}
/* BEGIN: secondary structures */
if (pa->thermodynamic_oligo_alignment==0) {
if (pa->p_args.weights.compl_any) {
sum += pa->p_args.weights.compl_any * h->self_any;
}
if (pa->p_args.weights.compl_end) {
sum += pa->p_args.weights.compl_end * h->self_end;
}
} else if (pa->thermodynamic_oligo_alignment==1) {
if (pa->p_args.weights.compl_any_th) {
if ((h->temp - pa->p_args.weights.temp_cutoff) <= h->self_any) {
sum += pa->p_args.weights.compl_any_th
* (h->self_any - (h->temp - pa->p_args.weights.temp_cutoff - 1.0)); /* -1.0 is added for the case where == */
} else {
sum += pa->p_args.weights.compl_any_th
* (1/(h->temp - pa->p_args.weights.temp_cutoff + 1.0 - h->self_any));
}
}
if (pa->p_args.weights.compl_end_th) {
if ((h->temp - pa->p_args.weights.temp_cutoff) <= h->self_end) {
sum += pa->p_args.weights.compl_end_th
* (h->self_end - (h->temp - pa->p_args.weights.temp_cutoff - 1.0));
} else {
sum += pa->p_args.weights.compl_end_th
* (1/(h->temp - pa->p_args.weights.temp_cutoff + 1.0 - h->self_end));
}
}
if (pa->p_args.weights.hairpin_th) {
if ((h->temp - pa->p_args.weights.temp_cutoff) <= h->hairpin_th) {
sum += pa->p_args.weights.hairpin_th
* (h->hairpin_th - (h->temp - pa->p_args.weights.temp_cutoff - 1.0));
} else {
sum += pa->p_args.weights.hairpin_th
* (1/(h->temp - pa->p_args.weights.temp_cutoff + 1.0 - h->hairpin_th));
}
}
} else {
PR_ASSERT(0)
/* Programming error,
illegal value for pa->thermodynamic_oligo_alignment */
}
/* END: secondary structures */
if (pa->p_args.weights.num_ns) {
sum += pa->p_args.weights.num_ns * h->num_ns;
}
if(pa->p_args.weights.repeat_sim) {
sum += pa->p_args.weights.repeat_sim
* h->repeat_sim.score[h->repeat_sim.max];
}
if (!bf_get_overlaps_target(h)) {
/* We might be evaluating p_obj_fn with h->target if
the client supplied 'pick_anyway' and specified
a primer or oligo. */
PR_ASSERT(!(bf_get_infinite_pos_penalty(h)));
if(pa->p_args.weights.pos_penalty) {
sum += pa->p_args.weights.pos_penalty * h->position_penalty;
}
}
if(pa->p_args.weights.end_stability) {
sum += pa->p_args.weights.end_stability * h->end_stability;
}
/* FIX ME QUALITY WT Change here */
if(pa->p_args.weights.seq_quality) {
sum += pa->p_args.weights.seq_quality *
(pa->quality_range_max - h->seq_quality); /* Look for end seq quality */
}
if (pa->p_args.weights.template_mispriming && pa->thermodynamic_template_alignment==0) {
PR_ASSERT(oligo_max_template_mispriming(h) != ALIGN_SCORE_UNDEF);
sum += pa->p_args.weights.template_mispriming *
oligo_max_template_mispriming(h);
}
if (pa->p_args.weights.template_mispriming_th && pa->thermodynamic_template_alignment==1) {
PR_ASSERT(oligo_max_template_mispriming_thermod(h) != ALIGN_SCORE_UNDEF);
if ((h->temp - pa->p_args.weights.temp_cutoff) <= oligo_max_template_mispriming_thermod(h)) {
sum += pa->p_args.weights.template_mispriming_th *
(oligo_max_template_mispriming_thermod(h) - (h->temp - pa->p_args.weights.temp_cutoff - 1.0));
}
if((h->temp - pa->p_args.weights.temp_cutoff) > oligo_max_template_mispriming_thermod(h)) {
sum += pa->p_args.weights.template_mispriming_th *
(1/(h->temp - pa->p_args.weights.temp_cutoff + 1.0 - oligo_max_template_mispriming_thermod(h)));
}
}
return sum;
} else if (j == OT_INTL) {
if(pa->o_args.weights.temp_gt && h->temp > pa->o_args.opt_tm) {
sum += pa->o_args.weights.temp_gt * (h->temp - pa->o_args.opt_tm);
}
if(pa->o_args.weights.temp_lt && h->temp < pa->o_args.opt_tm) {
sum += pa->o_args.weights.temp_lt * (pa->o_args.opt_tm - h->temp);
}
if(pa->o_args.weights.bound_gt && h->bound > pa->o_args.opt_bound) {
sum += pa->o_args.weights.bound_gt * (h->bound - pa->o_args.opt_bound);
}
if(pa->o_args.weights.bound_lt && h->bound < pa->o_args.opt_bound) {
sum += pa->o_args.weights.bound_lt * (pa->o_args.opt_bound - h->bound);
}
if(pa->o_args.weights.gc_content_gt && h->gc_content > pa->o_args.opt_gc_content) {
sum += pa->o_args.weights.gc_content_gt
* (h->gc_content - pa->o_args.opt_gc_content);
}
if(pa->o_args.weights.gc_content_lt && h->gc_content < pa->o_args.opt_gc_content) {
sum += pa->o_args.weights.gc_content_lt
* (pa->o_args.opt_gc_content - h->gc_content);
}
if(pa->o_args.weights.length_lt && h->length < pa->o_args.opt_size) {
sum += pa->o_args.weights.length_lt * (pa->o_args.opt_size - h->length);
}
if(pa->o_args.weights.length_gt && h->length > pa->o_args.opt_size) {
sum += pa->o_args.weights.length_gt * (h->length - pa->o_args.opt_size);
}
if(pa->o_args.weights.compl_any && pa->thermodynamic_oligo_alignment==0) {
sum += pa->o_args.weights.compl_any * h->self_any;
}
if(pa->o_args.weights.compl_end && pa->thermodynamic_oligo_alignment==0) {
sum += pa->o_args.weights.compl_end * h->self_end;
}
/* begin thermodynamical approach */
if (pa->thermodynamic_oligo_alignment==1) {
if (pa->o_args.weights.compl_any_th) {
if ((h->temp - pa->o_args.weights.temp_cutoff) <= h->self_any) {
sum +=
pa->o_args.weights.compl_any_th
* (h->self_any - (h->temp - pa->o_args.weights.temp_cutoff - 1.0)); /* -1.0 is added for the case where == */
} else {
sum +=
pa->o_args.weights.compl_any_th
* (1/(h->temp - pa->o_args.weights.temp_cutoff + 1.0 - h->self_any));
}
}
if (pa->o_args.weights.compl_end_th) {
if ((h->temp - pa->o_args.weights.temp_cutoff) <= h->self_end) {
sum +=
pa->o_args.weights.compl_end_th
* (h->self_end - (h->temp - pa->o_args.weights.temp_cutoff - 1.0));
} else {
sum +=
pa->o_args.weights.compl_end_th
* (1/(h->temp - pa->o_args.weights.temp_cutoff + 1.0 - h->self_end));
}
}
if (pa->o_args.weights.hairpin_th) {
if ((h->temp - pa->o_args.weights.temp_cutoff) <= h->hairpin_th) {
sum += pa->o_args.weights.hairpin_th * (h->hairpin_th - (h->temp - pa->o_args.weights.temp_cutoff - 1.0));
} else {
sum += pa->o_args.weights.hairpin_th * (1/(h->temp - pa->o_args.weights.temp_cutoff + 1.0 - h->hairpin_th));
}
}
}
/* end thermodynamical approach */
if(pa->o_args.weights.num_ns) {
sum += pa->o_args.weights.num_ns * h->num_ns;
}
if(pa->o_args.weights.repeat_sim) {
sum += pa->o_args.weights.repeat_sim
* h->repeat_sim.score[h->repeat_sim.max];
}
/* FIX ME QUALITY WT */
if(pa->o_args.weights.seq_quality) {
sum += pa->o_args.weights.seq_quality *
(pa->quality_range_max - h->seq_quality);
}
return sum;
} else {
PR_ASSERT(0); /* Programming error. */
return -1.0;
}
}
// <<<<<<<<<<<<<<<<<<<<<<<
/* Return max of h->template_mispriming and h->template_mispriming_r (max
template mispriming on either strand). */
double
oligo_max_template_mispriming(const primer_rec *h) {
return h->template_mispriming > h->template_mispriming_r ?
h->template_mispriming : h->template_mispriming_r;
}
double
oligo_max_template_mispriming_thermod(const primer_rec *h) {
return h->template_mispriming > h->template_mispriming_r ?
h->template_mispriming : h->template_mispriming_r;
}
char *
oligo_max_template_mispriming_struct(const primer_rec *h) {
return h->template_mispriming > h->template_mispriming_r ?
h->template_mispriming_struct : h->template_mispriming_r_struct;
}
/* Sort a given primer array by penalty */
static void
sort_primer_array(oligo_array *oligo)
{
// qsort(&oligo->oligo[0], oligo->num_elem, sizeof(*oligo->oligo),
// primer_rec_comp);
qsort(&oligo->oligo[0], oligo->num_elem, sizeof(primer_rec),
primer_rec_comp);
}
/* Compare function for sorting primer records. */
static int
primer_rec_comp(const void *x1, const void *x2)
{
const primer_rec *a1 = (const primer_rec *) x1;
const primer_rec *a2 = (const primer_rec *) x2;
if(a1->quality < a2->quality) return -1;
if (a1->quality > a2->quality) return 1;
/*
* We want primer_rec_comp to always return a non-0 result, because
* different implementations of qsort differ in how they treat "equal"
* elements, making it difficult to compare test output on different
* systems.
*/
if(a1->start > a2->start) return -1;
if(a1->start < a2->start) return 1;
if(a1->length < a2->length) return -1;
return 1;
}
/* Compare function for sorting primer records. */
static int
compare_primer_pair(const void *x1, const void *x2)
{
const primer_pair *a1 = (const primer_pair *) x1;
const primer_pair *a2 = (const primer_pair *) x2;
const double epsilon = 1e-6;
int y1, y2;
if ((a1->pair_quality + epsilon) < a2->pair_quality) return -1;
if (a1->pair_quality > (a2->pair_quality + epsilon)) return 1;
/*
* The following statements ensure that we get a stable order that
* is the same on all systems.
*/
y1 = a1->left->start;
y2 = a2->left->start;
if (y1 > y2) return -1; /* prefer left primers to the right. */
if (y1 < y2) return 1;
y1 = a1->right->start;
y2 = a2->right->start;
if (y1 < y2) return -1; /* prefer right primers to the left. */
if (y1 > y2) return 1;
y1 = a1->left->length;
y2 = a2->left->length;
if (y1 < y2) return -1; /* prefer shorter primers. */
if (y1 > y2) return 1;
y1 = a1->right->length;
y2 = a2->right->length;
if (y1 < y2) return -1; /* prefer shorter primers. */
if (y1 > y2) return 1;
return 0;
}
/*
* Defines parameter values for given primer pair. Returns PAIR_OK if the pair is
* acceptable; PAIR_FAILED otherwise. This function sets the
* various elements of *ppair, and also calculates some key EXPENSIVE
* parameters for individual primers if they have not been set yet.
*/
static int
characterize_pair(p3retval *retval,
const p3_global_settings *pa,
const seq_args_t* sa,
int m, int n, int int_num,
primer_pair *ppair,
const dpal_arg_holder *dpal_arg_to_use,
const thal_arg_holder *thal_arg_to_use,
int update_stats) {
char s1[THAL_MAX_ALIGN+1], s2[THAL_MAX_ALIGN+1],
s1_rev[THAL_MAX_ALIGN+1], s2_rev[THAL_MAX_ALIGN+1];
double compl_end, compl_end2;
pair_stats *pair_expl = &retval->best_pairs.expl;
int must_use = 0;
double min_oligo_tm;
int i, overhang_len;
tm_ret tm_calc; /* structure with Tm and bound (primer fraction) */
const thal_args *thal_args_for_template_mispriming
= use_end_for_th_template_mispriming
? thal_arg_to_use->end1
: thal_arg_to_use->any;
// memset(ppair, 0, sizeof(*ppair));
memset(ppair, 0, sizeof(primer_pair));
ppair->left = &retval->fwd.oligo[m];
ppair->right = &retval->rev.oligo[n];
ppair->product_size = retval->rev.oligo[n].start - retval->fwd.oligo[m].start+1;
ppair->target = 0;
ppair->compl_any = ppair->compl_end = 0;
ppair->compl_any_struct = NULL;
ppair->compl_end_struct = NULL;
ppair->template_mispriming_struct = NULL;
if (update_stats) {
pair_expl->considered++;
}
if (pa->primer_task == check_primers) {
must_use = 1;
}
/* We must use the pair if the caller specifed
both the left and the right primer. */
if (ppair->left->must_use != 0 &&
ppair->right->must_use != 0) {
/* But if caller specified primers are in
reversed order we cannot analyze them
as a pair. */
if (ppair->product_size < 1) {
pair_expl->reversed++;
return PAIR_FAILED;
}
must_use = 1;
}
ppair->must_use = must_use;
if (sa->tar2.count > 0) {
if (pair_spans_target(ppair, sa)) {
ppair->target = 1;
} else {
ppair->target = -1;
if (update_stats) { pair_expl->target++; }
if (!must_use) { return PAIR_FAILED; }
}
}
/* ============================================================= */
/* Check that the pair is included in one of the specified ok regions */
if ((sa->ok_regions.count > 0) && (!sa->ok_regions.any_pair)) {
int included = 0;
int l_start = ppair->left->start, l_end = ppair->left->start + ppair->left->length - 1;
int r_start = ppair->right->start - ppair->right->length + 1, r_end = ppair->right->start;
for (i=0; iok_regions.count; i++) {
if (sa->ok_regions.left_pairs[i][0] == -1) {
/* any left primer, check right primer */
if ((r_start >= sa->ok_regions.right_pairs[i][0]) &&
(r_end <= sa->ok_regions.right_pairs[i][0] + sa->ok_regions.right_pairs[i][1] - 1)) {
included = 1;
break;
}
} else if (sa->ok_regions.right_pairs[i][0] == -1) {
/* any right primer, check the left primer */
if ((l_start >= sa->ok_regions.left_pairs[i][0]) &&
(l_end <= sa->ok_regions.left_pairs[i][0] + sa->ok_regions.left_pairs[i][1] - 1)) {
included = 1;
break;
}
} else {
/* check both primers */
if ((l_start >= sa->ok_regions.left_pairs[i][0]) &&
(l_end <= sa->ok_regions.left_pairs[i][0] + sa->ok_regions.left_pairs[i][1] - 1) &&
(r_start >= sa->ok_regions.right_pairs[i][0]) &&
(r_end <= sa->ok_regions.right_pairs[i][0] + sa->ok_regions.right_pairs[i][1] - 1)) {
included = 1;
break;
}
}
}
if (!included) {
if (update_stats) { pair_expl->not_in_any_ok_region++; }
if (!must_use) { return PAIR_FAILED; }
}
}
/* ============================================================= */
/* Compute product Tm and related parameters; check constraints. */
if (ppair->right->start - ppair->left->start + 1 <= 0) {
fprintf(stderr, "temporary");
}
PR_ASSERT(ppair->right->start - ppair->left->start + 1 > 0)
tm_calc = long_seq_tm(
sa->trimmed_seq,
ppair->left->start,
ppair->right->start - ppair->left->start + 1,
/* TO DO -- skewed, it would be better to not use p_args elements here */
pa->p_args.salt_conc,
pa->p_args.divalent_conc,
pa->p_args.dntp_conc,
pa->p_args.dmso_conc,
pa->p_args.dmso_fact,
pa->p_args.formamide_conc
);
ppair->product_tm = tm_calc.Tm;
PR_ASSERT(ppair->product_tm != OLIGOTM_ERROR);
min_oligo_tm
= ppair->left->temp > ppair->right->temp ? ppair->right->temp : ppair->left->temp;
ppair->product_tm_oligo_tm_diff = ppair->product_tm - min_oligo_tm;
ppair->t_opt_a = 0.3 * min_oligo_tm + 0.7 * ppair->product_tm - 14.9;
if (pa->product_min_tm != PR_DEFAULT_PRODUCT_MIN_TM
&& ppair->product_tm < pa->product_min_tm) {
if (update_stats) { pair_expl->low_tm++; }
if (!must_use) { return PAIR_FAILED; }
}
if (pa->product_max_tm != PR_DEFAULT_PRODUCT_MAX_TM
&& ppair->product_tm > pa->product_max_tm) {
if (update_stats) { pair_expl->high_tm++; }
if (!must_use) { return PAIR_FAILED; }
}
ppair->diff_tm = fabs(retval->fwd.oligo[m].temp - retval->rev.oligo[n].temp);
if (ppair->diff_tm > pa->max_diff_tm) {
if (update_stats) { pair_expl->temp_diff++; }
if (!must_use) { return PAIR_FAILED; }
}
/* End of product-temperature related computations. */
/* ============================================================= */
/* ============================================================= */
/* BEGIN "EXPENSIVE" computations on _individual_ primers
in the pair. These have been postponed until
this point in the interests of efficiency.
*/
/* ============================================================= */
/* Estimate secondary structure and primer-dimer of _individual_
primers if not already calculated. */
/* s1 is the forward oligo. */
if (NULL != sa->overhang_left) {
overhang_len = strlen(sa->overhang_left);
strcpy(s1, sa->overhang_left);
_pr_shift_substr(sa->trimmed_seq,
retval->fwd.oligo[m].start,
retval->fwd.oligo[m].length,
overhang_len,
s1);
} else {
_pr_substr(
sa->trimmed_seq,
retval->fwd.oligo[m].start,
retval->fwd.oligo[m].length,
s1
);
}
/* s2 is the reverse oligo. */
_pr_substr(
sa->trimmed_seq,
retval->rev.oligo[n].start - retval->rev.oligo[n].length + 1,
retval->rev.oligo[n].length,
s2
);
if (NULL != sa->overhang_right) {
overhang_len = strlen(sa->overhang_right);
_pr_shift_substr(
sa->overhang_right_rv,
0,
overhang_len,
retval->rev.oligo[n].length,
s2
);
}
p3_reverse_complement(s1, s1_rev);
p3_reverse_complement(s2, s2_rev);
if (retval->fwd.oligo[m].self_any == ALIGN_SCORE_UNDEF
&& pa->thermodynamic_oligo_alignment==0) {
/* We have not yet computed the 'self_any' paramter,
which is an estimate of self primer-dimer and secondary
structure propensity. */
oligo_compl(&retval->fwd.oligo[m], &pa->p_args,
&retval->fwd.expl, dpal_arg_to_use, s1, s1_rev);
if (!OK_OR_MUST_USE(&retval->fwd.oligo[m])) {
pair_expl->considered--;
if (!must_use) { return PAIR_FAILED; }
}
}
/* Thermodynamic approach, fwd-primer */
if (retval->fwd.oligo[m].self_any == ALIGN_SCORE_UNDEF
&& pa->thermodynamic_oligo_alignment==1) {
oligo_compl_thermod(&retval->fwd.oligo[m], &pa->p_args,
&retval->fwd.expl, thal_arg_to_use, s1, s1); /* ! s1, s1_rev */
if (!OK_OR_MUST_USE(&retval->fwd.oligo[m])) {
pair_expl->considered--;
if (!must_use) { return PAIR_FAILED; }
}
}
if ((retval->fwd.oligo[m].hairpin_th == ALIGN_SCORE_UNDEF)
&& pa->thermodynamic_oligo_alignment==1) {
oligo_hairpin(&retval->fwd.oligo[m], &pa->p_args,
&retval->fwd.expl, thal_arg_to_use, s1);
if (!OK_OR_MUST_USE(&retval->fwd.oligo[m])) {
pair_expl->considered--;
if (!must_use) { return PAIR_FAILED; }
}
}
/* End of thermodynamic approach */
if (retval->rev.oligo[n].self_any == ALIGN_SCORE_UNDEF && pa->thermodynamic_oligo_alignment==0) {
oligo_compl(&retval->rev.oligo[n], &pa->p_args,
&retval->rev.expl, dpal_arg_to_use, s2_rev, s2);
if (!OK_OR_MUST_USE(&retval->rev.oligo[n])) {
pair_expl->considered--;
if (!must_use) { return PAIR_FAILED; }
}
}
/* Thermodynamic approach */
if (retval->rev.oligo[n].self_any == ALIGN_SCORE_UNDEF && pa->thermodynamic_oligo_alignment==1) {
oligo_compl_thermod(&retval->rev.oligo[n], &pa->p_args,
&retval->rev.expl, thal_arg_to_use, s2_rev, s2_rev); /* s2_rev, s2 */
if (!OK_OR_MUST_USE(&retval->rev.oligo[n])) {
pair_expl->considered--;
if (!must_use) { return PAIR_FAILED; }
}
}
if (retval->rev.oligo[n].hairpin_th == ALIGN_SCORE_UNDEF && pa->thermodynamic_oligo_alignment==1) {
oligo_hairpin(&retval->rev.oligo[n], &pa->p_args,
&retval->rev.expl, thal_arg_to_use, s2_rev);
if (!OK_OR_MUST_USE(&retval->rev.oligo[n])) {
pair_expl->considered--;
if (!must_use) { return PAIR_FAILED; }
}
}
/* End of thermodynamic approach */
/* End of secondary structure and primer-dimer of _individual_
primers. */
/* ============================================================= */
/* ============================================================= */
/* Mispriming of _individual_ primers to template and
to repeat libraries. */
if (retval->fwd.oligo[m].repeat_sim.score == NULL) {
/* We have not yet checked the oligo against the repeat library. */
oligo_repeat_library_mispriming(&retval->fwd.oligo[m], pa, sa, OT_LEFT,
&retval->fwd.expl, dpal_arg_to_use, &retval->glob_err);
if (OK_OR_MUST_USE(&retval->fwd.oligo[m])) {
oligo_template_mispriming(&retval->fwd.oligo[m], pa, sa, OT_LEFT,
&retval->fwd.expl,
dpal_arg_to_use->local_end,
thal_args_for_template_mispriming);
}
if (!OK_OR_MUST_USE(&retval->fwd.oligo[m])) {
pair_expl->considered--;
if (!must_use) { return PAIR_FAILED; }
}
}
if (retval->rev.oligo[n].repeat_sim.score == NULL) {
oligo_repeat_library_mispriming(&retval->rev.oligo[n], pa, sa, OT_RIGHT,
&retval->rev.expl, dpal_arg_to_use, &retval->glob_err);
if (OK_OR_MUST_USE(&retval->rev.oligo[n])) {
oligo_template_mispriming(&retval->rev.oligo[n], pa, sa, OT_RIGHT,
&retval->rev.expl,
dpal_arg_to_use->local_end,
thal_args_for_template_mispriming);
}
if (!OK_OR_MUST_USE(&retval->rev.oligo[n])) {
pair_expl->considered--;
if (!must_use) { return PAIR_FAILED; }
}
}
/* End of mispriming of _individual_ primers to template and
to repeat libraries. */
/* ============================================================= */
/* ============================================================= */
/*
* Similarity between s1 and s2 is equivalent to complementarity between
* s2's complement and s1. (Both s1 and s2 are taken from the same strand.)
*/
if(pa->thermodynamic_oligo_alignment==0) {
ppair->compl_any = align(s1, s2, dpal_arg_to_use->local);
if (ppair->compl_any > pa->pair_compl_any) {
if (update_stats) { pair_expl->compl_any++; }
if (!must_use) { return PAIR_FAILED; }
}
ppair->compl_end = align(s1, s2, dpal_arg_to_use->end);
if (ppair->compl_end > pa->pair_compl_end) {
if (update_stats) { pair_expl->compl_end++; }
if (!must_use) { return PAIR_FAILED; }
}
} else {
/* thermodynamical approach */
ppair->compl_any = align_thermod(s1, s2_rev, thal_arg_to_use->any);
if (ppair->compl_any > pa->pair_compl_any_th) {
if (update_stats) {
pair_expl->compl_any++;
}
if (!must_use) { return PAIR_FAILED; }
}
ppair->compl_end = align_thermod(s1, s2_rev, thal_arg_to_use->end1);
compl_end = align_thermod(s1, s2_rev, thal_arg_to_use->end2); /* Triinu Please check */
if (ppair->compl_end < compl_end) {
ppair->compl_end = compl_end;
}
if (ppair->compl_end > pa->pair_compl_end_th) {
if (update_stats) {
pair_expl->compl_end++;
}
if (!must_use) { return PAIR_FAILED; }
}
}
/*
* It is conceivable (though unlikely) that
* align(s2_rev, s1_rev, end_args) > align(s1,s2,end_args).
*/
if (pa->thermodynamic_oligo_alignment==0 && (compl_end = align(s2_rev, s1_rev, dpal_arg_to_use->end))
> ppair->compl_end) {
if (compl_end > pa->p_args.max_self_end) {
if (update_stats) { pair_expl->compl_end++; }
if (!must_use) { return PAIR_FAILED; }
}
ppair->compl_end = compl_end;
}
if ((ppair->repeat_sim = pair_repeat_sim(ppair, pa))
> pa->pair_repeat_compl) {
if (update_stats) { pair_expl->repeat_sim++; }
if (!must_use) { return PAIR_FAILED; }
}
/* thermodynamic approach */
if (pa->thermodynamic_oligo_alignment==1) {
compl_end = align_thermod(s2, s1_rev, thal_arg_to_use->end1);
compl_end2 = align_thermod(s2, s1_rev, thal_arg_to_use->end2);
if (compl_end2 > compl_end) {
compl_end = compl_end2;
}
if (compl_end > ppair->compl_end) {
if (compl_end > pa->p_args.max_self_end_th) {
if (update_stats) {
pair_expl->compl_end++;
}
if (!must_use) { return PAIR_FAILED; }
}
ppair->compl_end = compl_end;
}
}
/* ============================================================= */
/* ============================================================= */
/* Calculate _pair_ mispriming, if necessary. */
if (pa->thermodynamic_template_alignment == 0) {
if (!_pr_need_pair_template_mispriming(pa)) {
ppair->template_mispriming = ALIGN_SCORE_UNDEF;
} else {
PR_ASSERT(ppair->left->template_mispriming != ALIGN_SCORE_UNDEF);
PR_ASSERT(ppair->left->template_mispriming_r != ALIGN_SCORE_UNDEF);
PR_ASSERT(ppair->right->template_mispriming != ALIGN_SCORE_UNDEF);
PR_ASSERT(ppair->right->template_mispriming_r != ALIGN_SCORE_UNDEF);
ppair->template_mispriming =
ppair->left->template_mispriming + ppair->right->template_mispriming_r;
if ((ppair->left->template_mispriming_r + ppair->right->template_mispriming)
> ppair->template_mispriming)
ppair->template_mispriming
= ppair->left->template_mispriming_r + ppair->right->template_mispriming;
if (pa->pair_max_template_mispriming >= 0.0
&& ppair->template_mispriming > pa->pair_max_template_mispriming) {
if (update_stats) { pair_expl->template_mispriming++; }
if (!must_use) { return PAIR_FAILED; }
}
}
} else { /* thermodynamic approach */
if (!_pr_need_pair_template_mispriming_thermod(pa)) {
ppair->template_mispriming = ALIGN_SCORE_UNDEF;
} else {
PR_ASSERT(ppair->left->template_mispriming != ALIGN_SCORE_UNDEF);
PR_ASSERT(ppair->left->template_mispriming_r != ALIGN_SCORE_UNDEF);
PR_ASSERT(ppair->right->template_mispriming != ALIGN_SCORE_UNDEF);
PR_ASSERT(ppair->right->template_mispriming_r != ALIGN_SCORE_UNDEF);
ppair->template_mispriming =
ppair->left->template_mispriming + ppair->right->template_mispriming_r;
if ((ppair->left->template_mispriming_r + ppair->right->template_mispriming)
> ppair->template_mispriming)
ppair->template_mispriming
= ppair->left->template_mispriming_r + ppair->right->template_mispriming;
if (pa->pair_max_template_mispriming_th
&& ppair->template_mispriming > pa->pair_max_template_mispriming_th) {
if (update_stats) {
pair_expl->template_mispriming++;
}
if (!must_use) { return PAIR_FAILED; }
}
}
}
/* End of calculating _pair_ mispriming if necessary. */
/* ============================================================= */
return PAIR_OK;
} /* characterize_pair */
/*
*/
void
compute_position_penalty(const p3_global_settings *pa,
const seq_args_t* sa,
primer_rec *h,
oligo_type o_type)
{
int three_prime_base;
int inside_flag = 0;
int target_begin, target_end;
PR_ASSERT(OT_LEFT == o_type || OT_RIGHT == o_type);
PR_ASSERT(1 == sa->tar2.count);
target_begin = sa->tar2.pairs[0][0];
target_end = target_begin + sa->tar2.pairs[0][1] - 1;
three_prime_base = OT_LEFT == o_type
? h->start + h->length - 1 : h->start - h->length + 1;
bf_set_infinite_pos_penalty(h,1);
h->position_penalty = 0.0;
if (OT_LEFT == o_type) {
if (three_prime_base <= target_end) {
bf_set_infinite_pos_penalty(h,0);
if (three_prime_base < target_begin) {
h->position_penalty = target_begin - three_prime_base - 1;
} else {
h->position_penalty = three_prime_base - target_begin + 1;
inside_flag = 1;
}
}
} else { /* OT_RIGHT == o_type */
if (three_prime_base >= target_begin) {
bf_set_infinite_pos_penalty(h,0);
if (three_prime_base > target_end) {
h->position_penalty = three_prime_base - target_end - 1;
} else {
h->position_penalty = target_end - three_prime_base + 1;
inside_flag = 1;
}
}
}
if (!inside_flag) {
h->position_penalty *= pa->outside_penalty;
} else {
h->position_penalty *= pa->inside_penalty;
}
}
/*
* Return 1 if 'pair' spans any target (in sa->tar); otherwise return 0; An
* oligo pair spans a target, t, if the last base of the left primer is to
* left of the last base of t and the first base of the right primer is to
* the right of the first base of t. Of course the primers must
* still be in a legal position with respect to each other.
*/
static int
pair_spans_target(const primer_pair *pair, const seq_args_t* sa)
{
int i;
int last_of_left = pair->left->start + pair->left->length - 1;
int first_of_right = pair->right->start - pair->right->length + 1;
int target_first, target_last;
for (i = 0; i < sa->tar2.count; i++) {
target_first = sa->tar2.pairs[i][0];
target_last = target_first + sa->tar2.pairs[i][1] - 1;
if (last_of_left <= target_last
&& first_of_right >= target_first
&& last_of_left < first_of_right)
return 1;
}
return 0;
}
/*
* Return the value of the objective function value for given primer pair.
* We must know that the pair is acceptable before calling obj_fn.
*/
static double
obj_fn(const p3_global_settings *pa, primer_pair *h)
{
double sum;
double lower_tm;
sum = 0.0;
lower_tm = h->right->temp;
if(h->left->temp < h->right->temp) lower_tm = h->left->temp;
if(pa->pr_pair_weights.primer_quality) /* HERE 1 */
sum += pa->pr_pair_weights.primer_quality * (h->left->quality + h->right->quality);
if(pa->pr_pair_weights.io_quality && pa->pick_right_primer
&& pa->pick_left_primer && pa->pick_internal_oligo) {
sum += pa->pr_pair_weights.io_quality * h->intl->quality;
}
if(pa->pr_pair_weights.diff_tm) {
sum += pa->pr_pair_weights.diff_tm * h->diff_tm;
}
if (pa->thermodynamic_oligo_alignment==0) {
if (pa->pr_pair_weights.compl_any) {
sum += pa->pr_pair_weights.compl_any * h->compl_any;
}
if (pa->pr_pair_weights.compl_end) {
sum += pa->pr_pair_weights.compl_end * h->compl_end;
}
} else if (pa->thermodynamic_oligo_alignment==1) {
if (pa->pr_pair_weights.compl_any_th && ((lower_tm - pa->pr_pair_weights.temp_cutoff) <= h->compl_any)) {
sum += pa->pr_pair_weights.compl_any_th * (h->compl_any - (lower_tm - pa->pr_pair_weights.temp_cutoff - 1.0));
}
if (pa->pr_pair_weights.compl_any_th && ((lower_tm - pa->pr_pair_weights.temp_cutoff) > h->compl_any)) {
sum += pa->pr_pair_weights.compl_any_th * (1/(lower_tm - pa->pr_pair_weights.temp_cutoff + 1.0 - h->compl_any));
}
if (pa->pr_pair_weights.compl_end_th && ((lower_tm - pa->pr_pair_weights.temp_cutoff) <= h->compl_end)) {
sum += pa->pr_pair_weights.compl_end_th * (h->compl_end - (lower_tm - pa->pr_pair_weights.temp_cutoff - 1.0));
}
if (pa->pr_pair_weights.compl_end_th && ((lower_tm - pa->pr_pair_weights.temp_cutoff) > h->compl_end)) {
sum += pa->pr_pair_weights.compl_end_th * (1/(lower_tm - pa->pr_pair_weights.temp_cutoff + 1.0 - h->compl_end));
}
} else {
PR_ASSERT(0);
/* Programming error */
}
if(pa->pr_pair_weights.product_tm_lt && h->product_tm < pa->product_opt_tm) {
sum += pa->pr_pair_weights.product_tm_lt *
(pa->product_opt_tm - h->product_tm);
}
if(pa->pr_pair_weights.product_tm_gt && h->product_tm > pa->product_opt_tm) {
sum += pa->pr_pair_weights.product_tm_gt *
(h->product_tm - pa->product_opt_tm);
}
if(pa->pr_pair_weights.product_size_lt &&
h->product_size < pa->product_opt_size) {
sum += pa->pr_pair_weights.product_size_lt *
(pa->product_opt_size - h->product_size);
}
if(pa->pr_pair_weights.product_size_gt &&
h->product_size > pa->product_opt_size) {
sum += pa->pr_pair_weights.product_size_gt *
(h->product_size - pa->product_opt_size);
}
if(pa->pr_pair_weights.repeat_sim) {
sum += pa->pr_pair_weights.repeat_sim * h->repeat_sim;
}
if (pa->pr_pair_weights.template_mispriming && pa->thermodynamic_template_alignment==0) {
PR_ASSERT(pa->pr_pair_weights.template_mispriming >= 0.0);
PR_ASSERT(h->template_mispriming >= 0.0);
sum += pa->pr_pair_weights.template_mispriming * h->template_mispriming;
}
if (pa->pr_pair_weights.template_mispriming_th && pa->thermodynamic_template_alignment==1) {
PR_ASSERT(pa->pr_pair_weights.template_mispriming_th >= 0.0);
PR_ASSERT(h->template_mispriming >= 0.0);
if((lower_tm - pa->pr_pair_weights.temp_cutoff) <= h->template_mispriming) {
sum += pa->pr_pair_weights.template_mispriming_th *
(h->template_mispriming - (lower_tm - pa->pr_pair_weights.temp_cutoff - 1.0));
}
if((lower_tm - pa->pr_pair_weights.temp_cutoff) > h->template_mispriming) {
sum += pa->pr_pair_weights.template_mispriming_th *
(1/(lower_tm - pa->pr_pair_weights.temp_cutoff + 1.0 - h->template_mispriming));
}
}
PR_ASSERT(sum >= 0.0);
return sum;
}
static double
align(const char *s1,
const char *s2,
const dpal_args *a) {
dpal_results r;
if(a->flag == DPAL_LOCAL || a->flag == DPAL_LOCAL_END) {
if ((int)strlen(s2) < 3) {
/* For extremely short alignments we simply
max out the score, because the dpal subroutines
for these cannot handle this case.
TO DO: this can probably be corrected in dpal. */
return (int)strlen(s2);
}
}
dpal((const unsigned char *) s1, (const unsigned char *) s2, a, DPM_FAST, &r);
PR_ASSERT(r.score <= SHRT_MAX);
if (r.score == DPAL_ERROR_SCORE) {
/* There was an error. */
if (errno == ENOMEM) {
longjmp(_jmp_buf, 1);
} else {
/* This branch is taken only if there is a programming error, in
that s1 or s2 were NULL or contained an illegal character. We
try to print some debugging information before aborting. */
fprintf(stderr, "%s", r.msg);
/* Always false, causes an abort: */
PR_ASSERT(r.score != DPAL_ERROR_SCORE);
}
}
return ((r.score < 0.0) ? 0.0 : r.score / PR_ALIGN_SCORE_PRECISION);
}
/* Helper function */
static int
_set_string(char **loc, const char *new_string) {
if (*loc) {
free(*loc);
*loc = NULL;
}
if (!(*loc = (char *) malloc((int)strlen(new_string) + 1))) {
return 1; /* ENOMEM */
}
strcpy(*loc, new_string);
return 0;
}
static double
align_thermod(const char *s1,
const char *s2,
const thal_args *a)
{
int thal_trace=0;
thal_results r;
thal(
(const unsigned char *) s1,
(const unsigned char *) s2,
a,
THL_FAST,
&r,
DO_PRINTOUT
);
if (thal_trace) {
fprintf(
stdout,
"thal, thal_args, type=%d maxLoop=%d mv=%f dv=%f "
"dntp=%f dna_conc=%f, temp=%f, mode=%d dimer=%d\n",
a->type, a->maxLoop, a->mv, a->dv, a->dntp, a->dna_conc,
a->temp, DPM_FAST, a->dimer
);
fprintf(
stdout,
"thal: s1=%s s2=%s temp=%f msg=%s end1=%d end2=%d\n",
s1, s2, r.temp, r.msg, r.align_end_1, r.align_end_2
);
}
PR_ASSERT(r.temp <= DBL_MAX);
if (r.temp == THAL_ERROR_SCORE) {
/* There was an error. */
if (errno == ENOMEM) {
longjmp(_jmp_buf, 1);
} else {
/* This branch is taken if there is an error other than
ENOMEM, in which case we treat it as a per sequence error.
*/
/* Save the error string */
if (!_set_string(&thermodynamic_alignment_length_error_msg, r.msg)) {
thermodynamic_alignment_length_error = 1;
}
longjmp(_jmp_buf, 1);
}
}
return ((r.temp < 0.0) ? 0.0 : (double) (r.temp));
}
/* Free the secondary structure strings for selected primers */
void
destroy_secundary_structures(
const p3_global_settings *pa,
p3retval *retval
) {
/* Pointers for the primer set just printing */
int num_print;
if ((pa == NULL) || (retval == NULL)) {
return;
}
/* Do we have a list of primers or pairs? */
if (retval->output_type == primer_list) {
/* For Primer Lists: Figure out how many primers are in
* the array that can be printed. If more than needed,
* set it to the number requested. */
/* Get how may primers should be max. printed */
num_print = pa->num_return;
if (num_print > retval->fwd.num_elem) {
num_print = retval->fwd.num_elem;
}
for (int i = 0 ; i < num_print ; i++) {
destroy_primer_sec_struct(&retval->fwd.oligo[i]);
}
num_print = pa->num_return;
if (num_print > retval->rev.num_elem) {
num_print = retval->rev.num_elem;
}
for (int i = 0 ; i < num_print ; i++) {
destroy_primer_sec_struct(&retval->rev.oligo[i]);
}
num_print = pa->num_return;
if (num_print > retval->intl.num_elem) {
num_print = retval->intl.num_elem;
}
for (int i = 0 ; i < num_print ; i++) {
destroy_primer_sec_struct(&retval->intl.oligo[i]);
}
} else {
/* Get how may primers should be max. printed */
num_print = retval->best_pairs.num_pairs;
for (int i = 0 ; i < num_print ; i++) {
destroy_primer_sec_struct(retval->best_pairs.pairs[i].left);
destroy_primer_sec_struct(retval->best_pairs.pairs[i].right);
destroy_pair_sec_struct(&retval->best_pairs.pairs[i]);
if (retval->intl.num_elem > 0) {
destroy_primer_sec_struct(retval->best_pairs.pairs[i].intl);
}
}
}
}
void
destroy_primer_sec_struct(primer_rec *p_rec) {
if (NULL == p_rec) { return; }
if (p_rec->self_any_struct != NULL) {
free(p_rec->self_any_struct);
p_rec->self_any_struct = NULL;
}
if (p_rec->self_end_struct != NULL) {
free(p_rec->self_end_struct);
p_rec->self_end_struct = NULL;
}
if (p_rec->hairpin_struct != NULL) {
free(p_rec->hairpin_struct);
p_rec->hairpin_struct = NULL;
}
}
void
destroy_pair_sec_struct(primer_pair *ppair) {
if (NULL == ppair) { return; }
if (ppair->compl_any_struct != NULL) {
free(ppair->compl_any_struct);
ppair->compl_any_struct = NULL;
}
if (ppair->compl_end_struct != NULL) {
free(ppair->compl_end_struct);
ppair->compl_end_struct = NULL;
}
}
void
save_overwrite_sec_struct(char **base, char *inp) {
if (*base != NULL) {
free(*base);
}
*base = inp;
}
/* Calculate the secondary structures for selected primers */
void
recalc_secundary_structures(
const p3_global_settings *pa,
const seq_args_t* sa,
const dpal_arg_holder *dpal_arg_to_use,
const thal_arg_holder *thal_arg_to_use,
const thal_arg_holder *thal_oligo_arg_to_use,
p3retval *retval
) {
/* Pointers for the primer set just printing */
int num_print;
/* Do we have a list of primers or pairs? */
if (retval->output_type == primer_list) {
/* For Primer Lists: Figure out how many primers are in
* the array that can be printed. If more than needed,
* set it to the number requested. */
/* Get how may primers should be max. printed */
num_print = pa->num_return;
if (num_print > retval->fwd.num_elem) {
num_print = retval->fwd.num_elem;
}
for (int i = 0 ; i < num_print ; i++) {
recalc_primer_sec_struct(
&retval->fwd.oligo[i],
0,
pa,
sa,
dpal_arg_to_use,
thal_arg_to_use
);
}
num_print = pa->num_return;
if (num_print > retval->rev.num_elem) {
num_print = retval->rev.num_elem;
}
for (int i = 0 ; i < num_print ; i++) {
recalc_primer_sec_struct(
&retval->rev.oligo[i],
1,
pa,
sa,
dpal_arg_to_use,
thal_arg_to_use
);
}
num_print = pa->num_return;
if (num_print > retval->intl.num_elem) {
num_print = retval->intl.num_elem;
}
for (int i = 0 ; i < num_print ; i++) {
recalc_primer_sec_struct(
&retval->intl.oligo[i],
2,
pa,
sa,
dpal_arg_to_use,
thal_oligo_arg_to_use
);
}
} else {
/* Get how may primers should be max. printed */
num_print = retval->best_pairs.num_pairs;
for (int i = 0 ; i < num_print ; i++) {
recalc_primer_sec_struct(
retval->best_pairs.pairs[i].left,
0,
pa,
sa,
dpal_arg_to_use,
thal_arg_to_use
);
recalc_primer_sec_struct(
retval->best_pairs.pairs[i].right,
1,
pa,
sa,
dpal_arg_to_use,
thal_arg_to_use
);
recalc_pair_sec_struct(
&retval->best_pairs.pairs[i],
pa,
sa,
dpal_arg_to_use,
thal_arg_to_use
);
if (retval->intl.num_elem > 0) {
recalc_primer_sec_struct(
retval->best_pairs.pairs[i].intl,
2,
pa,
sa,
dpal_arg_to_use,
thal_oligo_arg_to_use
);
}
}
}
}
/* This functions overwrite the any/end values to report discrepancies for debugging.*/
void
recalc_primer_sec_struct(
primer_rec *p_rec,
const int primer_type, /* left 0, right 1, intl 2 */
const p3_global_settings *pa,
const seq_args_t* sa,
const dpal_arg_holder *dpal_arg_to_use,
const thal_arg_holder *thal_arg_to_use
) {
char s1[THAL_MAX_ALIGN+1], s1_rev[THAL_MAX_ALIGN+1];
int overhang_len;
/* s1 is the forward oligo. */
if (primer_type == 0) { /*left */
if (NULL != sa->overhang_left) {
overhang_len = strlen(sa->overhang_left);
strcpy(s1, sa->overhang_left);
_pr_shift_substr(
sa->trimmed_seq,
p_rec->start,
p_rec->length,
overhang_len,
s1
);
} else {
_pr_substr(sa->trimmed_seq, p_rec->start, p_rec->length, s1);
}
p3_reverse_complement(s1, s1_rev);
} else if (primer_type == 2) { /* intl */
_pr_substr(sa->trimmed_seq, p_rec->start, p_rec->length, s1);
p3_reverse_complement(s1, s1_rev);
} else { /* right */
_pr_substr(
sa->trimmed_seq,
p_rec->start - p_rec->length + 1,
p_rec->length,
s1_rev
);
if (NULL != sa->overhang_right) {
overhang_len = strlen(sa->overhang_right);
_pr_shift_substr(
sa->overhang_right_rv,
0,
overhang_len,
p_rec->length,
s1_rev
);
} else {
_pr_substr(
sa->trimmed_seq,
p_rec->start - p_rec->length + 1,
p_rec->length,
s1_rev
);
}
p3_reverse_complement(s1_rev, s1);
}
if (pa->thermodynamic_oligo_alignment==0) {
dpal_results any, end;
/* NOTE: important to set these values to NULL to prevent segfaults */
any.sec_struct = NULL;
end.sec_struct = NULL;
if (p_rec->self_any > 0.0) {
dpal((const unsigned char *) s1, (const unsigned char *) s1_rev,
dpal_arg_to_use->local, DPM_STRUCT, &any);
p_rec->self_any = any.score / PR_ALIGN_SCORE_PRECISION;
save_overwrite_sec_struct(&p_rec->self_any_struct, any.sec_struct);
}
if (p_rec->self_end > 0.0) {
dpal((const unsigned char *) s1, (const unsigned char *) s1_rev,
dpal_arg_to_use->end, DPM_STRUCT, &end);
p_rec->self_end = end.score / PR_ALIGN_SCORE_PRECISION;
save_overwrite_sec_struct(&p_rec->self_end_struct, end.sec_struct);
}
}
/* Thermodynamic approach, fwd-primer */
if (pa->thermodynamic_oligo_alignment==1) {
thal_results any, end, hair;
/* NOTE: important to set these values to NULL to prevent segfaults */
any.sec_struct = NULL;
end.sec_struct = NULL;
hair.sec_struct = NULL;
if (p_rec->self_any > 0.0 ) {
thal(
(const unsigned char *) s1,
(const unsigned char *) s1,
thal_arg_to_use->any,
THL_STRUCT,
&any,
DO_PRINTOUT
);
p_rec->self_any = any.temp;
save_overwrite_sec_struct(&p_rec->self_any_struct, any.sec_struct);
}
if (p_rec->self_end > 0.0) {
thal(
(const unsigned char *) s1,
(const unsigned char *) s1,
thal_arg_to_use->end1,
THL_STRUCT,
&end,
DO_PRINTOUT
);
p_rec->self_end = end.temp;
save_overwrite_sec_struct(&p_rec->self_end_struct, end.sec_struct);
}
if (p_rec->hairpin_th > 0.0 ) {
thal(
(const unsigned char *) s1,
(const unsigned char *) s1,
thal_arg_to_use->hairpin_th,
THL_STRUCT,
&hair,
DO_PRINTOUT
);
p_rec->hairpin_th = hair.temp;
save_overwrite_sec_struct(&p_rec->hairpin_struct, hair.sec_struct);
}
}
}
void
recalc_pair_sec_struct(
primer_pair *ppair,
const p3_global_settings *pa,
const seq_args_t* sa,
const dpal_arg_holder *dpal_arg_to_use,
const thal_arg_holder *thal_arg_to_use
) {
char s1[THAL_MAX_ALIGN+1], s1_rev[THAL_MAX_ALIGN+1];
char s2[THAL_MAX_ALIGN+1], s2_rev[THAL_MAX_ALIGN+1];
int overhang_len;
/* s1 is the forward oligo. */
if (NULL != sa->overhang_left) {
overhang_len = strlen(sa->overhang_left);
strcpy(s1, sa->overhang_left);
_pr_shift_substr(sa->trimmed_seq,
ppair->left->start,
ppair->left->length,
overhang_len,
s1);
} else {
_pr_substr(sa->trimmed_seq,
ppair->left->start,
ppair->left->length,
s1);
}
/* s2 is the reverse oligo. */
_pr_substr(sa->trimmed_seq,
ppair->right->start - ppair->right->length + 1,
ppair->right->length,
s2);
if (NULL != sa->overhang_right) {
overhang_len = strlen(sa->overhang_right);
_pr_shift_substr(
sa->overhang_right_rv,
0,
overhang_len,
ppair->right->length,
s2
);
}
p3_reverse_complement(s1, s1_rev);
p3_reverse_complement(s2, s2_rev);
if(pa->thermodynamic_oligo_alignment==0) {
dpal_results any, end, end2;
end2.sec_struct = NULL;
if (ppair->compl_any > 0.0) {
dpal(
(const unsigned char *) s1,
(const unsigned char *) s2,
dpal_arg_to_use->local,
DPM_STRUCT,
&any
);
ppair->compl_any = any.score / PR_ALIGN_SCORE_PRECISION;
save_overwrite_sec_struct(
&ppair->compl_any_struct,
any.sec_struct
);
}
if (ppair->compl_end > 0.0) {
dpal(
(const unsigned char *) s1,
(const unsigned char *) s2,
dpal_arg_to_use->end,
DPM_STRUCT,
&end
);
ppair->compl_end = end.score / PR_ALIGN_SCORE_PRECISION;
save_overwrite_sec_struct(&ppair->compl_end_struct, end.sec_struct);
dpal(
(const unsigned char *) s2_rev,
(const unsigned char *) s1_rev,
dpal_arg_to_use->end,
DPM_STRUCT,
&end2
);
if (end2.score / PR_ALIGN_SCORE_PRECISION > ppair->compl_end){
ppair->compl_end = end2.score / PR_ALIGN_SCORE_PRECISION;
save_overwrite_sec_struct(&ppair->compl_end_struct, end2.sec_struct);
} else {
if (end2.sec_struct != NULL) {
free(end2.sec_struct);
end2.sec_struct = NULL;
}
}
}
} else {
/* thermodynamical approach */
thal_results any, end1, end2, end3, end4;
any.sec_struct = NULL;
end1.sec_struct = NULL;
end2.sec_struct = NULL;
end3.sec_struct = NULL;
end4.sec_struct = NULL;
if (ppair->compl_any > 0.0) {
thal(
(const unsigned char *) s1,
(const unsigned char *) s2_rev,
thal_arg_to_use->any,
THL_STRUCT,
&any,
DO_PRINTOUT
);
ppair->compl_any = any.temp;
save_overwrite_sec_struct(&ppair->compl_any_struct, any.sec_struct);
}
if (ppair->compl_end > 0.0) {
thal(
(const unsigned char *) s1,
(const unsigned char *) s2_rev,
thal_arg_to_use->end1,
THL_STRUCT,
&end1,
DO_PRINTOUT
);
ppair->compl_end = end1.temp;
save_overwrite_sec_struct(&ppair->compl_end_struct, end1.sec_struct);
thal(
(const unsigned char *) s1,
(const unsigned char *) s2_rev,
thal_arg_to_use->end2,
THL_STRUCT,
&end2,
DO_PRINTOUT
); /* Triinu Please check */
if (ppair->compl_end < end2.temp) {
ppair->compl_end = end2.temp;
save_overwrite_sec_struct(&ppair->compl_end_struct, end2.sec_struct);
} else {
if (end2.sec_struct != NULL) {
free(end2.sec_struct);
end2.sec_struct = NULL;
}
}
thal(
(const unsigned char *) s2,
(const unsigned char *) s1_rev,
thal_arg_to_use->end1,
THL_STRUCT,
&end3,
DO_PRINTOUT
);
if (ppair->compl_end < end3.temp) {
ppair->compl_end = end3.temp;
save_overwrite_sec_struct(&ppair->compl_end_struct, end3.sec_struct);
} else {
if (end3.sec_struct != NULL) {
free(end3.sec_struct);
end3.sec_struct = NULL;
}
}
thal(
(const unsigned char *) s2,
(const unsigned char *) s1_rev,
thal_arg_to_use->end2,
THL_STRUCT,
&end4,
DO_PRINTOUT
); /* Triinu Please check */
if (ppair->compl_end < end4.temp) {
ppair->compl_end = end4.temp;
save_overwrite_sec_struct(&ppair->compl_end_struct, end4.sec_struct);
} else {
if (end4.sec_struct != NULL) {
free(end4.sec_struct);
end4.sec_struct = NULL;
}
}
}
}
}
/* Return the sequence of oligo in
a ****static***** buffer. The
sequence returned is changed at the
next call to pr_oligo_sequence. */
char *
pr_oligo_overhang_sequence(const seq_args_t* sa,
const primer_rec *oligo)
{
static char s[THAL_MAX_ALIGN+1];
int seq_len, overhang_len;
PR_ASSERT(NULL != sa);
PR_ASSERT(NULL != oligo);
seq_len = strlen(sa->sequence);
if (NULL != sa->overhang_left) {
overhang_len = strlen(sa->overhang_left);
_pr_substr(sa->overhang_left, 0, overhang_len, s);
} else {
overhang_len = 0;
}
PR_ASSERT(oligo->start + sa->incl_s >= 0);
PR_ASSERT(oligo->start + sa->incl_s + oligo->length <= seq_len);
_pr_shift_substr(sa->sequence, sa->incl_s + oligo->start,
oligo->length, overhang_len, s);
return &s[0];
}
char *
pr_oligo_sequence(const seq_args_t* sa,
const primer_rec *oligo)
{
static char s[THAL_MAX_ALIGN+1];
int seq_len;
PR_ASSERT(NULL != sa);
PR_ASSERT(NULL != oligo);
seq_len = (int)strlen(sa->sequence);
PR_ASSERT(oligo->start + sa->incl_s >= 0);
PR_ASSERT(oligo->start + sa->incl_s + oligo->length <= seq_len);
_pr_substr(sa->sequence, sa->incl_s + oligo->start, oligo->length, s);
return &s[0];
}
char *
pr_oligo_rev_c_overhang_sequence(
const seq_args_t* sa,
const primer_rec *o
) {
static char s[THAL_MAX_ALIGN+1], s1[THAL_MAX_ALIGN+1];
int seq_len, start, overhang_len;
PR_ASSERT(NULL != sa);
PR_ASSERT(NULL != o);
seq_len = strlen(sa->sequence);
start = sa->incl_s + o->start - o->length + 1;
PR_ASSERT(start >= 0);
PR_ASSERT(start + o->length <= seq_len);
_pr_substr(sa->sequence, start, o->length, s);
p3_reverse_complement(s,s1);
if (NULL != sa->overhang_right) {
overhang_len = strlen(sa->overhang_right);
_pr_substr(sa->overhang_right, 0, overhang_len, s);
} else {
overhang_len = 0;
}
_pr_shift_substr(s1, 0, o->length, overhang_len, s);
return &s[0];
}
char *
pr_oligo_rev_c_sequence(const seq_args_t* sa,
const primer_rec *o)
{
static char s[THAL_MAX_ALIGN+1], s1[THAL_MAX_ALIGN+1];
int seq_len, start;
PR_ASSERT(NULL != sa);
PR_ASSERT(NULL != o);
seq_len = (int)strlen(sa->sequence);
start = sa->incl_s + o->start - o->length + 1;
PR_ASSERT(start >= 0);
PR_ASSERT(start + o->length <= seq_len);
_pr_substr(sa->sequence, start, o->length, s);
p3_reverse_complement(s,s1);
return &s1[0];
}
/* Calculate self complementarity (both h->self_any and h->self_end)
which we use as an approximation for both secondary structure and
self primer-dimer. */
static void
oligo_compl(primer_rec *h,
const args_for_one_oligo_or_primer *po_args,
oligo_stats *ostats,
const dpal_arg_holder *dpal_arg_to_use,
const char *oligo_seq,
const char *revc_oligo_seq)
{
PR_ASSERT(h != NULL);
h->self_any = align(oligo_seq, revc_oligo_seq, dpal_arg_to_use->local);
if (h->self_any > po_args->max_self_any) {
op_set_high_self_any(h);
ostats->compl_any++;
ostats->ok--;
if (!h->must_use) { return; }
}
h->self_end = align(oligo_seq, revc_oligo_seq, dpal_arg_to_use->end);
if (h->self_end > po_args->max_self_end) {
op_set_high_self_end(h);
ostats->compl_end++;
ostats->ok--;
if (!h->must_use) { return; }
}
}
static void
oligo_compl_thermod(primer_rec *h,
const args_for_one_oligo_or_primer *po_args,
oligo_stats *ostats,
const thal_arg_holder *thal_arg_to_use,
const char *oligo_seq,
const char *revc_oligo_seq)
{
PR_ASSERT(h != NULL);
h->self_any = align_thermod(oligo_seq, revc_oligo_seq, thal_arg_to_use->any);
if(h->self_any > po_args->max_self_any_th) {
op_set_high_self_any(h);
ostats->compl_any++;
ostats->ok--;
if (!h->must_use) { return; }
}
h->self_end = align_thermod(oligo_seq, revc_oligo_seq, thal_arg_to_use->end1);
if(h->self_end > po_args->max_self_end_th) {
op_set_high_self_end(h);
ostats->compl_end++;
ostats->ok--;
if (!h->must_use) { return; }
}
}
static void
oligo_hairpin(primer_rec *h,
const args_for_one_oligo_or_primer *po_args,
oligo_stats *ostats,
const thal_arg_holder *thal_arg_to_use,
const char *oligo_seq)
{
PR_ASSERT(h != NULL);
h->hairpin_th = align_thermod(oligo_seq, oligo_seq, thal_arg_to_use->hairpin_th);
if(h->hairpin_th > po_args->max_hairpin_th) {
op_set_high_hairpin_th(h);
ostats->hairpin_th++;
ostats->ok--;
return;
}
}
static void
primer_mispriming_to_template(primer_rec *h,
const p3_global_settings *pa,
const seq_args_t* sa,
oligo_type l,
oligo_stats *ostats,
int first,
int last,
/* The oligo sequence: */
const char *s,
/* s reverse complemented: */
const char *s_r,
const dpal_args *align_args
)
{
const char *oseq;
char *target, *target_r;
int tmp, seqlen;
int debug = 0;
int first_untrimmed, last_untrimmed;
/* Indexes of first and last bases of the oligo in sa->seq,
that is, WITHIN THE TOTAL SEQUENCE INPUT. */
/* first, last are indexes of first and last bases of the oligo in
sa->trimmed_seq, that is, WITHIN THE INCLUDED REGION. */
char tmp_char;
double tmp_score;
seqlen = (int)strlen(sa->upcased_seq);
first_untrimmed = sa->incl_s + first;
last_untrimmed = sa->incl_s + last;
if (l == OT_LEFT) {
oseq = &s[0];
target = &sa->upcased_seq[0];
target_r = &sa->upcased_seq_r[0];
} else { /* l == OT_RIGHT */
if (debug) {
fprintf(stderr, "first_untrimmed = %d, last_untrimmed = %d\n",
first_untrimmed, last_untrimmed);
}
oseq = &s_r[0];
target = &sa->upcased_seq_r[0];
target_r = &sa->upcased_seq[0];
/* We need to adjust first_untrimmed and last_untrimmed so that
they are correct in the reverse-complemented
sequence.
*/
tmp = (seqlen - last_untrimmed) - 1;
last_untrimmed = (seqlen - first_untrimmed) - 1;
first_untrimmed = tmp;
}
/* 1. Align to the template 5' of the oligo. */
tmp_char = target[first_untrimmed];
target[first_untrimmed] = '\0';
tmp_score = align(oseq, target, align_args);
if (debug) {
if (l == OT_LEFT) { fprintf(stderr, "\n************ OLIGO = LEFT\n"); }
else { fprintf(stderr, "\n************ OLIGO = RIGHT\n"); }
fprintf(stderr, "first_untrimmed = %d, last_untrimmed = %d,first = %d, last = %d\n",
first_untrimmed, last_untrimmed, first, last);
fprintf(stderr, "5' of oligo: Score %f aligning %s against %s\n\n", tmp_score,
oseq, target);
}
target[first_untrimmed] = tmp_char;
/* 2. Align to the template 3' of the oligo. */
h->template_mispriming
= align(oseq, &target[0] + last_untrimmed + 1, align_args);
if (debug) {
fprintf(stderr, "3' of oligo Score %f aligning %s against %s\n\n",
h->template_mispriming, oseq, &target[0] + last_untrimmed + 1);
}
/* 3. Take the max of 1. and 2. */
if (tmp_score > h->template_mispriming) {
h->template_mispriming = tmp_score;
}
/* 4. Align to the reverse strand of the template. */
h->template_mispriming_r
= align(oseq, target_r, align_args);
if (debug) {
fprintf(stderr, "other strand Score %f aligning %s against %s\n\n",
h->template_mispriming_r, oseq, target_r);
}
if (pa->p_args.max_template_mispriming >= 0) {
if (oligo_max_template_mispriming(h) > pa->p_args.max_template_mispriming) {
op_set_high_similarity_to_multiple_template_sites(h);
if (OT_LEFT == l || OT_RIGHT == l ) {
ostats->template_mispriming++;
ostats->ok--;
} else PR_ASSERT(0); /* Should not get here. */
} else {
/* This oligo is ok, mark it so we do not do this check again. */
h->template_mispriming_ok = 1;
}
}
}
static void
primer_mispriming_to_template_thermod(primer_rec *h,
const p3_global_settings *pa,
const seq_args_t* sa,
oligo_type l,
oligo_stats *ostats,
int first,
int last,
/* The oligo sequence: */
const char *s,
/* s reverse complemented: */
const char *s_r,
const thal_args *align_args)
{
const char *oseq;
char *target, *target_r;
int tmp, seqlen;
int debug = 0;
int first_untrimmed, last_untrimmed;
/* Indexes of first and last bases of the oligo in sa->seq,
* that is, WITHIN THE TOTAL SEQUENCE INPUT. */
/* first, last are indexes of first and last bases of the oligo in
* sa->trimmed_seq, that is, WITHIN THE INCLUDED REGION. */
char tmp_char;
double tmp_score;
seqlen = (int)strlen(sa->upcased_seq);
first_untrimmed = sa->incl_s + first;
last_untrimmed = sa->incl_s + last;
if (l == OT_RIGHT) {
oseq = &s_r[0];
target = &sa->upcased_seq[0];
target_r = &sa->upcased_seq_r[0];
} else { /* l == OT_RIGHT */
if (debug) {
fprintf(stdout, "first_untrimmed = %d, last_untrimmed = %d\n",
first_untrimmed, last_untrimmed);
}
oseq = &s[0];
target = &sa->upcased_seq_r[0];
target_r = &sa->upcased_seq[0];
/* We need to adjust first_untrimmed and last_untrimmed so that
* they are correct in the reverse-complemented
* sequence.
* */
tmp = (seqlen - last_untrimmed) - 1;
last_untrimmed = (seqlen - first_untrimmed) - 1;
first_untrimmed = tmp;
}
/* 1. Align to the template 5' of the oligo. */
/* tmp_char = target_r[first_untrimmed]; Corrected 2012-05-30 */
tmp_char = target[first_untrimmed];
target[first_untrimmed] = '\0';
tmp_score = align_thermod(oseq, target, align_args);
if (debug) {
if (l == OT_LEFT) { fprintf(stdout, "\n************ OLIGO = LEFT\n"); }
else { fprintf(stdout, "\n************ OLIGO = RIGHT\n"); }
fprintf(stdout, "first_untrimmed = %d, last_untrimmed = %d, first = %d, last = %d\n",
first_untrimmed, last_untrimmed, first, last);
fprintf(stdout, "5' of oligo: Score %f aligning %s against %s\n\n", tmp_score,
oseq, target);
}
target[first_untrimmed] = tmp_char;
/* 2. Align to the template 3' of the oligo. */
h->template_mispriming
= align_thermod(oseq, &target[0] + last_untrimmed + 1, align_args);
if (debug) {
fprintf(stdout, "3' of oligo Score %f aligning %s against %s\n\n",
h->template_mispriming, oseq, &target[0] + last_untrimmed + 1);
}
/* 3. Take the max of 1. and 2. */
if (tmp_score > h->template_mispriming) {
h->template_mispriming = tmp_score;
}
/* 4. Align to the reverse strand of the template. */
h->template_mispriming_r
= align_thermod(oseq, target_r, align_args);
if (debug) {
fprintf(stdout,
"In primer_mispriming_to_template_thermod\n"
" other strand Score %f aligning %s against %s\n\n",
h->template_mispriming_r, oseq, target_r);
}
if (pa->p_args.max_template_mispriming_th >= 0) {
if (oligo_max_template_mispriming_thermod(h) > pa->p_args.max_template_mispriming_th) {
op_set_high_similarity_to_multiple_template_sites(h);
if (OT_LEFT == l || OT_RIGHT == l ) {
ostats->template_mispriming++;
ostats->ok--;
} else { PR_ASSERT(0); } /* Should not get here. */
} else {
/* This oligo is ok, mark it so we do not do this check again. */
h->template_mispriming_ok = 1;
}
}
}
static void
oligo_compute_sequence_and_reverse(primer_rec *h,
const seq_args_t* sa,
oligo_type l,
int *first, int *last,
char *s, char *s_r)
{
*first = (OT_LEFT == l || OT_INTL == l)
? h->start
: h->start - h->length + 1;
*last = (OT_LEFT == l || OT_INTL == l)
? h->start + h->length - 1
: h->start;
_pr_substr(sa->trimmed_seq, *first, h->length, s);
p3_reverse_complement(s, s_r);
}
/* Possible improvement -- pass in the oligo sequences */
static void
oligo_repeat_library_mispriming(
primer_rec *h,
const p3_global_settings *pa,
const seq_args_t* sa,
oligo_type l,
oligo_stats *ostats,
const dpal_arg_holder *dpal_arg_to_use,
pr_append_str *error
) {
char s[MAX_PRIMER_LENGTH+1]; /* Will contain the oligo sequence. */
char s_r[MAX_PRIMER_LENGTH+1]; /* Will contain s reverse complemented. */
double w;
const seq_lib *lib;
int i;
int first, last; /* Indexes of first and last bases of the oligo in
sa->trimmed_seq, that is, WITHIN THE INCLUDED
REGION. */
int min, max;
short max_lib_compl;
/* First, check the oligo against the repeat library. */
if (OT_INTL == l) {
lib = pa->o_args.repeat_lib;
max_lib_compl = (short) pa->o_args.max_repeat_compl;
} else {
lib = pa->p_args.repeat_lib;
max_lib_compl = (short) pa->p_args.max_repeat_compl;
}
oligo_compute_sequence_and_reverse(h, sa, l, &first, &last, s, s_r);
/*
* Calculate maximum similarity to sequences from user defined repeat
* library. Compare it with maximum allowed repeat similarity.
*/
if (seq_lib_num_seq(lib) > 0) {
/* Library exists and is non-empty. */
h->repeat_sim.score =
(double *) pr_safe_malloc(lib->seq_num * sizeof(double));
h->repeat_sim.max = h->repeat_sim.min = 0;
max = min = 0;
h->repeat_sim.name = lib->names[0];
for (i = 0; i < lib->seq_num; i++) {
if (OT_LEFT == l) {
w = lib->weight[i] *
align(s, lib->seqs[i],
(pa->lib_ambiguity_codes_consensus
? dpal_arg_to_use->local_end_ambig
: dpal_arg_to_use->local_end));
} else if (OT_INTL == l) {
w = lib->weight[i] *
align(s, lib->seqs[i],
(pa->lib_ambiguity_codes_consensus
? dpal_arg_to_use->local_ambig
: dpal_arg_to_use->local));
} else {
w = lib->weight[i] *
align(s_r, lib->rev_compl_seqs[i],
(pa->lib_ambiguity_codes_consensus
? dpal_arg_to_use->local_end_ambig
: dpal_arg_to_use->local));
}
if (w > SHRT_MAX || w < SHRT_MIN) {
/* This check is necessary for the next 9 lines */
pr_append_new_chunk( error,
"Out of range error occured calculating match to repeat library");
return;
}
h->repeat_sim.score[i] = w;
if(w > max) {
max = (int) w;
h->repeat_sim.max = i;
h->repeat_sim.name = lib->names[i];
}
if(w < min) {
min = (int) w;
h->repeat_sim.min = i;
}
if (w > max_lib_compl) {
op_set_high_similarity_to_non_template_seq(h);
ostats->repeat_score++;
ostats->ok--;
if (!h->must_use) { return; }
} /* if w > max_lib_compl */
} /* for */
} /* if library exists and is non-empty */
/* End of checking against the repeat library */
}
/* This function carries out either the old "dpal" alignment or the
thermodynamic alignment, depending on the value of
pa->thermodynamic_template_alignment. */
static void
oligo_template_mispriming(primer_rec *h,
const p3_global_settings *pa,
const seq_args_t* sa,
oligo_type l,
oligo_stats *ostats,
const dpal_args *d_align_args,
const thal_args *t_align_args)
{
char s[MAX_PRIMER_LENGTH+1]; /* Will contain the oligo sequence. */
char s_r[MAX_PRIMER_LENGTH+1]; /* Will contain s reverse complemented. */
int first, last; /* Indexes of first and last bases of the oligo in
sa->trimmed_seq, that is, WITHIN THE INCLUDED
REGION. */
/* Check if we already did this and the oligo was ok. */
if (h->template_mispriming_ok) {
return;
}
oligo_compute_sequence_and_reverse(h, sa, l, &first, &last, s, s_r);
/* Calculate maximum similarity to ectopic sites in the template. */
if (l == OT_RIGHT || l == OT_LEFT) {
if (pa->thermodynamic_template_alignment == 0 && _pr_need_template_mispriming(pa)) {
primer_mispriming_to_template(h, pa, sa, l,
ostats, first,
last, s, s_r, d_align_args);
}
if (pa->thermodynamic_template_alignment == 1 && _pr_need_template_mispriming_thermod(pa)) {
primer_mispriming_to_template_thermod(h, pa, sa, l,
ostats, first,
last, s, s_r, t_align_args);
}
}
}
static int
pair_repeat_sim(primer_pair *h,
const p3_global_settings *pa) {
int i, n, max, w;
primer_rec *fw, *rev;
fw = h->left;
rev = h->right;
max = 0;
n = seq_lib_num_seq(pa->p_args.repeat_lib);
if(n == 0) { return 0; }
h->rep_name = pa->p_args.repeat_lib->names[0] ;
for (i = 0; i < n; i++) {
if ((w = (int) (fw->repeat_sim.score[i] +
rev->repeat_sim.score[i])) > max) {
max = w;
h->rep_name = pa->p_args.repeat_lib->names[i] ;
}
}
return max;
}
static void
set_retval_both_stop_codons(const seq_args_t* sa, p3retval *retval) {
/* The position of the intial base of the rightmost stop codon that
* is to the left of sa->start_codon_pos; valid only if
* sa->start_codon_pos is "not null". We will not want to include
* a stop codon to the right of the the start codon in the
* amplicon. */
retval->upstream_stop_codon = find_stop_codon(sa->trimmed_seq,
sa->start_codon_pos, -1);
retval->upstream_stop_codon += sa->incl_s;
retval->stop_codon_pos = find_stop_codon(sa->trimmed_seq,
sa->start_codon_pos, 1);
retval->stop_codon_pos += sa->incl_s;
}
/*
* 's' is the sequence in which to find the stop codon.
* 'start' is the position of a start codon.
*
* There are two modes depending on 'direction'.
*
* If direction is 1:
*
* Return the index of the first stop codon to the right of
* 'start' in 's' (in same frame).
* If there is no such stop codon return -1.
*
* If direction is -1:
*
* If 'start' is negative then return -1.
* Otherwise return the index the first stop codon to left of 'start'.
* If there is no such stop codon return -1.
*
* Note: we don't insist that the start codon be ATG, since in some
* cases the caller will not have the full sequence in 's', nor even
* know the postion of the start codon relative to s.
*/
static int
find_stop_codon(const char* s,
int start,
int direction) {
const char *p, *q;
int increment = 3 * direction;
int len = (int)strlen(s);
PR_ASSERT(s != NULL);
PR_ASSERT(direction == 1 || direction == -1);
PR_ASSERT(len >= 3);
PR_ASSERT(start <= (len - 3));
if (start < 0) {
if (direction == 1) {
while (start < 0) { start += increment; }
} else {
return -1;
}
}
for (p = &s[start];
p >= &s[0]
&& *p
&& *(p + 1)
&& *(p + 2);
p += increment) {
if ('T' != *p && 't' != *p) { continue; }
q = p + 1;
if ('A' == *q || 'a' == *q) {
q++;
if ('G' == *q || 'g' == *q || 'A' == *q || 'a' == *q) {
return (int)(p - &s[0]);
}
} else if ('G' == *q || 'g' == *q) {
q++;
if ('A' == *q || 'a' == *q) {
return (int)(p - &s[0]);
}
}
}
return -1;
}
int
strcmp_nocase(const char *s1, const char *s2)
{
static char M[UCHAR_MAX];
static int f = 0;
int i;
const char *p, *q;
if(f != 1){
for(i = 0; i < UCHAR_MAX; i++) M[i] = i;
i = 'a'; M[i] = 'A'; i = 'b'; M[i] = 'B'; i = 'c'; M[i] = 'C';
i = 'A'; M[i] = 'a'; i = 'B'; M[i] = 'b'; i = 'C'; M[i] = 'c';
i = 'd'; M[i] = 'D'; i = 'e'; M[i] = 'E'; i = 'f'; M[i] = 'F';
i = 'D'; M[i] = 'd'; i = 'E'; M[i] = 'e'; i = 'F'; M[i] = 'f';
i = 'g'; M[i] = 'G'; i = 'h'; M[i] = 'H'; i = 'i'; M[i] = 'I';
i = 'G'; M[i] = 'g'; i = 'H'; M[i] = 'h'; i = 'I'; M[i] = 'i';
i = 'k'; M[i] = 'K'; i = 'l'; M[i] = 'L'; i = 'm'; M[i] = 'M';
i = 'K'; M[i] = 'k'; i = 'L'; M[i] = 'l'; i = 'M'; M[i] = 'm';
i = 'n'; M[i] = 'N'; i = 'o'; M[i] = 'O'; i = 'p'; M[i] = 'P';
i = 'N'; M[i] = 'n'; i = 'O'; M[i] = 'o'; i = 'P'; M[i] = 'p';
i = 'q'; M[i] = 'Q'; i = 'r'; M[i] = 'R'; i = 's'; M[i] = 'S';
i = 'Q'; M[i] = 'q'; i = 'R'; M[i] = 'r'; i = 'S'; M[i] = 's';
i = 't'; M[i] = 'T'; i = 'u'; M[i] = 'U'; i = 'v'; M[i] = 'V';
i = 'T'; M[i] = 't'; i = 'U'; M[i] = 'u'; i = 'V'; M[i] = 'v';
i = 'w'; M[i] = 'W'; i = 'x'; M[i] = 'X'; i = 'y'; M[i] = 'Y';
i = 'W'; M[i] = 'w'; i = 'X'; M[i] = 'x'; i = 'Y'; M[i] = 'y';
i = 'z'; M[i] = 'Z'; i = 'Z'; M[i] = 'z'; i = 'j'; M[i] = 'J';
i = 'J'; M[i] = 'j';
f = 1;
}
if(s1 == NULL || s2 == NULL) { return 1; }
if((int)strlen(s1) != (int)strlen(s2)) { return 1; }
p = s1; q = s2;
while(*p != '\0' && *p != '\n' && *q != '\0' && *q != '\n') {
i = *p;
if(*p == *q || M[i] == *q ) {p++; q++; continue;}
return 1;
}
return 0;
}
static void
free_repeat_sim_score(p3retval *state)
{
int i;
for (i = 0; i < state->fwd.num_elem; i++) {
if (state->fwd.oligo[i].repeat_sim.score != NULL) {
free(state->fwd.oligo[i].repeat_sim.score);
state->fwd.oligo[i].repeat_sim.score = NULL;
}
}
for (i = 0; i < state->rev.num_elem; i++) {
if (state->rev.oligo[i].repeat_sim.score != NULL) {
free(state->rev.oligo[i].repeat_sim.score);
state->rev.oligo[i].repeat_sim.score = NULL;
}
}
for (i = 0; i < state->intl.num_elem; i++) {
if (state->intl.oligo[i].repeat_sim.score != NULL) {
free(state->intl.oligo[i].repeat_sim.score);
state->intl.oligo[i].repeat_sim.score = NULL;
}
}
}
static void
free_primer_repeat_sim_score(primer_rec *h)
{
if (h->repeat_sim.score != NULL) {
free(h->repeat_sim.score);
h->repeat_sim.score = NULL;
}
}
/*
Edited by T. Koressaar for lowercase masking. This function checks
if the 3' end of the primer has been masked by lowercase letter.
Function created/Added by Eric Reppo, July 9, 2002
*/
static int
is_lowercase_masked(int position,
const char *sequence,
primer_rec *h,
oligo_stats *global_oligo_stats)
{
const char* p = &sequence[position];
if ('a' == *p || 'c' == *p ||'g' == *p || 't' == *p) {
op_set_overlaps_masked_sequence(h);
global_oligo_stats->gmasked++;
return 1;
}
return 0;
}
/*
Edited by A. Untergasser
*/
static int
primer_must_match(const p3_global_settings *pa, primer_rec *h, oligo_stats *global_oligo_stats,
/* This is 5'->3' on the template sequence: */
const char *input_oligo_seq, char *match_three_prime, char *match_five_prime)
{
const char *seq;
char *test;
int length = h->length - 5;
if (match_five_prime != NULL) {
int i;
seq = input_oligo_seq;
test = match_five_prime;
for (i = 0; i < 5; i++) {
if (!compare_nucleotides(*seq, *test)) {
global_oligo_stats->must_match_fail++;
return 1;
}
seq++;
test++;
}
}
if (match_three_prime != NULL) {
int i;
seq = input_oligo_seq;
test = match_three_prime;
seq = seq + length;
for (i = 0; i < 5; i++) {
if (!compare_nucleotides(*seq, *test)) {
global_oligo_stats->must_match_fail++;
return 1;
}
seq++;
test++;
}
}
return 0;
}
/* For a [NACTG] is allowed, for b [NACTGRYWSMKBHDV].*/
static int compare_nucleotides(const char a, const char b)
{
char x = a;
char y = b;
/* Convert to uppercase */
if(a >= 'a' && a <= 'z') {
x = ('A' + a - 'a');
}
if(b >= 'a' && b <= 'z') {
y = ('A' + b - 'a');
}
if ( x == y ) {
return 1;
}
if (( x == 'N') || (y == 'N')) {
return 1;
}
if (x == 'A') {
if ((y == 'R') || (y == 'W') || (y == 'M') ||
(y == 'H') || (y == 'D') || (y == 'V')) {
return 1;
}
}
if (x == 'G') {
if ((y == 'R') || (y == 'S') || (y == 'K') ||
(y == 'B') || (y == 'D') || (y == 'V')){
return 1;
}
}
if (x == 'C') {
if ((y == 'Y') || (y == 'S') || (y == 'M') ||
(y == 'B') || (y == 'H') || (y == 'V')) {
return 1;
}
}
if (x == 'T') {
if ((y == 'Y') || (y == 'W') || (y == 'K') ||
(y == 'B') || (y == 'H') || (y == 'D')) {
return 1;
}
}
return 0;
}
static int test_must_match_parameters(char *test)
{
int i = 0;
char x;
while (*test != '\0') {
/* First to UPPER letters */
if ((*test >= 'a') && (*test <= 'z')) {
x = ('A' + (*test) - 'a');
} else {
x = *test;
}
/* Second check that it is in Range A-Z */
if ((x < 'A') || (x > 'Z')){
return 1;
}
/* Check it is NACTGRYWSMKBHDV */
if ((x == 'N') ||
(x == 'A') || (x == 'C') ||
(x == 'T') || (x == 'G') ||
(x == 'R') || (x == 'Y') ||
(x == 'W') || (x == 'S') ||
(x == 'M') || (x == 'K') ||
(x == 'B') || (x == 'H') ||
(x == 'D') || (x == 'V'))
{
test++;
i++;
} else {
return 1;
}
}
/* Check it is 5 letters */
if (i != 5) {
return 1;
}
return 0;
}
/* Put substring of seq starting at n with length m into s. */
void
_pr_substr(const char *seq, int n, int m, char *s)
{
int i;
for(i = n;i < n + m; i++) { s[i-n]=seq[i]; }
s[m] = '\0';
}
/* Put substring of seq starting at n with length m into s from p on. */
void
_pr_shift_substr(const char *seq, int n, int m, int p, char *s)
{
int i;
for(i=n;i= seq) {
switch (*p)
{
case 'A': *q = 'T'; break;
case 'C': *q = 'G'; break;
case 'G': *q = 'C'; break;
case 'T': *q = 'A'; break;
case 'U': *q = 'A'; break;
case 'B': *q = 'V'; break;
case 'D': *q = 'H'; break;
case 'H': *q = 'D'; break;
case 'V': *q = 'B'; break;
case 'R': *q = 'Y'; break;
case 'Y': *q = 'R'; break;
case 'K': *q = 'M'; break;
case 'M': *q = 'K'; break;
case 'S': *q = 'S'; break;
case 'W': *q = 'W'; break;
case 'N': *q = 'N'; break;
case 'a': *q = 't'; break;
case 'c': *q = 'g'; break;
case 'g': *q = 'c'; break;
case 't': *q = 'a'; break;
case 'u': *q = 'a'; break;
case 'b': *q = 'v'; break;
case 'd': *q = 'h'; break;
case 'h': *q = 'd'; break;
case 'v': *q = 'b'; break;
case 'r': *q = 'y'; break;
case 'y': *q = 'r'; break;
case 'k': *q = 'm'; break;
case 'm': *q = 'k'; break;
case 's': *q = 's'; break;
case 'w': *q = 'w'; break;
case 'n': *q = 'n'; break;
}
p--; q++;
}
*q = '\0';
}
int
_pr_need_template_mispriming(const p3_global_settings *pa) {
return
pa->p_args.max_template_mispriming >= 0
|| pa->p_args.weights.template_mispriming > 0.0
|| _pr_need_pair_template_mispriming(pa);
}
int
_pr_need_template_mispriming_thermod(const p3_global_settings *pa) {
return
pa->p_args.max_template_mispriming_th >= 0
|| pa->p_args.weights.template_mispriming_th > 0.0
|| _pr_need_pair_template_mispriming_thermod(pa);
}
int
_pr_need_pair_template_mispriming(const p3_global_settings *pa)
{
return
pa->pair_max_template_mispriming >= 0
|| pa->pr_pair_weights.template_mispriming > 0.0;
}
int
_pr_need_pair_template_mispriming_thermod(const p3_global_settings *pa)
{
return
pa->pair_max_template_mispriming_th >= 0
|| pa->pr_pair_weights.template_mispriming_th > 0.0;
}
/* Upcase a DNA string, s, in place. If amibiguity_code_ok is false,
then the characters acgtnACGTN are 'recognized' and upcased. If
ambiguity_code_ok is true, then the IUB/IUPAC ambiguity codes are
also 'recognized' and upcased.
Change any unrecognized letters in *s to 'N"
Return the first unrecognized letter, if
any, that is seen. Otherwise return '\0'. */
static char
dna_to_upper(char * s, int ambiguity_code_ok)
{
char *p = s;
int unrecognized_base = '\0';
while (*p) {
switch (*p) {
case 'a': case 'A': *p='A'; break;
case 'c': case 'C': *p='C'; break;
case 'g': case 'G': *p='G'; break;
case 't': case 'T': *p='T'; break;
case 'n': case 'N': *p='N'; break;
default:
if (ambiguity_code_ok) {
switch (*p) {
case 'r': case 'R': *p = 'R'; break;
case 'y': case 'Y': *p = 'Y'; break;
case 'm': case 'M': *p = 'M'; break;
case 'w': case 'W': *p = 'W'; break;
case 's': case 'S': *p = 'S'; break;
case 'k': case 'K': *p = 'K'; break;
case 'd': case 'D': *p = 'D'; break;
case 'h': case 'H': *p = 'H'; break;
case 'v': case 'V': *p = 'V'; break;
case 'b': case 'B': *p = 'B'; break;
}
} else {
if (!unrecognized_base) { unrecognized_base = *p; }
*p = 'N';
}
break;
}
p++;
}
return unrecognized_base;
}
static char *
strstr_nocase(char *s1, char *s2) {
int n1, n2;
char *p, q, *tmp;
if(s1 == NULL || s2 == NULL) { return NULL; }
n1 = (int)strlen(s1);
n2 = (int)strlen(s2);
if(n1 < n2) { return NULL; }
tmp = (char *) pr_safe_malloc(n1 + 1);
strcpy(tmp, s1);
q = *tmp; p = tmp;
while(q != '\0' && q != '\n') {
q = *(p + n2);
*(p + n2) = '\0';
if(strcmp_nocase(p, s2)) {
*(p + n2) = q;
p++;
continue;
} else {
if (tmp != NULL) free(tmp);
return p;
}
}
if (tmp != NULL) free(tmp);
return NULL;
}
#define CHECK if (r > bsize || r < 0) return "Internal error, not enough space for \"explain\" string"; bufp += r; bsize -= r
#define SP_AND_CHECK(FMT, VAL) { r = sprintf(bufp, FMT, VAL); CHECK; }
#define IF_SP_AND_CHECK(FMT, VAL) { if (VAL) { SP_AND_CHECK(FMT, VAL) } }
const char *
p3_pair_explain_string(const pair_stats *pair_expl)
{
/* WARNING WARNING WARNING
Static, fixed-size buffer. If you add more calls to SP_AND_CHECK or
IF_SP_AND_CHECK, you need to make sure the buffer cannot overflow.
*/
static char buf[10000];
char *bufp = buf;
size_t bsize = 10000;
size_t r;
SP_AND_CHECK("considered %d", pair_expl->considered)
IF_SP_AND_CHECK(", no target %d", pair_expl->target)
IF_SP_AND_CHECK(", unacceptable product size %d", pair_expl->product)
IF_SP_AND_CHECK(", low product Tm %d", pair_expl->low_tm)
IF_SP_AND_CHECK(", high product Tm %d", pair_expl->high_tm)
IF_SP_AND_CHECK(", tm diff too large %d",pair_expl->temp_diff)
IF_SP_AND_CHECK(", high any compl %d", pair_expl->compl_any)
IF_SP_AND_CHECK(", high end compl %d", pair_expl->compl_end)
IF_SP_AND_CHECK(", no internal oligo %d", pair_expl->internal)
IF_SP_AND_CHECK(", high mispriming library similarity %d",
pair_expl->repeat_sim)
IF_SP_AND_CHECK(", no overlap of required point %d",
pair_expl->does_not_overlap_a_required_point)
IF_SP_AND_CHECK(", primer in pair overlaps a primer in a better pair %d",
pair_expl->overlaps_oligo_in_better_pair)
IF_SP_AND_CHECK(", high template mispriming score %d",
pair_expl->template_mispriming)
IF_SP_AND_CHECK(", not in any ok region %d",
pair_expl->not_in_any_ok_region);
IF_SP_AND_CHECK(", left primer to right of right primer %d",
pair_expl->reversed);
SP_AND_CHECK(", ok %d", pair_expl->ok)
return buf;
}
const char *
p3_oligo_explain_string(const oligo_stats *stat)
{
/* WARNING WARNING WARNING
Static, fixed-size buffer. If you add more calls to SP_AND_CHECK or
IF_SP_AND_CHECK, you need to make sure the buffer cannot overflow.
*/
static char buf[10000];
char *bufp = buf;
size_t bsize = 10000;
size_t r;
IF_SP_AND_CHECK("sequencing locations %d, ", stat->sequencing_location)
SP_AND_CHECK("considered %d", stat->considered)
IF_SP_AND_CHECK(", would not amplify any of the ORF %d", stat->no_orf)
IF_SP_AND_CHECK(", too many Ns %d", stat->ns)
IF_SP_AND_CHECK(", overlap target %d", stat->target)
IF_SP_AND_CHECK(", overlap excluded region %d", stat->excluded)
IF_SP_AND_CHECK(", GC content failed %d", stat->gc)
IF_SP_AND_CHECK(", GC clamp failed %d", stat->gc_clamp)
IF_SP_AND_CHECK(", low tm %d", stat->temp_min)
IF_SP_AND_CHECK(", high tm %d", stat->temp_max)
IF_SP_AND_CHECK(", low faction bound %d", stat->bound_min)
IF_SP_AND_CHECK(", high fraction bound %d", stat->bound_max)
IF_SP_AND_CHECK(", high any compl %d", stat->compl_any)
IF_SP_AND_CHECK(", high end compl %d", stat->compl_end)
IF_SP_AND_CHECK(", high hairpin stability %d", stat->hairpin_th)
IF_SP_AND_CHECK(", high repeat similarity %d", stat->repeat_score)
IF_SP_AND_CHECK(", long poly-x seq %d", stat->poly_x)
IF_SP_AND_CHECK(", low sequence quality %d", stat->seq_quality)
IF_SP_AND_CHECK(", high 3' stability %d", stat->stability)
IF_SP_AND_CHECK(", high template mispriming score %d",
stat->template_mispriming)
IF_SP_AND_CHECK(", lowercase masking of 3' end %d",stat->gmasked)
IF_SP_AND_CHECK(", failed must_match requirements %d",stat->must_match_fail)
IF_SP_AND_CHECK(", not in any ok left region %d",
stat->not_in_any_left_ok_region)
IF_SP_AND_CHECK(", not in any ok right region %d",
stat->not_in_any_right_ok_region)
IF_SP_AND_CHECK(", no overlap of required point %d",
stat->does_not_overlap_a_required_point)
SP_AND_CHECK(", ok %d", stat->ok)
return buf;
}
#undef CHECK
#undef SP_AND_CHECK
#undef IF_SP_AND_CHEC
const char *
p3_get_oligo_array_explain_string(const oligo_array *oligo_array)
{
return p3_oligo_explain_string(&oligo_array->expl);
}
const char *
p3_get_pair_array_explain_string(const pair_array_t *pair_array)
{
return p3_pair_explain_string(&pair_array->expl);
}
const char *
libprimer3_release(void)
{
return "libprimer3 release 2.6.1";
}
const char *
primer3_copyright(void)
{
return primer3_copyright_char_star;
}
/* ============================================================ */
/* BEGIN Internal and external functions for pr_append_str */
/* ============================================================ */
void
init_pr_append_str(pr_append_str *s)
{
s->data = NULL;
s->storage_size = 0;
}
const char *
pr_append_str_chars(const pr_append_str *x)
{
return x->data;
}
pr_append_str *
create_pr_append_str()
{
/* We cannot use pr_safe_malloc here
because this function will be called outside
of the setjmp(....) */
pr_append_str *ret;
ret = (pr_append_str *) malloc(sizeof(pr_append_str));
if (NULL == ret) { return NULL; }
init_pr_append_str(ret);
return ret;
}
void
destroy_pr_append_str_data(pr_append_str *str)
{
if (NULL == str) { return; }
if (str->data != NULL) {
free(str->data);
str->data = NULL;
}
}
void
destroy_pr_append_str(pr_append_str *str)
{
if (str == NULL) { return; }
destroy_pr_append_str_data(str);
free(str);
str = NULL;
}
int
pr_append_external(pr_append_str *x, const char *s)
{
int xlen, slen;
PR_ASSERT(NULL != s);
PR_ASSERT(NULL != x);
if (NULL == x->data) {
x->storage_size = 24;
x->data = (char *) malloc(x->storage_size);
if (NULL == x->data) { return 1; } /* out of memory */
*x->data = '\0';
}
xlen = (int)strlen(x->data);
slen = (int)strlen(s);
if (xlen + slen + 1 > x->storage_size) {
x->storage_size += 2 * (slen + 1);
x->data = (char *) realloc(x->data, x->storage_size);
if (NULL == x->data) { return 1; } /* out of memory */
}
strcpy(x->data + xlen, s);
return 0;
}
static void
pr_append_new_chunk(pr_append_str *x, const char *s)
{
PR_ASSERT(NULL != x)
if (NULL == s) { return; }
pr_append_w_sep(x, "; ", s);
}
int
pr_append_new_chunk_external(pr_append_str *x, const char *s)
{
PR_ASSERT(NULL != x)
if (NULL == s) { return 0; }
return(pr_append_w_sep_external(x, "; ", s));
}
int
pr_append_w_sep_external(pr_append_str *x,
const char *sep,
const char *s)
{
PR_ASSERT(NULL != x)
PR_ASSERT(NULL != s)
PR_ASSERT(NULL != sep)
if (pr_is_empty(x)) {
return(pr_append_external(x, s));
} else {
return (pr_append_external(x, sep) || pr_append_external(x, s));
}
}
void
pr_set_empty(pr_append_str *x)
{
PR_ASSERT(NULL != x);
if (NULL != x->data) { *x->data = '\0'; }
}
int
pr_is_empty( const pr_append_str *x)
{
PR_ASSERT(NULL != x);
return NULL == x->data || '\0' == *x->data;
}
static void
pr_append_w_sep(pr_append_str *x,
const char *sep,
const char *s)
{
if (pr_append_w_sep_external(x, sep, s)) { longjmp(_jmp_buf, 1); }
}
static void
pr_append(pr_append_str *x,
const char *s)
{
if (pr_append_external(x, s)) { longjmp(_jmp_buf, 1); }
}
/* ============================================================ */
/* END internal and external functions for pr_append_str */
/* ============================================================ */
/* =========================================================== */
/* Malloc and realloc wrappers that longjmp() on failure */
/* =========================================================== */
static void *
pr_safe_malloc(size_t x)
{
void *r = malloc(x);
if (NULL == r) { longjmp(_jmp_buf, 1); }
return r;
}
static void *
pr_safe_realloc(void *p, size_t x)
{
void *r = realloc(p, x);
if (NULL == r) { longjmp(_jmp_buf, 1); }
return r;
}
/* =========================================================== */
/* End of malloc/realloc wrappers. */
/* =========================================================== */
/* ============================================================ */
/* START functions which check and modify the input */
/* ============================================================ */
/* Fuction to set the included region and fix the start positions */
static void
_adjust_seq_args(const p3_global_settings *pa,
seq_args_t* sa,
pr_append_str *nonfatal_err,
pr_append_str *warning)
{
int seq_len, inc_len, overhang_len;
/* Subtract the overhang from PRIMER_PRODUCT_SIZE_RANGE */
/* Create a seq for check primers if needed */
if (pa->primer_task == check_primers) {
if (NULL == sa->sequence) {
fake_a_sequence(sa, pa);
}
}
if (pa->primer_task == pick_sequencing_primers && sa->incl_l != -1) {
pr_append_new_chunk(nonfatal_err,
"Task pick_sequencing_primers cannot be combined with included region");
return;
}
/*
Complain if there is no sequence; We need to check this
error here, because this function cannot do its work if
sa->sequence == NULL
*/
if (NULL == sa->sequence) {
if (pa->primer_task == check_primers) {
pr_append_new_chunk(nonfatal_err, "No primers provided");
} else {
pr_append_new_chunk(nonfatal_err, "Missing SEQUENCE tag");
}
return;
}
/* Calculate once for all the reverse complement of the overhang_right */
if (NULL != sa->overhang_right) {
overhang_len = strlen(sa->overhang_right);
sa->overhang_right_rv = (char *) pr_safe_malloc(overhang_len + 1);
memset(sa->overhang_right_rv, '\0', overhang_len + 1);
p3_reverse_complement(sa->overhang_right, sa->overhang_right_rv);
}
seq_len = (int)strlen(sa->sequence);
/* For pick_cloning_primers set the forced positions */
if (pa->primer_task == pick_cloning_primers) {
if(sa->incl_l == -1) {
sa->force_left_start = pa->first_base_index;
sa->force_right_start = seq_len + pa->first_base_index - 1;
} else {
sa->force_left_start = sa->incl_s;
sa->force_right_start = sa->incl_s + sa->incl_l - 1;
}
}
/* For pick_discriminative_primers set the forced positions */
if (pa->primer_task == pick_discriminative_primers) {
/* Changed here from incl_s and incl_l to sa->tar2->pairs[0][0/1] */
if (sa->tar2.count != 1) {
pr_append_new_chunk(nonfatal_err,
"Task pick_discriminative_primers requires exactly one SEQUENCE_TARGET");
}
sa->force_left_end = sa->tar2.pairs[0][0] - 1;
sa->force_right_end = sa->tar2.pairs[0][0] + sa->tar2.pairs[0][1];
}
/* If no included region is specified,
* use the whole sequence as included region */
if (sa->incl_l == -1) {
sa->incl_l = seq_len;
sa->incl_s = pa->first_base_index;
}
/* Generate at least one target */
if (pa->primer_task == pick_sequencing_primers && sa->tar2.count == 0) {
sa->tar2.pairs[0][0] = pa->first_base_index;
sa->tar2.pairs[0][1] = seq_len;
sa->tar2.count = 1;
}
/* Fix the start of the included region and start codon */
sa->incl_s -= pa->first_base_index;
sa->start_codon_pos -= pa->first_base_index;
/* Fix the start */
sa->force_left_start -= pa->first_base_index;
sa->force_left_end -= pa->first_base_index;
sa->force_right_start -= pa->first_base_index;
sa->force_right_end -= pa->first_base_index;
/* Make it relative to included region */
sa->force_left_start -= sa->incl_s;
sa->force_left_end -= sa->incl_s;
sa->force_right_start -= sa->incl_s;
sa->force_right_end -= sa->incl_s;
inc_len = sa->incl_s + sa->incl_l - 1;
if ((sa->incl_l < INT_MAX) && (sa->incl_s > -1)
&& (sa->incl_l > -1) && (inc_len < seq_len) ) {
/* Copies inluded region into trimmed_seq */
sa->trimmed_seq = (char *) pr_safe_malloc(sa->incl_l + 1);
_pr_substr(sa->sequence, sa->incl_s, sa->incl_l, sa->trimmed_seq);
/* Copies inluded region into trimmed_orig_seq */
/* edited by T. Koressaar for lowercase masking */
sa->trimmed_orig_seq = (char *) pr_safe_malloc(sa->incl_l + 1);
_pr_substr(sa->sequence, sa->incl_s, sa->incl_l, sa->trimmed_orig_seq);
#if !defined(OS_WIN)
/* Masks original trimmed sequence */
/* edited by M. Lepamets */
if (pa->mask_template && (pa->pick_left_primer == 1 && pa->pick_right_primer == 1)) {
input_sequence *input_seq;
output_sequence *output_seq;
input_seq = create_input_sequence_from_string (sa->trimmed_orig_seq, nonfatal_err);
output_seq = create_output_sequence ((unsigned long long) sa->incl_l, pa->mp.mdir, nonfatal_err);
read_and_mask_sequence (input_seq, output_seq, &pa->mp, nonfatal_err, 0);
if (output_seq->sequence) {
if (pa->mp.mdir == fwd) {
sa->trimmed_masked_seq = (char *) pr_safe_malloc(sa->incl_l + 1);
strcpy (sa->trimmed_masked_seq, output_seq->sequence);
} else if (pa->mp.mdir == rev) {
sa->trimmed_masked_seq_r = (char *) pr_safe_malloc(sa->incl_l + 1);
strcpy (sa->trimmed_masked_seq_r, output_seq->sequence);
}
} else {
sa->trimmed_masked_seq = (char *) pr_safe_malloc(sa->incl_l + 1);
strcpy (sa->trimmed_masked_seq, output_seq->sequence_fwd);
sa->trimmed_masked_seq_r = (char *) pr_safe_malloc(sa->incl_l + 1);
strcpy (sa->trimmed_masked_seq_r, output_seq->sequence_rev);
}
delete_input_sequence (input_seq);
delete_output_sequence (output_seq);
}
#endif
/* Copies the whole sequence into upcased_seq */
sa->upcased_seq = (char *) pr_safe_malloc((int)strlen(sa->sequence) + 1);
strcpy(sa->upcased_seq, sa->sequence);
dna_to_upper(sa->upcased_seq, 1);
/* We do not need to check for illegal characters in the return
from dna_to_upper(), because errors are checked in
_pr_data_control sa->trimmed_seq. */
/* Copies the reverse complement of the whole sequence into upcased_seq_r */
sa->upcased_seq_r = (char *) pr_safe_malloc((int)strlen(sa->sequence) + 1);
p3_reverse_complement(sa->upcased_seq, sa->upcased_seq_r);
}
if (_check_and_adjust_intervals(sa,
seq_len,
pa->first_base_index,
nonfatal_err, warning)) {
return;
}
if (_check_and_adjust_overlap_pos(sa,
sa->primer_overlap_junctions,
&sa->primer_overlap_junctions_count,
"SEQUENCE_OVERLAP_JUNCTION_LIST",
seq_len,
pa->first_base_index,
nonfatal_err, warning)) {
return;
}
if (_check_and_adjust_overlap_pos(sa,
sa->intl_overlap_junctions,
&sa->intl_overlap_junctions_count,
"SEQUENCE_INTERNAL_OVERLAP_JUNCTION_LIST",
seq_len,
pa->first_base_index,
nonfatal_err, warning)) {
return;
}
/* Update ok regions, if non empty */
if (sa->ok_regions.count > 0) {
_optimize_ok_regions_list(pa, sa);
}
}
/*
* This function uses the max/min product size info and the max/min
* oligo length in order to reduce the ranges of the ok regions. On
* some imputs this improves speed dramatically.
*/
static void
_optimize_ok_regions_list(const p3_global_settings *pa,
seq_args_t* sa)
{
int pmin = INT_MAX;
int pmax = 0;
int omin = pa->p_args.min_size;
int omax = pa->p_args.max_size;
int i;
/* We do this only if we enabled the optimization and
* the primers were NOT specified. */
if (!OPTIMIZE_OK_REGIONS || (sa->left_input) || (sa->right_input)) {
return;
}
/* If any pair is allowed, no point in doing this */
if (sa->ok_regions.any_pair) {
return;
}
/* Determine min/max product size */
for (i=0; i < pa->num_intervals; i++) {
if (pa->pr_min[i] < pmin) { pmin = pa->pr_min[i]; }
if (pa->pr_max[i] > pmax) { pmax = pa->pr_max[i]; }
}
/* Update each region */
for (i=0; iok_regions.count; i++) {
int ls = -1, le = -1, rs = -1, re = -1;
int new_ls = -1, new_le = -1, new_rs = -1, new_re = -1;
if (sa->ok_regions.left_pairs[i][0] != -1) {
ls = sa->ok_regions.left_pairs[i][0];
le = sa->ok_regions.left_pairs[i][0]
+ sa->ok_regions.left_pairs[i][1] - 1;
}
if (sa->ok_regions.right_pairs[i][0] != -1) {
rs = sa->ok_regions.right_pairs[i][0];
re = sa->ok_regions.right_pairs[i][0]
+ sa->ok_regions.right_pairs[i][1] - 1;
}
/* Compute new right region based on left range and min/max values
of product size and oligo length */
if (ls != -1) {
new_rs = ls + pmin - omax - 1; /* -1 just to be safe */
new_re = le - omin + pmax + 1; /* +1 just to be safe */
/* Adjust the ranges */
if ((rs == -1) || (new_rs > rs)) { rs = new_rs; }
if ((re == -1) || (new_re < re)) { re = new_re; }
if (rs < 0) { rs = 0; }
if (re > (signed) (int)strlen(sa->sequence)) { re = (int)strlen(sa->sequence); }
}
/* Compute new left region based on right range and min/max values
of product size and oligo length */
if (rs != -1) {
new_ls = rs + omin - pmax - 1; /* -1 just to be safe */
new_le = re - pmin + omax + 1; /* +1 just to be safe */
/* Adjust the ranges */
if ((ls == -1) || (new_ls > ls)) { ls = new_ls; }
if ((le == -1) || (new_le < le)) { le = new_le; }
if (ls < 0) { ls = 0; }
if (le > (signed) (int)strlen(sa->sequence)) { le = (int)strlen(sa->sequence); }
}
/* Temporary testing fprintf: */
/* fprintf(stderr, "Adjusted range [%d,%d,%d,%d] to [%d,%d,%d,%d],
pmin is %d, pmax is %d, omin is %d, omax is %d\n",
sa->ok_regions.left_pairs[i][0],
sa->ok_regions.left_pairs[i][0] +
sa->ok_regions.left_pairs[i][1] - 1,
sa->ok_regions.right_pairs[i][0],
sa->ok_regions.right_pairs[i][0] +
sa->ok_regions.right_pairs[i][1] - 1, ls, le, rs, re,
pmin, pmax, omin, omax);
*/
sa->ok_regions.left_pairs[i][0] = ls;
sa->ok_regions.left_pairs[i][1] = le - ls + 1;
sa->ok_regions.right_pairs[i][0] = rs;
sa->ok_regions.right_pairs[i][1] = re - rs + 1;
}
/* any_left and any_right not true anymore */
sa->ok_regions.any_left = 0;
sa->ok_regions.any_right = 0;
}
/*
* Return 1 on error, 0 on success. fake_a_sequence creates a sequence
* out of the provided primers and puts them in sa.
*/
static int
fake_a_sequence(seq_args_t* sa, const p3_global_settings *pa)
{
int i, product_size, space, ns_to_fill;
char *rev = NULL;
int ns_to_fill_first, ns_to_fill_second;
/* Determine the product size */
if ((pa->product_opt_size < 1) || (pa->product_opt_size == PR_UNDEFINED_INT_OPT)){
product_size = pa->pr_max[0] - pa->pr_min[0];
} else {
product_size = pa->product_opt_size;
}
space = product_size + 1;
ns_to_fill = product_size;
/* Calculate how many Ns have to be added */
if (sa->left_input) {
ns_to_fill = ns_to_fill - (int)strlen(sa->left_input);
}
if (sa->right_input) {
ns_to_fill = ns_to_fill - (int)strlen(sa->right_input);
rev = (char *) pr_safe_malloc((int)strlen(sa->right_input) + 1);
p3_reverse_complement(sa->right_input, rev);
}
if (sa->internal_input) {
ns_to_fill = ns_to_fill - (int)strlen(sa->internal_input);
}
/* Return if there are no primers provided */
if (ns_to_fill == product_size + 1){
return 0;
}
ns_to_fill_first = ns_to_fill / 2;
ns_to_fill_second = ns_to_fill - ns_to_fill_first;
/* Allocate the space for the sequence */
sa->sequence = (char *) pr_safe_malloc(space);
*sa->sequence = '\0';
/* Copy over the primers */
if (sa->left_input){
strcat(sa->sequence, sa->left_input);
}
/* Add the Ns*/
for (i = 0; i < ns_to_fill_first; i++ ) {
strcat(sa->sequence, "N\0");
}
if (sa->internal_input){
strcat(sa->sequence, sa->internal_input);
}
for (i = 0; i < ns_to_fill_second; i++ ) {
strcat(sa->sequence, "N\0");
}
if (sa->right_input){
strcat(sa->sequence, rev);
}
if (rev != NULL) {
free(rev);
rev = NULL;
}
return 0;
}
/*
* Return 1 on error, 0 on success. Set sa->trimmed_seq and possibly modify
* sa->tar. Upcase and check all bases in sa->trimmed_seq.
* TO DO -- this would probably be cleaner if it only
* checked, rather than updated, sa.
*/
/* Check if the input in sa and pa makes sense */
int
_pr_data_control(const p3_global_settings *pa,
const seq_args_t* sa,
pr_append_str *glob_err,
pr_append_str *nonfatal_err,
pr_append_str *warning)
{
static char s1[MAX_PRIMER_LENGTH+1];
int i, pr_min, seq_len, overhang_left_len, overhang_right_len;
char offending_char = '\0';
overhang_left_len = 0;
overhang_right_len = 0;
seq_len = (int)strlen(sa->sequence);
/* The overhang from PRIMER_PRODUCT_SIZE_RANGE is subtracted
in adjust_seq_args() */
/* If sequence quality is provided, is it as long as the sequence? */
if (sa->n_quality !=0 && sa->n_quality != seq_len) {
pr_append_new_chunk(nonfatal_err,
"Error in sequence quality data");
}
if ((pa->min_left_three_prime_distance < -1) ||
(pa->min_internal_three_prime_distance < -1) ||
(pa->min_right_three_prime_distance < -1))
pr_append_new_chunk(nonfatal_err,
"Minimum 3' distance must be >= -1 "
"(min_*_three_prime_distance)");
if ((pa->p_args.min_quality != 0 || pa->o_args.min_quality != 0)
&& sa->n_quality == 0)
pr_append_new_chunk(nonfatal_err, "Sequence quality data missing");
if (pa->first_base_index < PR_NULL_FORCE_POSITION) {
pr_append_new_chunk(glob_err, "Value too small at tag PRIMER_FIRST_BASE_INDEX");
return 1;
}
if (pa->p_args.max_template_mispriming > SHRT_MAX && pa->thermodynamic_template_alignment == 0) {
pr_append_new_chunk(glob_err, "Value too large at tag PRIMER_MAX_TEMPLATE_MISPRIMING");
return 1;
}
if (pa->pair_max_template_mispriming > SHRT_MAX && pa->thermodynamic_template_alignment == 0) {
pr_append_new_chunk(glob_err, "Value too large at tag PRIMER_PAIR_MAX_TEMPLATE_MISPRIMING");
return 1;
}
if (pa->p_args.max_repeat_compl > SHRT_MAX && pa->thermodynamic_oligo_alignment == 0) {
pr_append_new_chunk(glob_err, "Value too large at tag PRIMER_MAX_LIBRARY_MISPRIMING");
return 1;
}
if (pa->o_args.max_repeat_compl > SHRT_MAX && pa->thermodynamic_oligo_alignment == 0) {
pr_append_new_chunk(glob_err, "Value too large at tag PRIMER_INTERNAL_MAX_LIBRARY_MISHYB");
return 1;
}
if (pa->pair_repeat_compl > SHRT_MAX && pa->thermodynamic_oligo_alignment == 0) {
pr_append_new_chunk(glob_err, "Value too large at tag PRIMER_PAIR_MAX_LIBRARY_MISPRIMING");
return 1;
}
if (pa->o_args.max_template_mispriming >= 0 && pa->thermodynamic_template_alignment==0)
pr_append_new_chunk(glob_err,
"PRIMER_INTERNAL_MAX_TEMPLATE_MISHYB is not supported");
if (pa->o_args.max_template_mispriming_th >= 0 && pa->thermodynamic_template_alignment==1)
pr_append_new_chunk(glob_err,
"PRIMER_INTERNAL_MAX_TEMPLATE_MISHYB_TH is not supported");
if (pa->p_args.min_size < 1)
pr_append_new_chunk(glob_err, "PRIMER_MIN_SIZE must be >= 1");
if (pa->p_args.max_size > MAX_PRIMER_LENGTH) {
pr_append_new_chunk(glob_err,
"PRIMER_MAX_SIZE exceeds built-in maximum of ");
pr_append(glob_err, MACRO_VALUE_AS_STRING(MAX_PRIMER_LENGTH));
return 1;
}
if (pa->p_args.opt_size > pa->p_args.max_size) {
pr_append_new_chunk(glob_err,
"PRIMER_{OPT,DEFAULT}_SIZE > PRIMER_MAX_SIZE");
return 1;
}
if (pa->p_args.opt_size < pa->p_args.min_size) {
pr_append_new_chunk(glob_err,
"PRIMER_{OPT,DEFAULT}_SIZE < PRIMER_MIN_SIZE");
return 1;
}
if (pa->o_args.max_size > MAX_PRIMER_LENGTH) {
pr_append_new_chunk(glob_err,
"PRIMER_INTERNAL_MAX_SIZE exceeds built-in maximum");
return 1;
}
if (pa->o_args.opt_size > pa->o_args.max_size) {
pr_append_new_chunk(glob_err,
"PRIMER_INTERNAL_{OPT,DEFAULT}_SIZE > MAX_SIZE");
return 1;
}
if (pa->o_args.opt_size < pa->o_args.min_size) {
pr_append_new_chunk(glob_err,
"PRIMER_INTERNAL_{OPT,DEFAULT}_SIZE < MIN_SIZE");
return 1;
}
/* A GC clamp can not be bigger then the primer */
if (pa->gc_clamp > pa->p_args.min_size) {
pr_append_new_chunk(glob_err,
"PRIMER_GC_CLAMP > PRIMER_MIN_SIZE");
return 1;
}
/* Must be >= 0 and <= 5 */
if ((pa->max_end_gc < 0)
|| (pa->max_end_gc > 5)) {
pr_append_new_chunk(glob_err,
"PRIMER_MAX_END_GC must be between 0 to 5");
return 1;
}
/* Product size must be provided */
if (0 == pa->num_intervals) {
pr_append_new_chunk( glob_err,
"Empty value for PRIMER_PRODUCT_SIZE_RANGE");
return 1;
}
for (i = 0; i < pa->num_intervals; i++) {
if (pa->pr_min[i] > pa->pr_max[i] || pa->pr_min[i] < 0) {
pr_append_new_chunk(glob_err,
"Illegal element in PRIMER_PRODUCT_SIZE_RANGE");
return 1;
}
}
pr_min = INT_MAX;
/* Check if the primer is bigger then the product */
for(i=0;inum_intervals;i++)
if(pa->pr_min[i]pr_min[i];
if (pa->p_args.max_size > pr_min) {
pr_append_new_chunk(glob_err,
"PRIMER_MAX_SIZE > min PRIMER_PRODUCT_SIZE_RANGE");
return 1;
}
if ((pa->pick_internal_oligo == 1 )
&& pa->o_args.max_size > pr_min) {
pr_append_new_chunk(glob_err,
"PRIMER_INTERNAL_MAX_SIZE > min PRIMER_PRODUCT_SIZE_RANGE");
return 1;
}
/* There must be at least one primer returned */
if (pa->num_return < 1) {
pr_append_new_chunk(glob_err,
"PRIMER_NUM_RETURN < 1");
return 1;
}
if ((pa->p_args.must_match_five_prime != NULL) && ((int)strlen(pa->p_args.must_match_five_prime) != 5)) {
pr_append_new_chunk(glob_err,
"PRIMER_MUST_MATCH_FIVE_PRIME must have 5 characters");
return 1;
}
if ((pa->p_args.must_match_three_prime != NULL) && ((int)strlen(pa->p_args.must_match_three_prime) != 5)) {
pr_append_new_chunk(glob_err,
"PRIMER_MUST_MATCH_THREE_PRIME must have 5 characters");
return 1;
}
if ((pa->o_args.must_match_five_prime != NULL) && ((int)strlen(pa->o_args.must_match_five_prime) != 5)) {
pr_append_new_chunk(glob_err,
"PRIMER_INTERNAL_MUST_MATCH_FIVE_PRIME must have 5 characters");
return 1;
}
if ((pa->o_args.must_match_three_prime != NULL) && ((int)strlen(pa->o_args.must_match_three_prime) != 5)) {
pr_append_new_chunk(glob_err,
"PRIMER_INTERNAL_MUST_MATCH_THREE_PRIME must have 5 characters");
return 1;
}
if (sa->incl_l >= INT_MAX) {
pr_append_new_chunk(nonfatal_err, "Value for SEQUENCE_INCLUDED_REGION too large");
return 1;
}
if (sa->incl_s < 0 || sa->incl_l < 0
|| sa->incl_s + sa->incl_l > seq_len) {
pr_append_new_chunk(nonfatal_err, "Illegal value for SEQUENCE_INCLUDED_REGION");
return 1;
}
/* The product must fit in the included region */
if (sa->incl_l < pr_min && pa->pick_left_primer == 1
&& pa->pick_right_primer == 1) {
if (pa->primer_task == check_primers) {
pr_append_new_chunk(warning,
"SEQUENCE_INCLUDED_REGION length < min PRIMER_PRODUCT_SIZE_RANGE");
} else if (pa->primer_task != pick_primer_list) {
pr_append_new_chunk(nonfatal_err,
"SEQUENCE_INCLUDED_REGION length < min PRIMER_PRODUCT_SIZE_RANGE");
}
if (pa->primer_task == generic_p3) {
return 1;
}
}
if (pa->max_end_stability < 0) {
pr_append_new_chunk(nonfatal_err,
"PRIMER_MAX_END_STABILITY must be non-negative");
return 1;
}
/* Is the startodon ATG and in the incl. region */
if (!PR_START_CODON_POS_IS_NULL(sa)) {
if (!PR_POSITION_PENALTY_IS_NULL(pa)) {
pr_append_new_chunk(nonfatal_err,
"Cannot accept both SEQUENCE_START_CODON_POSITION and non-default ");
pr_append(nonfatal_err,
"arguments for PRIMER_INSIDE_PENALTY or PRIMER_OUTSIDE_PENALTY");
}
if (sa->start_codon_pos > (sa->incl_s + sa->incl_l - 3)) {
pr_append_new_chunk(nonfatal_err,
"Start codon position not contained in SEQUENCE_INCLUDED_REGION");
return 1;
} else {
if (sa->start_codon_seq[0] == 'X') {
pr_append_new_chunk(nonfatal_err,
"No codon provided in SEQUENCE_START_CODON_SEQUENCE");
return 1;
}
if (
(sa->start_codon_pos >= 0)
&& (
(toupper(sa->sequence[sa->start_codon_pos]) != sa->start_codon_seq[0])
|| (toupper(sa->sequence[sa->start_codon_pos + 1]) != sa->start_codon_seq[1])
|| (toupper(sa->sequence[sa->start_codon_pos + 2]) != sa->start_codon_seq[2])
)
) {
pr_append_new_chunk(nonfatal_err,
"No start codon at SEQUENCE_START_CODON_POSITION");
return 1;
}
}
}
if (NULL != sa->quality) {
if(pa->p_args.min_quality != 0 && pa->p_args.min_quality < pa->quality_range_min) {
pr_append_new_chunk(glob_err,
"PRIMER_MIN_QUALITY < PRIMER_QUALITY_RANGE_MIN");
return 1;
}
if (pa->p_args.min_quality != 0 && pa->p_args.min_quality > pa->quality_range_max) {
pr_append_new_chunk(glob_err,
"PRIMER_MIN_QUALITY > PRIMER_QUALITY_RANGE_MAX");
return 1;
}
if (pa->o_args.min_quality != 0 && pa->o_args.min_quality quality_range_min) {
pr_append_new_chunk(glob_err,
"PRIMER_INTERNAL_MIN_QUALITY < PRIMER_QUALITY_RANGE_MIN");
return 1;
}
if (pa->o_args.min_quality != 0 && pa->o_args.min_quality > pa->quality_range_max) {
pr_append_new_chunk(glob_err,
"PRIMER_INTERNAL_MIN_QUALITY > PRIMER_QUALITY_RANGE_MAX");
return 1;
}
for(i=0; i < sa->n_quality; i++) {
if(sa->quality[i] < pa->quality_range_min ||
sa->quality[i] > pa->quality_range_max) {
pr_append_new_chunk(nonfatal_err,
"Sequence quality score out of range");
return 1;
}
}
} else if (pa->p_args.weights.seq_quality || pa->o_args.weights.seq_quality) {
pr_append_new_chunk(nonfatal_err,
"Sequence quality is part of objective function but sequence quality is not defined");
return 1;
}
if ((offending_char = dna_to_upper(sa->trimmed_seq, 0))) {
char err_msg[64];
snprintf(
err_msg,
64,
"Rejecting invalid sequence character (only ACGTN allowed): %c",
offending_char
);
if (pa->liberal_base) {
pr_append_new_chunk(warning, err_msg);
} else {
pr_append_new_chunk(nonfatal_err, err_msg);
return 1;
}
}
if (NULL != sa->overhang_left) {
overhang_left_len = strlen(sa->overhang_left);
if (((unsigned) pa->p_args.max_size + overhang_left_len) > THAL_MAX_ALIGN) {
pr_append_new_chunk(glob_err,
"PRIMER_MAX_SIZE + SEQUENCE_OVERHANG_LEFT exceeds built-in maximum of ");
pr_append(glob_err, MACRO_VALUE_AS_STRING(THAL_MAX_ALIGN));
return 1;
}
if ((offending_char = dna_to_upper(sa->overhang_left, 0))) {
pr_append_new_chunk(nonfatal_err, "Unrecognized base in left overhang");
return 1;
}
}
if (NULL != sa->overhang_right) {
overhang_right_len = strlen(sa->overhang_right);
if (((unsigned) pa->p_args.max_size + overhang_right_len )> THAL_MAX_ALIGN) {
pr_append_new_chunk(glob_err,
"PRIMER_MAX_SIZE + SEQUENCE_OVERHANG_RIGHT exceeds built-in maximum of ");
pr_append(glob_err, MACRO_VALUE_AS_STRING(THAL_MAX_ALIGN));
return 1;
}
if ((offending_char = dna_to_upper(sa->overhang_right, 0))) {
pr_append_new_chunk(nonfatal_err, "Unrecognized base in right overhang");
return 1;
}
}
if (pa->p_args.opt_tm < pa->p_args.min_tm
|| pa->p_args.opt_tm > pa->p_args.max_tm) {
pr_append_new_chunk(glob_err,
"Optimum primer Tm lower than minimum or higher than maximum");
return 1;
}
if (pa->o_args.opt_tm < pa->o_args.min_tm
|| pa->o_args.opt_tm > pa->o_args.max_tm) {
pr_append_new_chunk(glob_err,
"Optimum internal oligo Tm lower than minimum or higher than maximum");
return 1;
}
if ((pa->p_args.opt_bound < pa->p_args.min_bound)
|| (pa->p_args.opt_bound > pa->p_args.max_bound)) {
pr_append_new_chunk(glob_err,
"Optimum primer fraction binding lower than minimum or higher than maximum");
return 1;
}
if ((pa->o_args.opt_bound < pa->o_args.min_bound)
|| (pa->o_args.opt_bound > pa->o_args.max_bound)) {
pr_append_new_chunk(glob_err,
"Optimum internal oligo fraction binding lower than minimum or higher than maximum");
return 1;
}
if (pa->annealing_temp > 0.0) {
if (pa->annealing_temp > 100.0) {
pr_append_new_chunk(glob_err,
"Annealing temperature higher than 100 C");
return 1;
}
if (pa->salt_corrections == 2) {
pr_append_new_chunk(glob_err,
"Primer binding does not work with Owczarzy salt correction (PRIMER_SALT_CORRECTIONS=2)");
return 1;
}
}
if (
(pa->p_args.min_gc > pa->p_args.max_gc)
|| (pa->p_args.min_gc > 100)
|| (pa->p_args.max_gc < 0)
){
pr_append_new_chunk(glob_err,
"Illegal value for PRIMER_MAX_GC and PRIMER_MIN_GC");
return 1;
}
if (
(pa->o_args.min_gc > pa->o_args.max_gc)
|| (pa->o_args.min_gc > 100)
|| (pa->o_args.max_gc < 0)
) {
pr_append_new_chunk(glob_err,
"Illegal value for PRIMER_INTERNAL_OLIGO_GC");
return 1;
}
if (pa->p_args.num_ns_accepted < 0) {
pr_append_new_chunk(glob_err,
"Illegal value for PRIMER_MAX_NS_ACCEPTED");
return 1;
}
if (pa->o_args.num_ns_accepted < 0){
pr_append_new_chunk(glob_err,
"Illegal value for PRIMER_INTERNAL_MAX_NS_ACCEPTED");
return 1;
}
if (
(pa->p_args.max_self_any < 0) || (pa->p_args.max_self_any > SHRT_MAX)
|| (pa->p_args.max_self_end < 0) || (pa->p_args.max_self_end > SHRT_MAX)
|| (pa->pair_compl_any < 0)|| (pa->pair_compl_any > SHRT_MAX)
|| (pa->pair_compl_end < 0) || (pa->pair_compl_end > SHRT_MAX)
) {
pr_append_new_chunk(glob_err,
"Illegal value for primer complementarity restrictions");
return 1;
}
if (
(pa->p_args.max_self_any_th < 0)
|| (pa->p_args.max_self_end_th < 0) || (pa->p_args.max_hairpin_th < 0)
|| (pa->pair_compl_any_th < 0) || (pa->pair_compl_end_th < 0)
) {
pr_append_new_chunk(glob_err,
"Illegal value for primer complementarity restrictions (thermod. approach)");
return 1;
}
if(
(pa->o_args.max_self_any < 0) || (pa->o_args.max_self_any > SHRT_MAX)
|| (pa->o_args.max_self_end < 0) || (pa->o_args.max_self_end > SHRT_MAX)
) {
pr_append_new_chunk(glob_err,
"Illegal value for internal oligo complementarity restrictions");
return 1;
}
if(
(pa->o_args.max_self_any_th < 0)
|| (pa->o_args.max_self_end_th < 0) || (pa->o_args.max_hairpin_th < 0)
) {
pr_append_new_chunk(glob_err,
"Illegal value for internal oligo complementarity restrictions");
return 1;
}
if ((pa->p_args.salt_conc <= 0) || (pa->p_args.dna_conc <= 0)){
pr_append_new_chunk(glob_err,
"Illegal value for primer salt or dna concentration");
return 1;
}
if (((pa->p_args.dntp_conc < 0) && (pa->p_args.divalent_conc != 0) )
|| (pa->p_args.divalent_conc < 0)){ /* added by T.Koressaar */
pr_append_new_chunk(glob_err, "Illegal value for primer divalent salt or dNTP concentration");
return 1;
}
if((pa->o_args.salt_conc <= 0) || (pa->o_args.dna_conc <= 0)){
pr_append_new_chunk(glob_err,
"Illegal value for internal oligo salt or dna concentration");
return 1;
}
if(((pa->o_args.dntp_conc < 0) && (pa->o_args.divalent_conc != 0))
|| (pa->o_args.divalent_conc < 0)) { /* added by T.Koressaar */
pr_append_new_chunk(glob_err,
"Illegal value for internal oligo divalent salt or dNTP concentration");
return 1;
}
if (!_PR_DEFAULT_POSITION_PENALTIES(pa) && sa->tar2.count > 1) {
pr_append_new_chunk(nonfatal_err,
"Non-default inside penalty or outside penalty ");
pr_append(nonfatal_err,
"is valid only when number of targets <= 1");
}
if (!_PR_DEFAULT_POSITION_PENALTIES(pa) && 0 == sa->tar2.count) {
pr_append_new_chunk(warning,
"Non-default inside penalty or outside penalty ");
pr_append(warning,
"has no effect when number of targets is 0");
}
if (pa->pick_internal_oligo != 1 && sa->internal_input) {
pr_append_new_chunk(nonfatal_err,
"Not specified to pick internal oligos");
pr_append(nonfatal_err,
" but a specific internal oligo is provided");
}
if (sa->internal_input) {
if ((int)strlen(sa->internal_input) > MAX_PRIMER_LENGTH) {
pr_append_new_chunk(glob_err,
"Specified internal oligo exceeds built-in maximum of ");
pr_append(glob_err, MACRO_VALUE_AS_STRING(MAX_PRIMER_LENGTH));
return 1;
}
if ((int)strlen(sa->internal_input) > (int)pa->o_args.max_size)
pr_append_new_chunk(warning,
"Specified internal oligo > PRIMER_INTERNAL_MAX_SIZE");
if ((int)strlen(sa->internal_input) < (int)pa->o_args.min_size)
pr_append_new_chunk(warning,
"Specified internal oligo < PRIMER_INTERNAL_MIN_SIZE");
if (!strstr_nocase(sa->sequence, sa->internal_input))
pr_append_new_chunk(nonfatal_err,
"Specified internal oligo not in sequence");
else if (!strstr_nocase(sa->trimmed_seq, sa->internal_input))
pr_append_new_chunk(nonfatal_err,
"Specified internal oligo not in Included Region");
}
if (sa->left_input) {
if ((int)strlen(sa->left_input) > MAX_PRIMER_LENGTH) {
pr_append_new_chunk(glob_err,
"Specified left primer exceeds built-in maximum of ");
pr_append(glob_err, MACRO_VALUE_AS_STRING(MAX_PRIMER_LENGTH));
return 1;
}
if ((strlen(sa->left_input) + overhang_left_len) > THAL_MAX_ALIGN) {
pr_append_new_chunk(glob_err,
"Specified left primer + overhang exceeds built-in maximum of ");
pr_append(glob_err, MACRO_VALUE_AS_STRING(THAL_MAX_ALIGN));
return 1;
}
if ((int)strlen(sa->left_input) > (int)pa->p_args.max_size) {
pr_append_new_chunk(warning,
"Specified left primer > PRIMER_MAX_SIZE");
}
if ((int)strlen(sa->left_input) < (int)pa->p_args.min_size) {
pr_append_new_chunk(warning,
"Specified left primer < PRIMER_MIN_SIZE");
}
if (!strstr_nocase(sa->sequence, sa->left_input)) {
pr_append_new_chunk(nonfatal_err,
"Specified left primer not in sequence");
} else if (!strstr_nocase(sa->trimmed_seq, sa->left_input)) {
pr_append_new_chunk(nonfatal_err,
"Specified left primer not in Included Region");
}
}
if (sa->right_input) {
if ((int)strlen(sa->right_input) > MAX_PRIMER_LENGTH) {
pr_append_new_chunk(glob_err,
"Specified right primer exceeds built-in maximum of ");
pr_append(glob_err, MACRO_VALUE_AS_STRING(MAX_PRIMER_LENGTH));
return 1;
}
if ((strlen(sa->right_input) + overhang_right_len) > THAL_MAX_ALIGN) {
pr_append_new_chunk(glob_err,
"Specified right primer + overhang exceeds built-in maximum of ");
pr_append(glob_err, MACRO_VALUE_AS_STRING(THAL_MAX_ALIGN));
return 1;
}
if ((int)strlen(sa->right_input) < (int)pa->p_args.min_size) {
pr_append_new_chunk(warning,
"Specified right primer < PRIMER_MIN_SIZE");
}
if ((int)strlen(sa->right_input) > (int)pa->p_args.max_size) {
pr_append_new_chunk(warning,
"Specified right primer > PRIMER_MAX_SIZE");
} else { /* We do not want to overflow s1. */
p3_reverse_complement(sa->right_input,s1);
if (!strstr_nocase(sa->sequence, s1)) {
pr_append_new_chunk(nonfatal_err,
"Specified right primer not in sequence");
} else if (!strstr_nocase(sa->trimmed_seq, s1)) {
pr_append_new_chunk(nonfatal_err,
"Specified right primer not in Included Region");
} else if (sa->left_input) {
if (strcmp(sa->left_input, s1) == 0) {
pr_append_new_chunk(nonfatal_err,
"Specified left and right primer are reverse complementary");
}
if (strcmp(sa->left_input, sa->right_input) == 0) {
pr_append_new_chunk(nonfatal_err,
"Specified left and right primer are identical");
}
}
}
}
if ((pa->pr_pair_weights.product_tm_lt ||
pa->pr_pair_weights.product_tm_gt)
&& (pa->product_opt_tm == PR_UNDEFINED_DBL_OPT)) {
pr_append_new_chunk(glob_err,
"Product temperature is part of objective function while optimum temperature is not defined");
return 1;
}
if((pa->pr_pair_weights.product_size_lt ||
pa->pr_pair_weights.product_size_gt)
&& pa->product_opt_size == PR_UNDEFINED_INT_OPT) {
pr_append_new_chunk(glob_err,
"Product size is part of objective function while optimum size is not defined");
return 1;
}
if ((pa->p_args.weights.gc_content_lt ||
pa->p_args.weights.gc_content_gt)
&& pa->p_args.opt_gc_content == DEFAULT_OPT_GC_PERCENT) {
pr_append_new_chunk(glob_err,
"Primer GC content is part of objective function while optimum gc_content is not defined");
return 1;
}
if ((pa->o_args.weights.gc_content_lt ||
pa->o_args.weights.gc_content_gt)
&& pa->o_args.opt_gc_content == DEFAULT_OPT_GC_PERCENT) {
pr_append_new_chunk(glob_err,
"Hyb probe GC content is part of objective function "
"while optimum gc_content is not defined");
return 1;
}
if ((pa->pick_internal_oligo != 1) &&
(pa->pr_pair_weights.io_quality)) {
pr_append_new_chunk(glob_err,
"Internal oligo quality is part of objective function "
"while internal oligo choice is not required");
return 1;
}
if (pa->p_args.weights.repeat_sim && (!seq_lib_num_seq(pa->p_args.repeat_lib))) {
pr_append_new_chunk(glob_err,
"Mispriming score is part of objective function, but mispriming library is not defined");
return 1;
}
if (pa->o_args.weights.repeat_sim && (!seq_lib_num_seq(pa->o_args.repeat_lib))) {
pr_append_new_chunk(glob_err,
"Internal oligo mispriming score is part of objective function while mishyb library is not defined");
return 1;
}
if (pa->pr_pair_weights.repeat_sim && (!(seq_lib_num_seq(pa->p_args.repeat_lib)))) {
pr_append_new_chunk(glob_err,
"Mispriming score is part of objective function, "
"but mispriming library is not defined");
return 1;
}
if(pa->pr_pair_weights.io_quality
&& pa->pick_internal_oligo == 0 ) {
pr_append_new_chunk(glob_err,
"Internal oligo quality is part of objective function"
" while internal oligo choice is not required");
return 1;
}
if (pa->sequencing.lead < 0) {
pr_append_new_chunk(glob_err,
"Illegal value for PRIMER_SEQUENCING_LEAD");
return 1;
}
if (pa->sequencing.interval < 0) {
pr_append_new_chunk(glob_err,
"Illegal value for PRIMER_SEQUENCING_INTERVAL");
return 1;
}
if (pa->sequencing.accuracy < 0) {
pr_append_new_chunk(glob_err,
"Illegal value for PRIMER_SEQUENCING_ACCURACY");
return 1;
}
if (pa->sequencing.spacing < 0) {
pr_append_new_chunk(glob_err,
"Illegal value for PRIMER_SEQUENCING_SPACING");
return 1;
}
if(pa->sequencing.interval > pa->sequencing.spacing) {
pr_append_new_chunk(glob_err,
"PRIMER_SEQUENCING_INTERVAL > PRIMER_SEQUENCING_SPACING");
return 1;
}
if(pa->sequencing.accuracy > pa->sequencing.spacing) {
pr_append_new_chunk(glob_err,
"PRIMER_SEQUENCING_ACCURACY > PRIMER_SEQUENCING_SPACING");
return 1;
}
if(pa->sequencing.lead > pa->sequencing.spacing) {
pr_append_new_chunk(glob_err,
"PRIMER_SEQUENCING_LEAD > PRIMER_SEQUENCING_SPACING");
return 1;
}
if((sa->force_left_start > -1) && (sa->force_left_end > -1)
&& (sa->force_left_start > sa->force_left_end)) {
pr_append_new_chunk(glob_err,
"SEQUENCE_FORCE_LEFT_START > SEQUENCE_FORCE_LEFT_END");
return 1;
}
if((sa->force_right_end > -1) && (sa->force_right_start > -1)
&& (sa->force_right_end > sa->force_right_start)) {
pr_append_new_chunk(glob_err,
"SEQUENCE_FORCE_RIGHT_END > SEQUENCE_FORCE_RIGHT_START");
return 1;
}
if (pa->p_args.min_5_prime_overlap_of_junction < 1) {
pr_append_new_chunk(glob_err,
"Illegal value for PRIMER_MIN_5_PRIME_OVERLAP_OF_JUNCTION");
return 1;
}
if (pa->p_args.min_3_prime_overlap_of_junction < 1) {
pr_append_new_chunk(glob_err,
"Illegal value for PRIMER_MIN_3_PRIME_OVERLAP_OF_JUNCTION");
return 1;
}
if ((sa->primer_overlap_junctions_count > 0) &&
(pa->p_args.min_5_prime_overlap_of_junction > (pa->p_args.max_size / 2))) {
pr_append_new_chunk(glob_err,
"PRIMER_MIN_5_PRIME_OVERLAP_OF_JUNCTION > PRIMER_MAX_SIZE / 2");
return 1;
}
if ((sa->primer_overlap_junctions_count > 0) &&
(pa->p_args.min_3_prime_overlap_of_junction > (pa->p_args.max_size / 2))) {
pr_append_new_chunk(glob_err,
"PRIMER_MIN_3_PRIME_OVERLAP_OF_JUNCTION > PRIMER_MAX_SIZE / 2");
return 1;
}
if (pa->o_args.min_5_prime_overlap_of_junction < 1) {
pr_append_new_chunk(glob_err,
"Illegal value for PRIMER_INTERNAL_MIN_5_PRIME_OVERLAP_OF_JUNCTION");
return 1;
}
if (pa->o_args.min_3_prime_overlap_of_junction < 1) {
pr_append_new_chunk(glob_err,
"Illegal value for PRIMER_INTERNAL_MIN_3_PRIME_OVERLAP_OF_JUNCTION");
return 1;
}
if ((sa->primer_overlap_junctions_count > 0) &&
(pa->o_args.min_5_prime_overlap_of_junction > (pa->p_args.max_size / 2))) {
pr_append_new_chunk(glob_err,
"PRIMER_INTERNAL_MIN_5_PRIME_OVERLAP_OF_JUNCTION > PRIMER_MAX_SIZE / 2");
return 1;
}
if ((sa->primer_overlap_junctions_count > 0) &&
(pa->o_args.min_3_prime_overlap_of_junction > (pa->p_args.max_size / 2))) {
pr_append_new_chunk(glob_err,
"PRIMER_INTERNAL_MIN_3_PRIME_OVERLAP_OF_JUNCTION > PRIMER_MAX_SIZE / 2");
return 1;
}
if (pa->p_args.divalent_conc > 0.0 && pa->p_args.dntp_conc <= 0.0) {
pr_append_new_chunk(warning,
"PRIMER_SALT_DIVALENT > 0.0 "
"but PRIMER_DNTP_CONC <= 0.0; "
"use reasonable value for PRIMER_DNTP_CONC");
}
if ((pa->p_args.must_match_five_prime != NULL) &&
(test_must_match_parameters(pa->p_args.must_match_five_prime))) {
pr_append_new_chunk(glob_err,
"Illegal values for PRIMER_MUST_MATCH_FIVE_PRIME");
return 1;
}
if ((pa->p_args.must_match_three_prime != NULL) &&
(test_must_match_parameters(pa->p_args.must_match_three_prime))) {
pr_append_new_chunk(glob_err,
"Illegal values for PRIMER_MUST_MATCH_THREE_PRIME");
return 1;
}
if ((pa->o_args.must_match_five_prime != NULL) &&
(test_must_match_parameters(pa->o_args.must_match_five_prime))) {
pr_append_new_chunk(glob_err,
"Illegal values for PRIMER_INTERNAL_MUST_MATCH_FIVE_PRIME");
return 1;
}
if ((pa->o_args.must_match_three_prime != NULL) &&
(test_must_match_parameters(pa->o_args.must_match_three_prime))) {
pr_append_new_chunk(glob_err,
"Illegal values for PRIMER_INTERNAL_MUST_MATCH_THREE_PRIME");
return 1;
}
return (NULL == nonfatal_err->data && NULL == glob_err->data) ? 0 : 1;
} /* _pr_data_control */
static int
_check_and_adjust_overlap_pos(seq_args_t* sa,
int *list,
int *count,
const char *tag,
int seq_len,
int first_index,
pr_append_str *nonfatal_err,
pr_append_str *warning) {
int i;
int outside_warning_issued = 0;
char buffer[255];
if (*count == 0) {
return 0;
}
for (i = 0; i < *count; i++) {
/* Subtract first_index from the "must overlap" positions */
list[i] -= first_index;
if (list[i] >= seq_len) {
sprintf(buffer, "%s beyond end of sequence", tag);
pr_append_new_chunk(nonfatal_err, buffer);
return 1;
}
if (list[i] < 0) {
sprintf(buffer, "Negative %s length", tag);
pr_append_new_chunk(nonfatal_err, buffer);
return 1;
}
/* Cause the intron positions to be relative to the included region. */
list[i] -= sa->incl_s;
/* Check that intron positions are within the included region. */
if (list[i] < 0
|| list[i] > sa->incl_l) {
if (!outside_warning_issued) {
sprintf(buffer, "%s outside of INCLUDED_REGION", tag);
pr_append_new_chunk(warning, buffer);
outside_warning_issued = 1;
}
}
}
return 0;
}
/*
* Takes an upper case oligo sequence and a maximum allows number of
* identical consecutive base pairs. Returns 0 if a run of more than
* max_poly_x base pairs is not possible for seq and 1 otherwise.
*
* N can be any base and poly_x should be the worst case possible
* corner cases:
* NNG poly_x=3
* ANA poly_x=3
* CNN poly_x=3
* TNNG poly_x=3
* GNGNG poly_x=5
* ANGNG poly_x=4
*
* Algorithm - scan though seq from 0 to end considering all N bp to be
* the last seen non-N base pair. Then scan in the reverse direction
* and consider all N bp to the the last seen non-N base pair. The
* reverse scan can be skipped if seq does not contain any Ns.
*/
static int
_pr_violates_poly_x(const char *seq, int max_poly_x) {
if (max_poly_x < 1) return 0;
const int len = strlen(seq);
if (len <= max_poly_x) return 0;
int i, poly_x;
int has_N = 0;
char last_non_N = seq[0];
poly_x = 1;
if (last_non_N == 'N') {
for (i=1; i max_poly_x) return 1;
} else if (seq[i] == last_non_N) {
poly_x++;
if (poly_x > max_poly_x) return 1;
} else {
poly_x = 1;
last_non_N = seq[i];
}
}
if (has_N == 0) return 0;
last_non_N = seq[len-1];
poly_x = 1;
if (last_non_N == 'N') {
for (i=len-2; i>=0; i--){
if(seq[i] != 'N') {
last_non_N = seq[i];
break;
}
}
}
for (i=len-2; i>=0; i--){
if (seq[i] == 'N' || seq[i] == last_non_N) {
poly_x++;
if (poly_x > max_poly_x) return 1;
} else {
poly_x = 1;
last_non_N = seq[i];
}
}
return 0;
}
static int
_check_and_adjust_intervals(seq_args_t* sa,
int seq_len,
int first_index,
pr_append_str * nonfatal_err,
pr_append_str *warning) {
if (_check_and_adjust_1_interval("TARGET",
sa->tar2.count,
sa->tar2.pairs,
seq_len,
first_index,
nonfatal_err, sa, warning, 0)
== 1) {
return 1;
}
sa->start_codon_pos -= sa->incl_s;
if (_check_and_adjust_1_interval("EXCLUDED_REGION",
sa->excl2.count, sa->excl2.pairs,
seq_len, first_index,
nonfatal_err, sa, warning, 0)
== 1) {
return 1;
}
if (_check_and_adjust_1_interval("PRIMER_INTERNAL_OLIGO_EXCLUDED_REGION",
sa->excl_internal2.count,
sa->excl_internal2.pairs,
seq_len,
first_index,
nonfatal_err, sa, warning, 0)
== 1) {
return 1;
}
if (_check_and_adjust_1_interval("PRIMER_PAIR_OK_REGION_LIST",
sa->ok_regions.count,
sa->ok_regions.left_pairs,
seq_len,
first_index,
nonfatal_err, sa, warning, 1)
== 1) {
return 1;
}
if (_check_and_adjust_1_interval("PRIMER_PAIR_OK_REGION_LIST",
sa->ok_regions.count,
sa->ok_regions.right_pairs,
seq_len,
first_index,
nonfatal_err, sa, warning, 1)
== 1) {
return 1;
}
return 0;
}
/*
* Check intervals, and add any errors to err.
* Update the start of each interval to
* be relative to the start of the included region.
*/
static int
_check_and_adjust_1_interval(const char *tag_name,
int num_intervals,
interval_array_t intervals,
int seq_len,
int first_index,
pr_append_str *err,
seq_args_t* sa,
pr_append_str *warning,
int empty_allowed)
{
int i;
int outside_warning_issued = 0;
/* Subtract the first_index from the start positions in the interval
array */
for (i = 0; i < num_intervals; i++) {
if (empty_allowed && (intervals[i][0] == -1) && (intervals[i][1] == -1)) {
continue;
}
if (empty_allowed && (((intervals[i][0] == -1) && (intervals[i][1] != -1))
|| ((intervals[i][0] != -1) && (intervals[i][1] == -1)))) {
pr_append_new_chunk(err, tag_name);
pr_append(err, " illegal interval");
return 1;
}
intervals[i][0] -= first_index;
}
for (i=0; i < num_intervals; i++) {
if (empty_allowed && (intervals[i][0] == -1) && (intervals[i][1] == -1)) {
continue;
}
if (intervals[i][0] + intervals[i][1] > seq_len) {
pr_append_new_chunk(err, tag_name);
pr_append(err, " beyond end of sequence");
return 1;
}
/* Cause the interval start to be relative to the included region. */
intervals[i][0] -= sa->incl_s;
/* Check that intervals are within the included region. */
if (intervals[i][0] < 0
|| intervals[i][0] + intervals[i][1] > sa->incl_l) {
if (!outside_warning_issued) {
pr_append_new_chunk(warning, tag_name);
pr_append(warning,
" outside of INCLUDED_REGION");
outside_warning_issued = 1;
}
}
if (intervals[i][1] < 0) {
pr_append_new_chunk(err, "Negative ");
pr_append(err, tag_name);
pr_append(err, " length");
return 1;
}
}
return 0;
} /* _check_and_adjust_intervals */
/* ============================================================ */
/* END functions that check and modify the input */
/* ============================================================ */
/* ============================================================ */
/* BEGIN create primer files functions */
/* ============================================================ */
/* START OF WHAT SHOULD GO TO IO_PRIMER_FILES.C */
/*
Creates up to three files, the names of which are based on the
argument 'file_name'. One file is a table of forward primers, one
a table of reverse primers, and one a table of internal
hybridization oligos, depending on what the caller to
choose_primers() requested (in the 'pa' argument). Returns 0 on
success, 1 on error. On error, check errno for ENOMEM. Used to
implement P3_FILE_FLAG=1.
*/
int
p3_print_oligo_lists(const p3retval *retval,
const seq_args_t* sa,
const p3_global_settings *pa,
pr_append_str *err,
const char *file_name)
{
/* Figure out if the sequence starts at position 1 or 0 */
int first_base_index = pa->first_base_index;
int ret;
/* Start building up a filename */
char *file;
FILE *fh;
if (setjmp(_jmp_buf) != 0) {
return 1; /* If we get here, that means we returned via a longjmp.
In this case errno should be ENOMEM. */
}
file = (char *) malloc((int)strlen(sa->sequence_name) + 5);
if (NULL == file) { return 1; } /* ENOMEM */
/* Check if the left primers have to be printed */
if( pa->pick_left_primer ) {
/* Create the file name and open file*/
strcpy(file, sa->sequence_name);
strcat(file, ".for");
if (!(fh = fopen(file,"w"))) {
if (pr_append_new_chunk_external(err, "Unable to open file ")) {
return 1;
}
if (pr_append_external(err, file)) { return 1; }
if (pr_append_external(err, " for writing")) { return 1; }
free(file);
return 1;
}
/* Print the content to the file */
ret =
p3_print_one_oligo_list(sa, retval->fwd.num_elem,
retval->fwd.oligo, OT_LEFT,
first_base_index, NULL != pa->p_args.repeat_lib,
fh,pa->thermodynamic_oligo_alignment);
fclose(fh);
if (ret) { return 1; }
}
/* Check if the right primers have to be printed */
if (pa->pick_right_primer) {
strcpy(file, sa->sequence_name);
strcat(file, ".rev");
if (!(fh = fopen(file,"w"))) {
pr_append_new_chunk(err, "Unable to open file ");
pr_append(err, file);
pr_append(err, " for writing");
free(file);
return 1;
}
/* Print the content to the file */
ret = p3_print_one_oligo_list(sa, retval->rev.num_elem,
retval->rev.oligo, OT_RIGHT,
first_base_index, NULL != pa->p_args.repeat_lib,
fh, pa->thermodynamic_oligo_alignment);
fclose(fh);
if (ret) { return 1; }
}
/* Check if the internal oligos have to be printed */
if (pa->pick_internal_oligo) {
/* Create the file name and open file*/
strcpy(file, sa->sequence_name);
strcat(file, ".int");
if (!(fh = fopen(file,"w"))) {
if (pr_append_new_chunk_external(err, "Unable to open file ")) {
return 1;
}
if (pr_append_external(err, file)) { return 1; }
if (pr_append_external(err, " for writing")) { return 1; }
free(file);
return 1;
}
/* Print the content to the file */
ret = p3_print_one_oligo_list(sa, retval->intl.num_elem,
retval->intl.oligo, OT_INTL,
first_base_index,
NULL != pa->o_args.repeat_lib,
fh, pa->thermodynamic_oligo_alignment);
fclose(fh);
if (ret) { return 1; }
}
free(file);
return 0;
}
/* Print out the content of one primer array */
/* Return 1 on error, otherwise 0. */
int
p3_print_one_oligo_list(const seq_args_t* sa,
int n,
const primer_rec *oligo_arr,
const oligo_type o_type,
const int first_base_index,
const int print_lib_sim,
FILE *fh,
const int thermodynamic_oligo_alignment)
{
int i;
/* Print out the header for the table */
if (print_list_header(fh, o_type, first_base_index, print_lib_sim, thermodynamic_oligo_alignment)) {
return 1; /* error */
}
/* Iterate over the array */
for (i = 0; i < n; i++) {
/* Print each single oligo */
if (print_oligo(fh, sa, i, &oligo_arr[i], o_type,
first_base_index, print_lib_sim, thermodynamic_oligo_alignment)) {
return 1; /* error */
}
}
return 0; /* success */
}
static int
print_list_header(FILE *fh,
oligo_type type,
int first_base_index,
int print_lib_sim,
int thermodynamic_oligo_alignment)
{
int ret;
ret = fprintf(fh, "ACCEPTABLE %s\n",
OT_LEFT == type ? "LEFT PRIMERS"
: OT_RIGHT == type ? "RIGHT PRIMERS" : "INTERNAL OLIGOS");
if (ret < 0) { return 1; }
ret = fprintf(fh, " %4d-based ",
first_base_index);
if (ret < 0) { return 1; }
if(thermodynamic_oligo_alignment) {
ret = fprintf(fh, "# self self hair-");
} else {
ret = fprintf(fh, "# self self");
}
if (ret < 0) { return 1; }
if (print_lib_sim) {
/* ret = fprintf(fh, "# self self lib qual-\n"); */
ret = fprintf(fh, " lib");
}
if (ret < 0) { return 1; }
ret = fprintf(fh, " qual-\n");
if (ret < 0) { return 1; }
ret = fprintf(fh, " # sequence start ln ");
if (ret < 0) { return 1; }
ret = fprintf(fh, "N GC%% Tm");
if (ret < 0) { return 1; }
if(thermodynamic_oligo_alignment) {
ret = fprintf(fh, " any_th end_th pin");
} else {
ret = fprintf(fh, " any end");
}
if (ret < 0) { return 1; }
if (print_lib_sim) {
ret = fprintf(fh, " sim lity\n");
} else {
ret = fprintf(fh, " lity\n");
}
if (ret < 0) { return 1; }
return 0;
}
static int
print_oligo(FILE *fh,
const seq_args_t* sa,
int index,
const primer_rec *h,
oligo_type type,
int first_base_index,
int print_lib_sim,
int thermodynamical_approach)
{
int ret;
/* WARNING, *p points to static storage that is overwritten on next
call to pr_oligo_sequence or pr_oligo_rev_c_sequence. */
char *p =
(OT_RIGHT != type)
? pr_oligo_sequence(sa, h)
: pr_oligo_rev_c_sequence(sa, h);
ret = fprintf(fh,
"%4d %-30s %5d %2d %2d %5.2f %5.3f %5.2f %5.2f",
index, p, h->start+sa->incl_s + first_base_index,
h->length,
h->num_ns, h->gc_content, h->temp,
h->self_any,
h->self_end);
if (ret < 0) { return 1; }
if (1==thermodynamical_approach) {
ret = fprintf(fh, " %5.2f", h->hairpin_th);
if (ret < 0) { return 1; }
}
if (ret < 0) { return 1; }
if (print_lib_sim) {
PR_ASSERT(h->repeat_sim.score != NULL);
ret = fprintf(fh, " %5.2f",
h->repeat_sim.score[h->repeat_sim.max]);
if (ret < 0) { return 1; }
}
ret = fprintf(fh, " %6.3f\n", h->quality);
if (ret < 0) { return 1; }
else return 0;
}
/* END OF WHAT SHOULD GO TO IO_PRIMER_FILES.C */
/* ============================================================ */
/* END create primer files functions */
/* ============================================================ */
/* ============================================================
* BEGIN p3_read_line, a utility used
* both for reading boulder input and for reading sequence
* libraries.
* ============================================================ */
/* Read a line of any length from file. Return NULL on end of file,
* otherwise return a pointer to static storage containing the line. Any
* trailing newline is stripped off. Be careful -- there is only
* one static buffer, so subsequent calls will replace the string
* pointed to by the return value.
* Used in seq_lib functions and also exported
* used in p3_read_line and seq_lib functions
* */
#define INIT_BUF_SIZE 1024
char*
p3_read_line(FILE *file)
{
static size_t ssz;
static char *s = NULL;
size_t remaining_size;
char *p, *n;
if (NULL == s) {
ssz = INIT_BUF_SIZE;
s = (char *) pr_safe_malloc(ssz);
}
p = s;
remaining_size = ssz;
while (1) {
if (fgets(p, remaining_size, file) == NULL) { /* End of file. */
if (p == s) {
ssz = 0;
if (s != NULL) {
free(s);
}
s = NULL;
return NULL;
} else {
return s;
}
}
if ((n = strchr(p, '\n')) != NULL) {
*n = '\0';
n--;
if ((n >= p) && (*n == '\r')) {
*n = '\0';
}
return s;
}
/* We did not get the whole line. */
/*
* The following assertion is a bit of hack, a at least for 32-bit
* machines, because we will usually run out of address space first.
* Really we should treat an over-long line as an input error, but
* since an over-long line is unlikely and we do want to provide some
* protection....
*/
PR_ASSERT(ssz <= INT_MAX);
if (ssz >= INT_MAX / 2) {
ssz = INT_MAX;
} else {
ssz *= 2;
}
s = (char *) pr_safe_realloc(s, ssz);
p = strchr(s, '\0');
remaining_size = ssz - (p - s);
}
}
/* ============================================================ */
/* END p3_read_line */
/* ============================================================ */
/* ============================================================ */
/* BEGIN 'get' functions for seq_args_t */
/* ============================================================ */
const interval_array_t2 *
p3_get_sa_tar2(const seq_args_t* sargs) {
return &sargs->tar2 ;
}
const interval_array_t2 *
p3_get_sa_excl2(const seq_args_t* sargs) {
return &sargs->excl2 ;
}
const interval_array_t2 *
p3_get_sa_excl_internal2(const seq_args_t* sargs) {
return &sargs->excl_internal2 ;
}
const interval_array_t4 *
p3_get_sa_ok_regions(const seq_args_t* sargs)
{
return &sargs->ok_regions;
}
const int*
p3_get_sa_overlap_junctions(const seq_args_t* sargs)
{
return sargs->primer_overlap_junctions;
}
const int*
p3_get_sa_intl_overlap_junctions(const seq_args_t* sargs)
{
return sargs->intl_overlap_junctions;
}
/* ============================================================ */
/* END 'get' functions for seq_args_t */
/* ============================================================ */
int
p3_get_sa_n_quality(seq_args_t* sargs) {
return sargs->n_quality ;
}
/* ============================================================ */
/* BEGIN 'set' functions for seq_args_t */
/* ============================================================ */
int
p3_set_sa_sequence(seq_args_t* sargs, const char *sequence) {
return _set_string(&sargs->sequence, sequence) ;
}
void
p3_set_sa_primer_sequence_quality(seq_args_t* sargs, int quality) {
sargs->quality[sargs->n_quality++] = quality ;
}
int
p3_set_sa_sequence_name(seq_args_t* sargs, const char* sequence_name) {
return _set_string(&sargs->sequence_name, sequence_name);
}
int
p3_set_sa_left_input(seq_args_t* sargs, const char *s) {
return _set_string(&sargs->left_input, s);
}
int
p3_set_sa_right_input(seq_args_t* sargs, const char *s) {
return _set_string(&sargs->right_input, s);
}
int
p3_set_sa_internal_input(seq_args_t* sargs, const char *s) {
return _set_string(&sargs->internal_input, s);
}
void
p3_set_sa_incl_s(seq_args_t* sargs, int incl_s) {
sargs->incl_s = incl_s;
}
void
p3_set_sa_incl_l(seq_args_t* sargs, int incl_l) {
sargs->incl_l = incl_l;
}
void
p3_set_sa_empty_quality(seq_args_t* sargs) {
sargs->n_quality = 0;
}
void
p3_sa_add_to_quality_array(seq_args_t* sargs, int quality) {
int n = sargs->n_quality;
if (sargs->quality_storage_size == 0) {
sargs->quality_storage_size = 3000;
sargs->quality
= (int *)
// pr_safe_malloc(sizeof(*sargs->quality)
// * sargs->quality_storage_size);
pr_safe_malloc(sizeof(int)
* sargs->quality_storage_size);
}
if (n > sargs->quality_storage_size) {
sargs->quality_storage_size *= 2;
sargs->quality
= (int *)
// pr_safe_realloc(sargs->quality,
// sizeof(*sargs->quality)
// * sargs->quality_storage_size);
pr_safe_realloc(sargs->quality,
sizeof(int)
* sargs->quality_storage_size);
}
sargs->quality[n] = quality;
sargs->n_quality++;
}
int
p3_sa_add_to_overlap_junctions_array(seq_args_t* sargs, int overlap)
{
int c = sargs->primer_overlap_junctions_count;
if (c >= PR_MAX_INTERVAL_ARRAY) { return 1; }
sargs->primer_overlap_junctions[sargs->primer_overlap_junctions_count++] = overlap;
return 0;
}
int
p3_sa_add_to_intl_overlap_junctions_array(seq_args_t* sargs, int overlap)
{
int c = sargs->intl_overlap_junctions_count;
if (c >= PR_MAX_INTERVAL_ARRAY) return 1;
sargs->intl_overlap_junctions[sargs->intl_overlap_junctions_count++] = overlap;
return 0;
}
void
p3_set_sa_start_codon_pos(seq_args_t* sargs, int start_codon_pos) {
sargs->start_codon_pos = start_codon_pos;
}
int
p3_add_to_sa_tar2(seq_args_t* sargs, int n1, int n2) {
return p3_add_to_interval_array(&sargs->tar2, n1, n2);
}
int
p3_add_to_sa_excl2(seq_args_t* sargs, int n1, int n2) {
return p3_add_to_interval_array(&sargs->excl2, n1, n2);
}
int
p3_add_to_sa_excl_internal2(seq_args_t* sargs, int n1, int n2) {
return p3_add_to_interval_array(&sargs->excl_internal2, n1, n2);
}
int
p3_add_to_sa_ok_regions(seq_args_t* sargs, int l1, int l2, int r1, int r2)
{
return p3_add_to_2_interval_array(&sargs->ok_regions, l1, l2, r1, r2);
}
/* ============================================================ */
/* END 'set' functions for seq_args */
/* ============================================================ */
/* ============================================================ */
/* BEGIN 'get' functions for p3_global_settings */
/* ============================================================ */
args_for_one_oligo_or_primer *
p3_get_gs_p_args(p3_global_settings * p) {
return &p->p_args;
}
args_for_one_oligo_or_primer *
p3_get_gs_o_args(p3_global_settings * p) {
return &p->o_args;
}
/* ============================================================ */
/* END 'get' functions for p3_global_settings */
/* ============================================================ */
/* ============================================================ */
/* BEGIN 'set' functions for p3_global_settings */
/* ============================================================ */
void
p3_set_gs_prmin (p3_global_settings * p , int val, int i) {
p->pr_min[i] = val ;
}
void
p3_set_gs_prmax (p3_global_settings * p , int val, int i) {
p->pr_max[i] = val ;
}
void
p3_set_gs_primer_opt_size(p3_global_settings * p , int val) {
p->p_args.opt_size = val ;
}
void
p3_set_gs_primer_min_size(p3_global_settings * p , int val) {
p->p_args.min_size = val ;
}
void
p3_set_gs_primer_max_size(p3_global_settings * p , int val) {
p->p_args.max_size = val ;
}
void
p3_set_gs_primer_max_poly_x(p3_global_settings * p , int val) {
p->p_args.max_poly_x = val;
}
void
p3_set_gs_primer_opt_tm(p3_global_settings * p , double d) {
p->p_args.opt_tm = d ;
}
void
p3_set_gs_primer_opt_gc_percent(p3_global_settings * p , double d) {
p->p_args.opt_gc_content = d ;
}
void
p3_set_gs_primer_min_tm(p3_global_settings * p , double d) {
p->p_args.min_tm = d ;
}
void
p3_set_gs_primer_max_tm(p3_global_settings * p , double d) {
p->p_args.max_tm = d;
}
void
p3_set_gs_primer_opt_bound(p3_global_settings * p , double d) {
p->p_args.opt_bound = d ;
}
void
p3_set_gs_primer_min_bound(p3_global_settings * p , double d) {
p->p_args.min_bound = d ;
}
void
p3_set_gs_primer_max_bound(p3_global_settings * p , double d) {
p->p_args.max_bound = d;
}
void
p3_set_gs_primer_max_diff_tm(p3_global_settings * p , double val) {
p->max_diff_tm = val;
}
void
p3_set_gs_primer_tm_santalucia(p3_global_settings * p,
tm_method_type val) {
p->tm_santalucia = val ;
}
void
p3_set_gs_primer_salt_corrections(p3_global_settings * p,
salt_correction_type val) {
p->salt_corrections = val;
}
void
p3_set_gs_primer_annealing_temp(p3_global_settings * p,
double val) {
p->annealing_temp = val;
}
void
p3_set_gs_primer_min_gc(p3_global_settings * p , double val) {
p->p_args.min_gc = val ;
}
void
p3_set_gs_primer_max_gc(p3_global_settings * p , double val) {
p->p_args.max_gc = val ;
}
void
p3_set_gs_primer_salt_conc(p3_global_settings * p , double val) {
p->p_args.salt_conc = val ;
}
void
p3_set_gs_primer_divalent_conc(p3_global_settings * p , double val)
{
p->p_args.divalent_conc = val;
}
void
p3_set_gs_primer_dntp_conc(p3_global_settings * p , double val)
{
p->p_args.dntp_conc = val ;
}
void
p3_set_gs_primer_dna_conc(p3_global_settings * p , double val)
{
p->p_args.dna_conc = val ;
}
void
p3_set_gs_primer_dmso_conc(p3_global_settings * p , double val)
{
p->p_args.dmso_conc = val ;
}
void
p3_set_gs_primer_dmso_fact(p3_global_settings * p , double val)
{
p->p_args.dmso_fact = val ;
}
void
p3_set_gs_primer_formamide_conc(p3_global_settings * p , double val)
{
p->p_args.formamide_conc = val ;
}
void
p3_set_gs_primer_num_ns_accepted(p3_global_settings * p , int val)
{
p->p_args.num_ns_accepted = val ;
}
void
p3_set_gs_primer_product_opt_size(p3_global_settings * p , int val)
{
p->product_opt_size = val ;
}
void
p3_set_gs_primer_self_any(p3_global_settings * p , double val)
{
p->p_args.max_self_any = val;
}
void
p3_set_gs_primer_self_any_th(p3_global_settings * p , double val)
{
p->p_args.max_self_any_th = val;
}
void
p3_set_gs_primer_self_end(p3_global_settings * p , double val)
{
p->p_args.max_self_end = val; /* (short) (val * 100); */
}
void
p3_set_gs_primer_self_end_th(p3_global_settings * p , double val)
{
p->p_args.max_self_end_th = val;
}
void
p3_set_gs_primer_hairpin_th(p3_global_settings * p , double val) {
p->p_args.max_hairpin_th = val;
}
void /* Called in primer3_boulder_main.c. */
p3_set_gs_primer_file_flag(p3_global_settings * p , int file_flag)
{
p->file_flag = file_flag;
}
void
p3_set_gs_pick_anyway(p3_global_settings * p , int pick_anyway)
{
p->pick_anyway = pick_anyway ;
}
void
p3_set_gs_gc_clamp(p3_global_settings * p , int gc_clamp)
{
p->gc_clamp = gc_clamp;
}
void
p3_set_gs_primer_liberal_base(p3_global_settings * p , int val) {
p->liberal_base = val;
}
void
p3_set_gs_primer_first_base_index(p3_global_settings * p , int first_base_index){
p->first_base_index = first_base_index;
}
void
p3_set_gs_primer_num_return(p3_global_settings * p , int val) {
p->num_return = val ;
}
void
p3_set_gs_primer_min_quality(p3_global_settings * p , int val) {
p->p_args.min_quality = val ;
}
void
p3_set_gs_primer_min_end_quality(p3_global_settings * p , int val) {
p->p_args.min_end_quality = val ;
}
void
p3_set_gs_primer_quality_range_min(p3_global_settings * p , int val) {
p->quality_range_min = val ;
}
void
p3_set_gs_primer_quality_range_max(p3_global_settings * p , int val) {
p->quality_range_max = val ;
}
void
p3_set_gs_primer_product_max_tm(p3_global_settings * p , double val) {
p->product_max_tm = val ;
}
void
p3_set_gs_primer_product_min_tm(p3_global_settings * p , double val) {
p->product_min_tm = val ;
}
void
p3_set_gs_primer_product_opt_tm(p3_global_settings * p , double val) {
p->product_opt_tm = val ;
}
void
p3_set_gs_primer_task(p3_global_settings * pa , char * task_tmp)
{
if (!strcmp_nocase(task_tmp, "pick_pcr_primers")) {
pa->primer_task = generic_p3;
pa->pick_left_primer = 1;
pa->pick_right_primer = 1;
pa->pick_internal_oligo = 0;
} else if (!strcmp_nocase(task_tmp, "pick_pcr_primers_and_hyb_probe")) {
pa->primer_task = generic_p3;
pa->pick_left_primer = 1;
pa->pick_right_primer = 1;
pa->pick_internal_oligo = 1;
} else if (!strcmp_nocase(task_tmp, "pick_left_only")) {
pa->primer_task = generic_p3;
pa->pick_left_primer = 1;
pa->pick_right_primer = 0;
pa->pick_internal_oligo = 0;
} else if (!strcmp_nocase(task_tmp, "pick_right_only")) {
pa->primer_task = generic_p3;
pa->pick_left_primer = 0;
pa->pick_right_primer = 1;
pa->pick_internal_oligo = 0;
} else if (!strcmp_nocase(task_tmp, "pick_hyb_probe_only")) {
pa->primer_task = generic_p3;
pa->pick_left_primer = 0;
pa->pick_right_primer = 0;
pa->pick_internal_oligo = 1;
} else if (!strcmp_nocase(task_tmp, "generic")) {
pa->primer_task = generic_p3;
} else if (!strcmp_nocase(task_tmp, "pick_detection_primers")) {
pa->primer_task = generic_p3; /* Deliberate duplication for
backward compatibility. */
} else if (!strcmp_nocase(task_tmp, "pick_cloning_primers")) {
pa->primer_task = pick_cloning_primers;
} else if (!strcmp_nocase(task_tmp, "pick_discriminative_primers")) {
pa->primer_task = pick_discriminative_primers;
} else if (!strcmp_nocase(task_tmp, "pick_sequencing_primers")) {
pa->primer_task = pick_sequencing_primers;
} else if (!strcmp_nocase(task_tmp, "pick_primer_list")) {
pa->primer_task = pick_primer_list;
} else if (!strcmp_nocase(task_tmp, "check_primers")) {
pa->primer_task = check_primers;
}
}
void
p3_set_gs_primer_pick_right_primer(p3_global_settings * p , int pick_right_primer)
{
p->pick_right_primer = pick_right_primer;
}
void
p3_set_gs_primer_pick_internal_oligo(p3_global_settings * p , int pick_internal_oligo)
{
p->pick_internal_oligo = pick_internal_oligo;
}
void
p3_set_gs_primer_pick_left_primer(p3_global_settings * p , int pick_left_primer) {
p->pick_left_primer = pick_left_primer;
}
void
p3_set_gs_primer_internal_oligo_opt_size(p3_global_settings * p , int val) {
p->o_args.opt_size = val ;
}
void
p3_set_gs_primer_internal_oligo_max_size(p3_global_settings * p , int val) {
p->o_args.max_size = val ;
}
void
p3_set_gs_primer_internal_oligo_min_size(p3_global_settings * p , int val) {
p->o_args.min_size = val ;
}
void
p3_set_gs_primer_internal_oligo_max_poly_x(p3_global_settings * p , int val) {
p->o_args.max_poly_x = val ;
}
void
p3_set_gs_primer_internal_oligo_opt_tm(p3_global_settings * p , double val) {
p->o_args.opt_tm = val ;
}
void
p3_set_gs_primer_internal_oligo_opt_gc_percent(p3_global_settings * p , double val) {
p->o_args.opt_gc_content = val ;
}
void
p3_set_gs_primer_internal_oligo_max_tm(p3_global_settings * p , double val) {
p->o_args.max_tm = val ;
}
void
p3_set_gs_primer_internal_oligo_min_tm(p3_global_settings * p , double val) {
p->o_args.min_tm = val ;
}
void
p3_set_gs_primer_internal_oligo_opt_bound(p3_global_settings * p , double val) {
p->o_args.opt_bound = val ;
}
void
p3_set_gs_primer_internal_oligo_max_bound(p3_global_settings * p , double val) {
p->o_args.max_bound = val ;
}
void
p3_set_gs_primer_internal_oligo_min_bound(p3_global_settings * p , double val) {
p->o_args.min_bound = val ;
}
void
p3_set_gs_primer_internal_oligo_min_gc(p3_global_settings * p , double val) {
p->o_args.min_gc = val ;
}
void
p3_set_gs_primer_internal_oligo_max_gc(p3_global_settings * p , double val) {
p->o_args.max_gc = val ;
}
void
p3_set_gs_primer_internal_oligo_salt_conc(p3_global_settings * p , double val) {
p->o_args.salt_conc = val ;
}
void
p3_set_gs_primer_internal_oligo_divalent_conc(p3_global_settings * p , double val) {
p->o_args.divalent_conc = val ;
}
void
p3_set_gs_primer_internal_oligo_dntp_conc(p3_global_settings * p , double val) {
p->o_args.dntp_conc = val ;
}
void
p3_set_gs_primer_internal_oligo_dna_conc(p3_global_settings * p , double val) {
p->o_args.dna_conc = val ;
}
void
p3_set_gs_primer_internal_oligo_dmso_conc(p3_global_settings * p , double val) {
p->o_args.dmso_conc = val ;
}
void
p3_set_gs_primer_internal_oligo_dmso_fact(p3_global_settings * p , double val) {
p->o_args.dmso_fact = val ;
}
void
p3_set_gs_primer_internal_oligo_formamide_conc(p3_global_settings * p , double val) {
p->o_args.formamide_conc = val ;
}
void
p3_set_gs_primer_internal_oligo_num_ns(p3_global_settings * p , int val) {
p->o_args.num_ns_accepted = val ;
}
void
p3_set_gs_primer_internal_oligo_min_quality(p3_global_settings * p , int val) {
p->o_args.min_quality = val ;
}
void
p3_set_gs_primer_internal_oligo_self_any(p3_global_settings * p , double val) {
p->o_args.max_self_any = val;
}
void
p3_set_gs_primer_internal_oligo_self_any_th(p3_global_settings * p , double val) {
p->o_args.max_self_any_th = val;
}
void
p3_set_gs_primer_internal_oligo_self_end(p3_global_settings * p , double val) {
p->o_args.max_self_end = val; /* (short) (val * 100); */
}
void
p3_set_gs_primer_internal_oligo_self_end_th(p3_global_settings * p , double val) {
p->o_args.max_self_end_th = val;
}
void
p3_set_gs_primer_internal_oligo_hairpin_th(p3_global_settings * p , double val) {
p->o_args.max_hairpin_th = val;
}
void
p3_set_gs_primer_max_mispriming(p3_global_settings * p , double val) {
p->p_args.max_repeat_compl = val;
}
void
p3_set_gs_primer_internal_oligo_max_mishyb(p3_global_settings * p , double val) {
p->o_args.max_repeat_compl = val;
}
void
p3_set_gs_primer_pair_max_mispriming(p3_global_settings * p , double val) {
p->pair_repeat_compl = val;
}
void
p3_set_gs_primer_max_template_mispriming(p3_global_settings * p , double val) {
p->p_args.max_template_mispriming = val;
}
void
p3_set_gs_primer_max_template_mispriming_th(p3_global_settings * p , double val) {
p->p_args.max_template_mispriming_th = val;
}
void
p3_set_gs_primer_lib_ambiguity_codes_consensus(p3_global_settings * p , int val) {
p->lib_ambiguity_codes_consensus = val ;
}
void
p3_set_gs_primer_inside_penalty(p3_global_settings * p , double val) {
p->inside_penalty = val ;
}
void
p3_set_gs_primer_outside_penalty(p3_global_settings * p , double val) {
p->outside_penalty = val ;
}
void
p3_set_gs_primer_mispriming_library(p3_global_settings * p , char * path) {
/* TO DO: Re-factor this? TO DO: Check for errors */
p->p_args.repeat_lib = read_and_create_seq_lib(path, "mispriming library") ;
}
void
p3_set_gs_primer_internal_oligo_mishyb_library(p3_global_settings * p , char * path) {
/* TO DO: Re-factor this? TO DO: Check for errors */
p->o_args.repeat_lib = read_and_create_seq_lib(path, "internal oligio mishyb library") ;
}
void
p3_set_gs_primer_max_end_stability(p3_global_settings * p , double val) {
p->max_end_stability = val ;
}
void
p3_set_gs_primer_lowercase_masking(p3_global_settings * p , int val) {
p->lowercase_masking = val ;
}
void
p3_set_gs_primer_thermodynamic_oligo_alignment(p3_global_settings * p , int val) {
p->thermodynamic_oligo_alignment = val ;
}
void
p3_set_gs_primer_thermodynamic_template_alignment(p3_global_settings * p , int val) {
p->thermodynamic_template_alignment = val ;
}
void
p3_set_gs_primer_wt_tm_gt(p3_global_settings * p , double val) {
p->p_args.weights.temp_gt = val ;
}
void
p3_set_gs_primer_wt_tm_lt(p3_global_settings * p , double val) {
p->p_args.weights.temp_lt = val ;
}
void
p3_set_gs_primer_wt_bound_gt(p3_global_settings * p , double val) {
p->p_args.weights.bound_gt = val ;
}
void
p3_set_gs_primer_wt_bound_lt(p3_global_settings * p , double val) {
p->p_args.weights.bound_lt = val ;
}
void
p3_set_gs_primer_wt_gc_percent_gt(p3_global_settings * p , double val) {
p->p_args.weights.gc_content_gt = val ;
}
void
p3_set_gs_primer_wt_gc_percent_lt(p3_global_settings * p , double val) {
p->p_args.weights.gc_content_lt = val ;
}
void
p3_set_gs_primer_wt_size_lt(p3_global_settings * p , double val) {
p->p_args.weights.length_lt = val ;
}
void
p3_set_gs_primer_wt_size_gt(p3_global_settings * p , double val) {
p->p_args.weights.length_gt = val ;
}
void
p3_set_gs_primer_wt_compl_any(p3_global_settings * p , double val) {
p->p_args.weights.compl_any = val ;
}
void
p3_set_gs_primer_wt_compl_any_th(p3_global_settings * p , double val) {
p->p_args.weights.compl_any_th = val ;
}
void
p3_set_gs_primer_wt_compl_end(p3_global_settings * p , double val) {
p->p_args.weights.compl_end = val ;
}
void
p3_set_gs_primer_wt_compl_end_th(p3_global_settings * p , double val) {
p->p_args.weights.compl_end_th = val ;
}
void
p3_set_gs_primer_wt_hairpin_th(p3_global_settings * p , double val) {
p->p_args.weights.hairpin_th = val ;
}
void
p3_set_gs_primer_wt_num_ns(p3_global_settings * p , double val) {
p->p_args.weights.num_ns = val ;
}
void
p3_set_gs_primer_wt_rep_sim(p3_global_settings * p , double val) {
p->p_args.weights.repeat_sim = val ;
}
void
p3_set_gs_primer_wt_seq_qual(p3_global_settings * p , double val) {
p->p_args.weights.seq_quality = val ;
}
void
p3_set_gs_primer_wt_end_qual(p3_global_settings * p , double val) {
p->p_args.weights.end_quality = val ;
}
void
p3_set_gs_primer_wt_pos_penalty(p3_global_settings * p , double val){
p->p_args.weights.pos_penalty = val ;
}
void
p3_set_gs_primer_wt_end_stability(p3_global_settings * p , double val) {
p->p_args.weights.end_stability = val ;
}
void
p3_set_gs_primer_wt_template_mispriming(p3_global_settings * p , double val) {
p->p_args.weights.template_mispriming = val ;
}
void
p3_set_gs_primer_wt_template_mispriming_th(p3_global_settings * p , double val) {
p->p_args.weights.template_mispriming_th = val ;
}
void
p3_set_gs_primer_io_wt_tm_gt(p3_global_settings * p , double val) {
p->o_args.weights.temp_gt = val ;
}
void
p3_set_gs_primer_io_wt_tm_lt(p3_global_settings * p , double val){
p->o_args.weights.temp_lt = val ;
}
void
p3_set_gs_primer_io_wt_bound_gt(p3_global_settings * p , double val) {
p->o_args.weights.bound_gt = val ;
}
void
p3_set_gs_primer_io_wt_bound_lt(p3_global_settings * p , double val){
p->o_args.weights.bound_lt = val ;
}
void
p3_set_gs_primer_io_wt_gc_percent_gt(p3_global_settings * p , double val) {
p->o_args.weights.gc_content_gt = val ;
}
void
p3_set_gs_primer_io_wt_gc_percent_lt(p3_global_settings * p , double val) {
p->o_args.weights.gc_content_lt = val ;
}
void
p3_set_gs_primer_io_wt_size_lt(p3_global_settings * p , double val) {
p->o_args.weights.length_lt = val ;
}
void
p3_set_gs_primer_io_wt_size_gt(p3_global_settings * p , double val) {
p->o_args.weights.length_gt = val ;
}
void
p3_set_gs_primer_io_wt_wt_compl_any(p3_global_settings * p , double val) {
p->o_args.weights.compl_any = val ;
}
void
p3_set_gs_primer_io_wt_wt_compl_any_th(p3_global_settings * p , double val) {
p->o_args.weights.compl_any_th = val ;
}
void
p3_set_gs_primer_io_wt_compl_end(p3_global_settings * p , double val) {
p->o_args.weights.compl_end = val ;
}
void
p3_set_gs_primer_io_wt_compl_end_th(p3_global_settings * p , double val) {
p->o_args.weights.compl_end_th = val ;
}
void
p3_set_gs_primer_io_wt_hairpin_th(p3_global_settings * p , double val) {
p->o_args.weights.hairpin_th = val ;
}
void
p3_set_gs_primer_io_wt_num_ns(p3_global_settings * p , double val) {
p->o_args.weights.num_ns = val ;
}
void
p3_set_gs_primer_io_wt_rep_sim(p3_global_settings * p , double val) {
p->o_args.weights.repeat_sim = val ;
}
void
p3_set_gs_primer_io_wt_seq_qual(p3_global_settings * p , double val) {
p->o_args.weights.seq_quality = val ;
}
void
p3_set_gs_primer_io_wt_end_qual(p3_global_settings * p , double val) {
p->o_args.weights.end_quality = val ;
}
void
p3_set_gs_primer_pair_wt_pr_penalty(p3_global_settings * p , double val) {
p->pr_pair_weights.primer_quality = val ;
}
void
p3_set_gs_primer_pair_wt_io_penalty(p3_global_settings * p , double val) {
p->pr_pair_weights.io_quality = val ;
}
void
p3_set_gs_primer_pair_wt_diff_tm(p3_global_settings * p , double val) {
p->pr_pair_weights.diff_tm = val ;
}
void
p3_set_gs_primer_pair_wt_compl_any(p3_global_settings * p , double val) {
p->pr_pair_weights.compl_any = val ;
}
void
p3_set_gs_primer_pair_wt_compl_any_th(p3_global_settings * p , double val) {
p->pr_pair_weights.compl_any_th = val ;
}
void
p3_set_gs_primer_pair_wt_compl_end(p3_global_settings * p , double val) {
p->pr_pair_weights.compl_end = val ;
}
void
p3_set_gs_primer_pair_wt_compl_end_th(p3_global_settings * p , double val) {
p->pr_pair_weights.compl_end_th = val ;
}
void
p3_set_gs_primer_pair_wt_product_tm_lt(p3_global_settings * p , double val) {
p->pr_pair_weights.product_tm_lt = val ;
}
void
p3_set_gs_primer_pair_wt_product_tm_gt(p3_global_settings * p , double val) {
p->pr_pair_weights.product_tm_gt = val ;
}
void
p3_set_gs_primer_pair_wt_product_size_gt(p3_global_settings * p , double val) {
p->pr_pair_weights.product_size_gt = val ;
}
void
p3_set_gs_primer_pair_wt_product_size_lt(p3_global_settings * p , double val) {
p->pr_pair_weights.product_size_lt = val ;
}
void
p3_set_gs_primer_pair_wt_rep_sim(p3_global_settings * p , double val) {
p->pr_pair_weights.repeat_sim = val ;
}
void
p3_set_gs_primer_pair_wt_template_mispriming(p3_global_settings * p , double val) {
p->pr_pair_weights.template_mispriming = val ;
}
void
p3_set_gs_primer_pair_wt_template_mispriming_th(p3_global_settings * p , double val){
p->pr_pair_weights.template_mispriming_th = val ;
}
void
p3_set_gs_lib_ambiguity_codes_consensus(p3_global_settings * p,
int lib_ambiguity_codes_consensus)
{
p->lib_ambiguity_codes_consensus = lib_ambiguity_codes_consensus;
}
void
p3_set_gs_quality_range_min(p3_global_settings * p , int quality_range_min){
p->quality_range_min = quality_range_min;
}
void
p3_set_gs_quality_range_max(p3_global_settings * p , int quality_range_max){
p->quality_range_max = quality_range_max ;
}
void
p3_set_gs_max_end_gc(p3_global_settings *p, int max_end_gc) {
p->max_end_gc = max_end_gc;
}
void
p3_set_gs_max_end_stability(p3_global_settings * p , int max_end_stability){
p->max_end_stability = max_end_stability;
}
void
p3_set_gs_lowercase_masking(p3_global_settings * p , int lowercase_masking){
p->lowercase_masking = lowercase_masking;
}
void
p3_set_gs_outside_penalty(p3_global_settings * p , double outside_penalty){
p->outside_penalty = outside_penalty;
}
void
p3_set_gs_inside_penalty(p3_global_settings * p , double inside_penalty){
p->inside_penalty = inside_penalty;
}
void
p3_set_gs_pair_max_template_mispriming(p3_global_settings * p,
double pair_max_template_mispriming)
{
p->pair_max_template_mispriming = pair_max_template_mispriming;
}
void
p3_set_gs_pair_max_template_mispriming_th(p3_global_settings * p,
double pair_max_template_mispriming_th)
{
p->pair_max_template_mispriming_th = pair_max_template_mispriming_th;
}
void
p3_set_gs_pair_repeat_compl(p3_global_settings * p, double pair_repeat_compl)
{
p->pair_repeat_compl = pair_repeat_compl;
}
void
p3_set_gs_pair_compl_any(p3_global_settings * p , double pair_compl_any)
{
p->pair_compl_any = pair_compl_any;
}
void
p3_set_gs_pair_compl_any_th(p3_global_settings * p , double pair_compl_any_th)
{
p->pair_compl_any_th = pair_compl_any_th;
}
void
p3_set_gs_pair_compl_end(p3_global_settings * p , double pair_compl_end)
{
p->pair_compl_end = pair_compl_end;
}
void
p3_set_gs_pair_compl_end_th(p3_global_settings * p , double pair_compl_end_th)
{
p->pair_compl_end = pair_compl_end_th;
}
void
p3_set_gs_min_left_three_prime_distance(p3_global_settings *p, int min_distance)
{
p->min_left_three_prime_distance = min_distance;
}
void
p3_set_gs_min_internal_three_prime_distance(p3_global_settings *p, int min_distance)
{
p->min_internal_three_prime_distance = min_distance;
}
void
p3_set_gs_min_right_three_prime_distance(p3_global_settings *p, int min_distance)
{
p->min_right_three_prime_distance = min_distance;
}
void
p3_set_gs_min_5_prime_overlap_of_junction(p3_global_settings *p, int min_5_prime)
{
p->p_args.min_5_prime_overlap_of_junction = min_5_prime;
}
void
p3_set_gs_min_3_prime_overlap_of_junction(p3_global_settings *p, int min_3_prime)
{
p->p_args.min_3_prime_overlap_of_junction = min_3_prime;
}
void
p3_set_gs_min_5_internal_overlap_of_junction(p3_global_settings *p, int min_5_prime)
{
p->o_args.min_5_prime_overlap_of_junction = min_5_prime;
}
void
p3_set_gs_min_3_internal_overlap_of_junction(p3_global_settings *p, int min_3_prime)
{
p->o_args.min_3_prime_overlap_of_junction = min_3_prime;
}
void
p3_set_gs_max_diff_tm(p3_global_settings * p , double max_diff_tm) {
p->max_diff_tm = max_diff_tm;
}
void
p3_set_gs_primer_pick_anyway(p3_global_settings * p , int val) {
p->pick_anyway = val ;
}
void
p3_set_gs_primer_gc_clamp(p3_global_settings * p , int val) {
p->gc_clamp = val;
}
void
p3_empty_gs_product_size_range(p3_global_settings *pgs) {
pgs->num_intervals = 0;
}
int
p3_add_to_gs_product_size_range(p3_global_settings *pgs,
int n1, int n2) {
if (pgs->num_intervals >= PR_MAX_INTERVAL_ARRAY) {
return 1;
}
pgs->pr_min[pgs->num_intervals] = n1;
pgs->pr_max[pgs->num_intervals] = n2;
pgs->num_intervals++;
return 0;
}
/* ============================================================ */
/* END 'set' functions for p3_global_settings */
/* ============================================================ */
/* ============================================================ */
/* START functions for setting and getting oligo problems */
/* ============================================================ */
static void
initialize_op(primer_rec *oligo) {
oligo->problems.prob = 0UL; /* 0UL is the unsigned long zero */
}
/* We use bitfields to store all primer data. The idea is that
* a primer is uninitialized if all bits are 0. It was evaluated
* if OP_PARTIALLY_WRITTEN is true. If OP_COMPLETELY_WRITTEN is
* also true the primer was evaluated till the end - meaning if
* all OP_... are false, the primer is OK, if some are true
* primer3 was forced to use it (must_use). */
#define OP_PARTIALLY_WRITTEN (1UL << 0)
#define OP_COMPLETELY_WRITTEN (1UL << 1)
#define BF_OVERLAPS_TARGET (1UL << 2)
#define BF_OVERLAPS_EXCL_REGION (1UL << 3)
#define BF_INFINITE_POSITION_PENALTY (1UL << 4)
/* Space for more bitfields */
#define OP_HIGH_BOUND (1UL << 5)
#define OP_LOW_BOUND (1UL << 6)
#define OP_NOT_IN_ANY_OK_REGION (1UL << 7)
#define OP_TOO_MANY_NS (1UL << 8) /* 3prime problem*/
#define OP_OVERLAPS_TARGET (1UL << 9) /* 3prime problem*/
#define OP_HIGH_GC_CONTENT (1UL << 10)
#define OP_LOW_GC_CONTENT (1UL << 11)
#define OP_HIGH_TM (1UL << 12)
#define OP_LOW_TM (1UL << 13)
#define OP_OVERLAPS_EXCL_REGION (1UL << 14) /* 3prime problem*/
#define OP_HIGH_SELF_ANY (1UL << 15) /* 3prime problem*/
#define OP_HIGH_SELF_END (1UL << 16)
#define OP_NO_GC_CLAMP (1UL << 17) /* 3prime problem*/
#define OP_HIGH_END_STABILITY (1UL << 18) /* 3prime problem*/
#define OP_HIGH_POLY_X (1UL << 19) /* 3prime problem*/
#define OP_LOW_SEQUENCE_QUALITY (1UL << 20) /* 3prime problem*/
#define OP_LOW_END_SEQUENCE_QUALITY (1UL << 21) /* 3prime problem*/
#define OP_HIGH_SIM_TO_NON_TEMPLATE_SEQ (1UL << 22) /* 3prime problem*/
#define OP_HIGH_SIM_TO_MULTI_TEMPLATE_SITES (1UL << 23)
#define OP_OVERLAPS_MASKED_SEQ (1UL << 24)
#define OP_TOO_LONG (1UL << 25) /* 3prime problem*/
#define OP_TOO_SHORT (1UL << 26)
#define OP_DOES_NOT_AMPLIFY_ORF (1UL << 27)
#define OP_TOO_MANY_GC_AT_END (1UL << 28) /* 3prime problem*/
#define OP_HIGH_HAIRPIN (1UL << 29) /* 3prime problem*/
#define OP_MUST_MATCH_ERR (1UL << 30)
/* Space for more Errors */
/* Tip: the calculator of windows (in scientific mode) can easily convert
between decimal and binary numbers */
/* all bits 1 except bits 0 to 6 */
/* (~0UL) ^ 31UL = 1111 1111 1111 1111 1111 1111 1110 0000 */
static unsigned long int any_problem = (~0UL) ^ 31UL;
/* 310297344UL = 0001 0010 0111 1110 1100 0011 0000 0000 */
static unsigned long int five_prime_problem = 310297344UL;
int
p3_ol_is_uninitialized(const primer_rec *oligo) {
return (oligo->problems.prob == 0UL);
}
int
p3_ol_is_ok(const primer_rec *oligo) {
return (oligo->problems.prob & OP_COMPLETELY_WRITTEN) != 0;
}
/*
Return 1 iff the argument 'oligo' has any problems -- i.e.
violations of design constraints.
*/
int
p3_ol_has_any_problem(const primer_rec *oligo) {
return (oligo->problems.prob & any_problem) != 0;
}
static int
any_5_prime_ol_extension_has_problem(const primer_rec *oligo) {
return (oligo->problems.prob & five_prime_problem) != 0;
}
/*
Return a string details the the problems in 'oligo', i.e. the
constraints that 'oligo' violates. WARNING: Returns a pointer to
static storage, which is over-written on next call.
*/
#define ADD_OP_STR(COND, STR) if (prob & COND) { tmp = STR; strcpy(next, tmp); next += (int)strlen(tmp); }
const char *
p3_get_ol_problem_string(const primer_rec *oligo) {
static char output[4096*2]; /* WARNING, make sure all error strings
concatenated will not overflow this
buffer. */
char *next = output;
const char *tmp;
unsigned long int prob = oligo->problems.prob;
output[0] = '\0';
if (
(prob & OP_PARTIALLY_WRITTEN)
&&
!(prob & OP_COMPLETELY_WRITTEN)
) {
tmp = " Not completely checked;";
strcpy(next, tmp);
next += (int)strlen(tmp);
}
{
ADD_OP_STR(OP_TOO_MANY_NS,
" Too many Ns;")
ADD_OP_STR(OP_OVERLAPS_TARGET,
" Overlaps target;")
ADD_OP_STR(OP_HIGH_GC_CONTENT,
" GC content too high;")
ADD_OP_STR(OP_LOW_GC_CONTENT,
" GC content too low;")
ADD_OP_STR(OP_HIGH_TM,
" Temperature too high;")
ADD_OP_STR(OP_LOW_TM,
" Temperature too low;")
ADD_OP_STR(OP_HIGH_BOUND,
" Fraction bound too high;")
ADD_OP_STR(OP_LOW_BOUND,
" Fraction bound too low;")
ADD_OP_STR(OP_OVERLAPS_EXCL_REGION,
" Overlaps an excluded region;")
ADD_OP_STR(OP_NOT_IN_ANY_OK_REGION,
" Not in any ok region;")
ADD_OP_STR(OP_HIGH_SELF_ANY,
" Similarity to self too high;")
ADD_OP_STR(OP_HIGH_SELF_END,
" Similary to 3' end of self too high;")
ADD_OP_STR(OP_HIGH_HAIRPIN,
" Hairpin stability too high;")
ADD_OP_STR(OP_NO_GC_CLAMP,
" No 3' GC clamp;")
ADD_OP_STR(OP_TOO_MANY_GC_AT_END,
" Too many GCs at 3' end;")
ADD_OP_STR(OP_HIGH_END_STABILITY,
" 3' end too stable (delta-G too high);")
ADD_OP_STR(OP_HIGH_POLY_X,
" Contains too-long poly nucleotide tract;")
ADD_OP_STR(OP_LOW_SEQUENCE_QUALITY,
" Template sequence quality too low;")
ADD_OP_STR(OP_LOW_END_SEQUENCE_QUALITY,
" Template sequence quality at 3' end too low;")
ADD_OP_STR(OP_HIGH_SIM_TO_NON_TEMPLATE_SEQ,
" Similarity to non-template sequence too high;")
ADD_OP_STR(OP_HIGH_SIM_TO_MULTI_TEMPLATE_SITES,
" Similarity to multiple sites in template;")
ADD_OP_STR(OP_OVERLAPS_MASKED_SEQ,
" 3' base overlaps masked sequence;")
ADD_OP_STR(OP_TOO_LONG,
" Too long;")
ADD_OP_STR(OP_TOO_SHORT,
" Too short;")
ADD_OP_STR(OP_DOES_NOT_AMPLIFY_ORF,
" Would not amplify an open reading frame;")
ADD_OP_STR(OP_MUST_MATCH_ERR,
" Failed must_match requirements;")
}
return output;
}
#undef ADD_OP_STR
static void
bf_set_overlaps_target(primer_rec *oligo, int val){
if (val == 0) {
oligo->problems.prob |= BF_OVERLAPS_TARGET;
oligo->problems.prob ^= BF_OVERLAPS_TARGET;
} else {
oligo->problems.prob |= BF_OVERLAPS_TARGET;
}
}
static int
bf_get_overlaps_target(const primer_rec *oligo) {
return (oligo->problems.prob & BF_OVERLAPS_TARGET) != 0;
}
static void
bf_set_overlaps_excl_region(primer_rec *oligo, int val){
if (val == 0) {
oligo->problems.prob |= BF_OVERLAPS_EXCL_REGION;
oligo->problems.prob ^= BF_OVERLAPS_EXCL_REGION;
} else {
oligo->problems.prob |= BF_OVERLAPS_EXCL_REGION;
}
}
static int
bf_get_overlaps_excl_region(const primer_rec *oligo) {
return (oligo->problems.prob & BF_OVERLAPS_EXCL_REGION) != 0;
}
static void
bf_set_infinite_pos_penalty(primer_rec *oligo, int val){
if (val == 0) {
oligo->problems.prob |= BF_INFINITE_POSITION_PENALTY;
oligo->problems.prob ^= BF_INFINITE_POSITION_PENALTY;
} else {
oligo->problems.prob |= BF_INFINITE_POSITION_PENALTY;
}
}
static int
bf_get_infinite_pos_penalty(const primer_rec *oligo) {
return (oligo->problems.prob & BF_INFINITE_POSITION_PENALTY) != 0;
}
static void
op_set_does_not_amplify_orf(primer_rec *oligo) {
oligo->problems.prob |= OP_DOES_NOT_AMPLIFY_ORF;
oligo->problems.prob |= OP_PARTIALLY_WRITTEN;
}
static void
op_set_completely_written(primer_rec *oligo) {
oligo->problems.prob |= OP_COMPLETELY_WRITTEN;
}
static void
op_set_must_match_err(primer_rec *oligo) {
oligo->problems.prob |= OP_MUST_MATCH_ERR;
oligo->problems.prob |= OP_PARTIALLY_WRITTEN;
}
static void
op_set_too_many_ns(primer_rec *oligo) {
oligo->problems.prob |= OP_TOO_MANY_NS;
oligo->problems.prob |= OP_PARTIALLY_WRITTEN;
}
static void
op_set_overlaps_target(primer_rec *oligo) {
oligo->problems.prob |= OP_OVERLAPS_TARGET;
oligo->problems.prob |= OP_PARTIALLY_WRITTEN;
}
static void
op_set_high_gc_content(primer_rec *oligo) {
oligo->problems.prob |= OP_HIGH_GC_CONTENT;
oligo->problems.prob |= OP_PARTIALLY_WRITTEN;
}
static void
op_set_low_gc_content(primer_rec *oligo) {
oligo->problems.prob |= OP_LOW_GC_CONTENT;
oligo->problems.prob |= OP_PARTIALLY_WRITTEN;
}
static void
op_set_high_tm(primer_rec *oligo) {
oligo->problems.prob |= OP_HIGH_TM;
oligo->problems.prob |= OP_PARTIALLY_WRITTEN;
}
static void
op_set_low_tm(primer_rec *oligo) {
oligo->problems.prob |= OP_LOW_TM;
oligo->problems.prob |= OP_PARTIALLY_WRITTEN;
}
static void
op_set_high_bound(primer_rec *oligo) {
oligo->problems.prob |= OP_HIGH_BOUND;
oligo->problems.prob |= OP_PARTIALLY_WRITTEN;
}
static void
op_set_low_bound(primer_rec *oligo) {
oligo->problems.prob |= OP_LOW_BOUND;
oligo->problems.prob |= OP_PARTIALLY_WRITTEN;
}
static void
op_set_overlaps_excluded_region(primer_rec *oligo) {
oligo->problems.prob |= OP_OVERLAPS_EXCL_REGION;
oligo->problems.prob |= OP_PARTIALLY_WRITTEN;
}
static void
op_set_not_in_any_ok_region(primer_rec *oligo) {
oligo->problems.prob |= OP_NOT_IN_ANY_OK_REGION;
oligo->problems.prob |= OP_PARTIALLY_WRITTEN;
}
static void
op_set_high_self_any(primer_rec *oligo) {
oligo->problems.prob |= OP_HIGH_SELF_ANY;
oligo->problems.prob |= OP_PARTIALLY_WRITTEN;
}
static void
op_set_high_self_end(primer_rec *oligo) {
oligo->problems.prob |= OP_HIGH_SELF_END;
oligo->problems.prob |= OP_PARTIALLY_WRITTEN;
}
static void
op_set_high_hairpin_th(primer_rec *oligo) {
oligo->problems.prob |= OP_HIGH_HAIRPIN;
oligo->problems.prob |= OP_PARTIALLY_WRITTEN;
}
static void
op_set_no_gc_glamp(primer_rec *oligo) {
oligo->problems.prob |= OP_NO_GC_CLAMP;
oligo->problems.prob |= OP_PARTIALLY_WRITTEN;
}
static void
op_set_too_many_gc_at_end(primer_rec *oligo) {
oligo->problems.prob |= OP_TOO_MANY_GC_AT_END;
oligo->problems.prob |= OP_PARTIALLY_WRITTEN;
}
/* Must not be called on a hybridization probe / internal oligo */
static void
op_set_high_end_stability(primer_rec *oligo) {
oligo->problems.prob |= OP_HIGH_END_STABILITY;
oligo->problems.prob |= OP_PARTIALLY_WRITTEN;
}
static void
op_set_high_poly_x(primer_rec *oligo) {
oligo->problems.prob |= OP_HIGH_POLY_X;
oligo->problems.prob |= OP_PARTIALLY_WRITTEN;
}
static void
op_set_low_sequence_quality(primer_rec *oligo) {
oligo->problems.prob |= OP_LOW_SEQUENCE_QUALITY;
oligo->problems.prob |= OP_PARTIALLY_WRITTEN;
}
static void
op_set_low_end_sequence_quality(primer_rec *oligo) {
oligo->problems.prob |= OP_LOW_END_SEQUENCE_QUALITY;
oligo->problems.prob |= OP_PARTIALLY_WRITTEN;
}
static void
op_set_high_similarity_to_non_template_seq(primer_rec *oligo) {
oligo->problems.prob |= OP_HIGH_SIM_TO_NON_TEMPLATE_SEQ;
oligo->problems.prob |= OP_PARTIALLY_WRITTEN;
}
static void
op_set_high_similarity_to_multiple_template_sites(primer_rec *oligo) {
oligo->problems.prob |= OP_HIGH_SIM_TO_MULTI_TEMPLATE_SITES;
oligo->problems.prob |= OP_PARTIALLY_WRITTEN;
}
static void
op_set_overlaps_masked_sequence(primer_rec *oligo) {
oligo->problems.prob |= OP_OVERLAPS_MASKED_SEQ;
oligo->problems.prob |= OP_PARTIALLY_WRITTEN;
}
static void
op_set_too_long(primer_rec *oligo) {
oligo->problems.prob |= OP_TOO_LONG;
oligo->problems.prob |= OP_PARTIALLY_WRITTEN;
}
static void
op_set_too_short(primer_rec *oligo) {
oligo->problems.prob |= OP_TOO_SHORT;
oligo->problems.prob |= OP_PARTIALLY_WRITTEN;
}
/* ============================================================ */
/* END functions for setting and getting oligo problems */
/* ============================================================ */
/* ============================================================ */
/* START functions for getting values from p3retvals */
/* ============================================================ */
char *
p3_get_rv_and_gs_warnings(const p3retval *retval,
const p3_global_settings *pa) {
pr_append_str warning;
PR_ASSERT(NULL != pa);
init_pr_append_str(&warning);
if (seq_lib_warning_data(pa->p_args.repeat_lib)) {
pr_append_new_chunk(&warning, seq_lib_warning_data(pa->p_args.repeat_lib));
}
if(seq_lib_warning_data(pa->o_args.repeat_lib)) {
pr_append_new_chunk(&warning, seq_lib_warning_data(pa->o_args.repeat_lib));
pr_append(&warning, " (for internal oligo)");
}
if (!pr_is_empty(&retval->warnings)) {
pr_append_new_chunk(&warning, retval->warnings.data);
}
return pr_is_empty(&warning) ? NULL : warning.data;
}
const char *
p3_get_rv_global_errors(const p3retval *retval) {
return retval->glob_err.data;
}
const char *
p3_get_rv_per_sequence_errors(const p3retval *retval) {
return retval->per_sequence_err.data;
}
p3_output_type
p3_get_rv_output_type(const p3retval *r) {
return r->output_type;
}
const char *
p3_get_rv_warnings(const p3retval *r) {
return pr_append_str_chars(&r->warnings);
}
int
p3_get_rv_stop_codon_pos(p3retval *r) {
return r->stop_codon_pos;
}
/* ============================================================ */
/* END functions for getting values from p3retvals */
/* ============================================================ */
void
print_masking_parameters(const masker_parameters *mp, FILE* fd)
{
if (mp == NULL){
return;
}
// unsigned int i;
fprintf (fd, "Current masker parameters:\n");
fprintf (fd, " masking_direction = %s\n", mp->mdir == both_on_same ? "both" : (mp->mdir == fwd ? "fwd" : "rev"));
fprintf (fd, " failure_rate = %f\n", mp->failure_rate);
fprintf (fd, " abs_cutoff = %u\n", mp->abs_cutoff);
fprintf (fd, " m5p = %u\n", mp->nucl_masked_in_5p_direction);
fprintf (fd, " m3p = %u\n", mp->nucl_masked_in_3p_direction);
fprintf (fd, " print_sequence = %d\n", mp->print_sequence);
fprintf (fd, " do_soft_masking = %d\n", mp->do_soft_masking);
fprintf (fd, " masking_char = %c\n", mp->masking_char);
fprintf (fd, " nlists = %u\n", mp->nlists);
fprintf (fd, " intercept = %f\n", mp->formula_intercept);
// for (i = 0; i < mp->nlists; i++) {
// fprintf (fd, " LIST: %u\n", i);
// formula_parameters *fp = mp->fp[i];
// if (!fp) continue;
// fprintf (fd, " name = %s\n", fp->list_file_name);
// fprintf (fd, " oligo_length = %u\n", fp->oligo_length);
// fprintf (fd, " words_in_list = %llu\n", fp->words_in_list);
// fprintf (fd, " mm0 %f mm1 %f mm2 %f mm0_2 %f mm1_2 %f mm2_2 %f\n", fp->mm0, fp->mm1, fp->mm2, fp->mm0_2, fp->mm1_2, fp->mm2_2);
// }
return;
}
void
p3_print_args(const p3_global_settings *p, seq_args_t* s) {
p3_print_args_fd(p, s, stdout);
}
void
p3_print_args_fd(const p3_global_settings *p, seq_args_t* s, FILE* fd)
{
int i;
if (p != NULL) {
fprintf(fd, "=============\n");
fprintf(fd, "BEGIN GLOBAL ARGS\n") ;
fprintf(fd, " primer_task %i\n", p->primer_task);
fprintf(fd, " pick_left_primer %i\n", p->pick_left_primer);
fprintf(fd, " pick_right_primer %i\n", p->pick_right_primer);
fprintf(fd, " pick_internal_oligo %i\n", p->pick_internal_oligo);
fprintf(fd, " file_flag %i\n", p->file_flag) ;
fprintf(fd, " first_base_index %i\n", p->first_base_index);
fprintf(fd, " liberal_base %i\n", p->liberal_base );
fprintf(fd, " num_return %i\n", p->num_return) ;
fprintf(fd, " pick_anyway %i\n", p->pick_anyway);
fprintf(fd, " lib_ambiguity_codes_consensus %i\n",
p->lib_ambiguity_codes_consensus) ;
fprintf(fd, " quality_range_min %i\n", p->quality_range_min) ;
fprintf(fd, " quality_range_max %i\n", p->quality_range_max) ;
fprintf(fd, " tm_santalucia %i\n", p->tm_santalucia) ;
fprintf(fd, " salt_corrections %i\n", p->salt_corrections) ;
fprintf(fd, " annealing_temp %f\n", p->annealing_temp) ;
fprintf(fd, " max_end_stability %f\n", p->max_end_stability) ;
fprintf(fd, " gc_clamp %i\n", p->gc_clamp) ;
fprintf(fd, " max_end_gc %i\n", p->max_end_gc);
fprintf(fd, " lowercase_masking %i\n", p->lowercase_masking) ;
fprintf(fd, " thermodynamic_oligo_alignment %i\n", p->thermodynamic_oligo_alignment);
fprintf(fd, " thermodynamic_template_alignment %i\n", p->thermodynamic_template_alignment);
fprintf(fd, " outside_penalty %f\n", p->outside_penalty) ;
fprintf(fd, " inside_penalty %f\n", p->inside_penalty) ;
fprintf(fd, " number of product size ranges: %d\n", p->num_intervals);
fprintf(fd, " product size ranges:\n");
for (i = 0; i < p->num_intervals; i++) {
fprintf(fd, " %d - %d \n", p->pr_min[i], p->pr_max[i]);
}
fprintf(fd, " product_opt_size %i\n", p->product_opt_size) ;
fprintf(fd, " product_max_tm %f\n", p->product_max_tm) ;
fprintf(fd, " product_min_tm %f\n", p->product_min_tm) ;
fprintf(fd, " product_opt_tm %f\n", p->product_opt_tm) ;
fprintf(fd, " pair_max_template_mispriming %f\n", p->pair_max_template_mispriming) ;
fprintf(fd, " pair_max_template_mispriming_th %f\n", p->pair_max_template_mispriming_th) ;
fprintf(fd, " pair_repeat_compl %f\n", p->pair_repeat_compl) ;
fprintf(fd, " pair_compl_any %f\n", p->pair_compl_any) ;
fprintf(fd, " pair_compl_end %f\n", p->pair_compl_end) ;
fprintf(fd, " pair_compl_any_th %f\n", p->pair_compl_any_th) ;
fprintf(fd, " pair_compl_end_th %f\n", p->pair_compl_end_th) ;
fprintf(fd, " min_left_three_prime_distance %i\n", p->min_left_three_prime_distance) ;
fprintf(fd, " min_internal_three_prime_distance %i\n", p->min_internal_three_prime_distance) ;
fprintf(fd, " min_right_three_prime_distance %i\n", p->min_right_three_prime_distance) ;
fprintf(fd, " min_5_prime_overlap_of_junction %i\n", p->p_args.min_5_prime_overlap_of_junction);
fprintf(fd, " min_3_prime_overlap_of_junction %i\n", p->p_args.min_3_prime_overlap_of_junction);
fprintf(fd, " min_5_internal_overlap_of_junction %i\n", p->o_args.min_5_prime_overlap_of_junction);
fprintf(fd, " min_3_internal_overlap_of_junction %i\n", p->o_args.min_3_prime_overlap_of_junction);
fprintf(fd, " mask_template %i\n", p->mask_template);
fprintf(fd, " failure_rate %f\n", p->mp.failure_rate);
fprintf(fd, " nucl_masked_in_5p_direction %i\n", p->mp.nucl_masked_in_5p_direction);
fprintf(fd, " nucl_masked_in_3p_direction %i\n", p->mp.nucl_masked_in_3p_direction);
fprintf(fd, " list_prefix %s\n", p->mp.list_prefix);
fprintf(fd, " dump %i\n", p->dump);
fprintf(fd, " begin pr_pair_weights\n") ;
fprintf(fd, " primer_quality %f\n", p->pr_pair_weights.primer_quality) ;
fprintf(fd, " io_quality %f\n", p->pr_pair_weights.io_quality) ;
fprintf(fd, " diff_tm %f\n", p->pr_pair_weights.diff_tm) ;
fprintf(fd, " compl_any %f\n", p->pr_pair_weights.compl_any) ;
fprintf(fd, " compl_end %f\n", p->pr_pair_weights.compl_end) ;
fprintf(fd, " compl_any_th %f\n", p->pr_pair_weights.compl_any_th) ;
fprintf(fd, " compl_end_th %f\n", p->pr_pair_weights.compl_end_th) ;
fprintf(fd, " product_tm_lt %f\n", p->pr_pair_weights.product_tm_lt) ;
fprintf(fd, " product_tm_gt %f\n", p->pr_pair_weights.product_tm_gt) ;
fprintf(fd, " product_size_lt %f\n", p->pr_pair_weights.product_size_lt) ;
fprintf(fd, " product_size_gt %f\n", p->pr_pair_weights.product_size_gt) ;
fprintf(fd, " repeat_sim %f\n", p->pr_pair_weights.repeat_sim) ;
fprintf(fd, " template_mispriming %f\n", p->pr_pair_weights.template_mispriming) ;
fprintf(fd, " template_mispriming_th %f\n", p->pr_pair_weights.template_mispriming_th) ;
fprintf(fd, " end pair_weights\n") ;
fprintf(fd, "\n\n");
fprintf(fd, "=============\n");
fprintf(fd, "BEGIN primer_args\n");
fprintf(fd, "begin oligo_weights\n");
fprintf(fd, "temp_gt %f\n", p->p_args.weights.temp_gt) ;
fprintf(fd, "temp_lt %f\n", p->p_args.weights.temp_lt) ;
fprintf(fd, "bound_gt %f\n", p->p_args.weights.bound_gt) ;
fprintf(fd, "bound_lt %f\n", p->p_args.weights.bound_lt) ;
fprintf(fd, "gc_content_gt %f\n", p->p_args.weights.gc_content_gt) ;
fprintf(fd, "gc_content_lt %f\n", p->p_args.weights.gc_content_lt) ;
fprintf(fd, "compl_any %f\n", p->p_args.weights.compl_any) ;
fprintf(fd, "compl_end %f\n", p->p_args.weights.compl_end) ;
fprintf(fd, "compl_any_th %f\n", p->p_args.weights.compl_any_th) ;
fprintf(fd, "compl_end_th %f\n", p->p_args.weights.compl_end_th) ;
fprintf(fd, "hairpin %f\n", p->p_args.weights.hairpin_th) ;
fprintf(fd, "repeat_sim %f\n", p->p_args.weights.repeat_sim) ;
fprintf(fd, "length_lt %f\n", p->p_args.weights.length_lt) ;
fprintf(fd, "length_gt %f\n", p->p_args.weights.length_gt) ;
fprintf(fd, "seq_quality %f\n", p->p_args.weights.seq_quality) ;
fprintf(fd, "end_quality %f\n", p->p_args.weights.end_quality) ;
fprintf(fd, "pos_penalty %f\n", p->p_args.weights.pos_penalty) ;
fprintf(fd, "end_stability %f\n", p->p_args.weights.end_stability) ;
fprintf(fd, "num_ns %f\n", p->p_args.weights.num_ns) ;
fprintf(fd, "template_mispriming %f\n", p->p_args.weights.template_mispriming) ;
fprintf(fd, "template_mispriming_th %f\n", p->p_args.weights.template_mispriming_th) ;
fprintf(fd, "failure_rate %f\n", p->p_args.weights.failure_rate) ;
fprintf(fd, "end oligo_weights\n") ;
fprintf(fd, "opt_tm %f\n", p->p_args.opt_tm) ;
fprintf(fd, "min_tm %f\n", p->p_args.min_tm) ;
fprintf(fd, "max_tm %f\n", p->p_args.max_tm) ;
fprintf(fd, "opt_bound %f\n", p->p_args.opt_bound) ;
fprintf(fd, "min_bound %f\n", p->p_args.min_bound) ;
fprintf(fd, "max_bound %f\n", p->p_args.max_bound) ;
fprintf(fd, "opt_gc_content %f\n", p->p_args.opt_gc_content) ;
fprintf(fd, "max_gc %f\n", p->p_args.max_gc) ;
fprintf(fd, "min_gc %f\n", p->p_args.min_gc) ;
fprintf(fd, "divalent_conc %f\n", p->p_args.divalent_conc) ;
fprintf(fd, "dntp_conc %f\n", p->p_args.dntp_conc) ;
fprintf(fd, "dna_conc %f\n", p->p_args.dna_conc) ;
fprintf(fd, "dmso_conc %f\n", p->p_args.dmso_conc) ;
fprintf(fd, "dmso_fact %f\n", p->p_args.dmso_fact) ;
fprintf(fd, "formamide_conc %f\n", p->p_args.formamide_conc) ;
fprintf(fd, "num_ns_accepted %i\n", p->p_args.num_ns_accepted) ;
fprintf(fd, "opt_size %i\n", p->p_args.opt_size) ;
fprintf(fd, "min_size %i\n", p->p_args.min_size) ;
fprintf(fd, "max_size %i\n", p->p_args.max_size) ;
fprintf(fd, "max_poly_x %i\n", p->p_args.max_poly_x) ;
fprintf(fd, "min_end_quality %i\n", p->p_args.min_end_quality) ;
fprintf(fd, "min_quality %i\n", p->p_args.min_quality) ;
fprintf(fd, "max_self_any %f\n", p->p_args.max_self_any) ;
fprintf(fd, "max_self_end %f\n", p->p_args.max_self_end) ;
fprintf(fd, "max_self_any_th %f\n", p->p_args.max_self_any_th) ;
fprintf(fd, "max_self_end_th %f\n", p->p_args.max_self_end_th) ;
fprintf(fd, "max_hairpin %f\n", p->p_args.max_hairpin_th) ;
fprintf(fd, "max_repeat_compl %f\n", p->p_args.max_repeat_compl) ;
fprintf(fd, "max_template_mispriming %f\n", p->p_args.max_template_mispriming) ;
fprintf(fd, "max_template_mispriming_th %f\n", p->p_args.max_template_mispriming_th) ;
fprintf(fd, "end primer args\n") ;
fprintf(fd, "begin internal oligo args (p->o_args.)\n") ;
fprintf(fd, " begin internal oligo_weights (p->o_args.weights.)\n") ;
fprintf(fd, " temp_gt %f\n", p->o_args.weights.temp_gt) ;
fprintf(fd, " temp_lt %f\n", p->o_args.weights.temp_lt) ;
fprintf(fd, " bound_gt %f\n", p->o_args.weights.bound_gt) ;
fprintf(fd, " bound_lt %f\n", p->o_args.weights.bound_lt) ;
fprintf(fd, " gc_content_gt %f\n", p->o_args.weights.gc_content_gt) ;
fprintf(fd, " gc_content_lt %f\n", p->o_args.weights.gc_content_lt) ;
fprintf(fd, " compl_any %f\n", p->o_args.weights.compl_any) ;
fprintf(fd, " compl_end %f\n", p->o_args.weights.compl_end) ;
fprintf(fd, " compl_any_th %f\n", p->o_args.weights.compl_any_th) ;
fprintf(fd, " compl_end_th %f\n", p->o_args.weights.compl_end_th) ;
fprintf(fd, " hairpin %f\n", p->o_args.weights.hairpin_th) ;
fprintf(fd, " repeat_sim %f\n", p->o_args.weights.repeat_sim) ;
fprintf(fd, " length_lt %f\n", p->o_args.weights.length_lt) ;
fprintf(fd, " length_gt %f\n", p->o_args.weights.length_gt) ;
fprintf(fd, " seq_quality %f\n", p->o_args.weights.seq_quality) ;
fprintf(fd, " end_quality %f\n", p->o_args.weights.end_quality) ;
fprintf(fd, " pos_penalty %f\n", p->o_args.weights.pos_penalty) ;
fprintf(fd, " end_stability %f\n", p->o_args.weights.end_stability) ;
fprintf(fd, " num_ns %f\n", p->o_args.weights.num_ns) ;
fprintf(fd, " end internal oligo_weights\n") ;
fprintf(fd, " opt_tm %f\n", p->o_args.opt_tm) ;
fprintf(fd, " min_tm %f\n", p->o_args.min_tm) ;
fprintf(fd, " max_tm %f\n", p->o_args.max_tm) ;
fprintf(fd, " opt_bound %f\n", p->o_args.opt_bound) ;
fprintf(fd, " min_bound %f\n", p->o_args.min_bound) ;
fprintf(fd, " max_bound %f\n", p->o_args.max_bound) ;
fprintf(fd, " opt_gc_content %f\n", p->o_args.opt_gc_content) ;
fprintf(fd, " max_gc %f\n", p->o_args.max_gc) ;
fprintf(fd, " min_gc %f\n", p->o_args.min_gc) ;
fprintf(fd, " divalent_conc %f\n", p->o_args.divalent_conc) ;
fprintf(fd, " dntp_conc %f\n", p->o_args.dntp_conc) ;
fprintf(fd, " dna_conc %f\n", p->o_args.dna_conc) ;
fprintf(fd, " dmso_conc %f\n", p->o_args.dmso_conc) ;
fprintf(fd, " dmso_fact %f\n", p->o_args.dmso_fact) ;
fprintf(fd, " formamide_conc %f\n", p->o_args.formamide_conc) ;
fprintf(fd, " num_ns_accepted %i\n", p->o_args.num_ns_accepted) ;
fprintf(fd, " opt_size %i\n", p->o_args.opt_size) ;
fprintf(fd, " min_size %i\n", p->o_args.min_size) ;
fprintf(fd, " max_size %i\n", p->o_args.max_size) ;
fprintf(fd, " max_poly_x %i\n", p->o_args.max_poly_x) ;
fprintf(fd, " min_end_quality %i\n", p->o_args.min_end_quality) ;
fprintf(fd, " min_quality %i\n", p->o_args.min_quality) ;
fprintf(fd, " max_self_any %f\n", p->o_args.max_self_any) ;
fprintf(fd, " max_self_end %f\n", p->o_args.max_self_end) ;
fprintf(fd, " max_repeat_compl %f\n", p->o_args.max_repeat_compl) ;
fprintf(fd, " end internal oligo args\n");
fprintf(fd, "\n");
fprintf(fd, "END GLOBAL ARGS\n");
fprintf(fd, "=============\n");
fprintf(fd, "\n");
}
if (s != NULL) {
fprintf(fd, "=============\n");
fprintf(fd, "BEGIN SEQUENCE ARGS\n") ;
/* TO DO: complete the statments for dumping this data
fprintf(fd, "interval_array_t2 tar2 %i\n",
int pairs[PR_MAX_INTERVAL_ARRAY][2]) ;
int count) ;
fprintf(fd, "interval_array_t2 excl2 %i\n",
int pairs[PR_MAX_INTERVAL_ARRAY][2]) ;
int count) ;
fprintf(fd, "interval_array_t2 excl_internal2 %i\n",
int pairs[PR_MAX_INTERVAL_ARRAY][2]) ;
int count) ;
fprintf(fd, "ok_regions \n");
*/
fprintf(fd, "sequence_primer_pair_ok_regions %i\n",
s->ok_regions.count);
if (s->ok_regions.count) {
fprintf(fd, "sequence_primer_pair_ok_regions_list [\n");
for (i = 0; i < s->ok_regions.count; i++) {
fprintf(fd, " %i\n", s->ok_regions.left_pairs[i][0]);
fprintf(fd, " %i\n", s->ok_regions.left_pairs[i][1]);
fprintf(fd, " %i\n", s->ok_regions.right_pairs[i][0]);
fprintf(fd, " %i\n", s->ok_regions.right_pairs[i][1]);
}
fprintf(fd, "]\n");
}
if (s->primer_overlap_junctions_count > 0) {
fprintf(fd, "primer_overlap_junctions_count %i\n",
s->primer_overlap_junctions_count);
fprintf(fd, "primer_overlap_junctions_list [\n");
for (i = 0; i < s->primer_overlap_junctions_count; i++) {
fprintf(fd, " %i\n", s->primer_overlap_junctions[i]);
}
fprintf(fd, "]\n");
}
if (s->intl_overlap_junctions_count > 0) {
fprintf(fd, "intl_overlap_junctions_count %i\n",
s->intl_overlap_junctions_count);
fprintf(fd, "intl_overlap_junctions_list [\n");
for (i = 0; i < s->intl_overlap_junctions_count; i++) {
fprintf(fd, " %i\n", s->intl_overlap_junctions[i]);
}
fprintf(fd, "]\n");
}
fprintf(fd, "incl_s %i\n", s->incl_s) ;
fprintf(fd, "incl_l %i\n", s->incl_l) ;
fprintf(fd, "start_codon_pos %i\n", s->start_codon_pos) ;
fprintf(fd, "n_quality %i\n", s->n_quality) ;
/* TO DO fprintf(fd, "quality%i\", s->quality) ; */
fprintf(fd, "quality_storage_size %i\n", s->quality_storage_size) ;
fprintf(fd, "*sequence %s\n", s->sequence) ;
fprintf(fd, "*sequence_name %s\n", s->sequence_name) ;
fprintf(fd, "*sequence_file %s\n", s->sequence_file) ;
fprintf(fd, "*trimmed_seq %s\n", s->trimmed_seq) ;
fprintf(fd, "*trimmed_orig_seq %s\n", s->trimmed_orig_seq) ;
fprintf(fd, "*trimmed_masked_seq %s\n", s->trimmed_masked_seq) ;
fprintf(fd, "*trimmed_masked_seq_r %s\n", s->trimmed_masked_seq_r) ;
fprintf(fd, "*upcased_seq %s\n", s->upcased_seq) ;
fprintf(fd, "*upcased_seq_r %s\n", s->upcased_seq_r) ;
fprintf(fd, "*left_input %s\n", s->left_input) ;
fprintf(fd, "*right_input %s\n", s->right_input) ;
fprintf(fd, "*internal_input %s\n", s->internal_input) ;
fprintf(fd, "force_left_start %i\n", s->force_left_start) ;
fprintf(fd, "force_left_end %i\n", s->force_left_end) ;
fprintf(fd, "force_right_start %i\n", s->force_right_start) ;
fprintf(fd, "force_right_end %i\n", s->force_right_end) ;
fprintf(fd, "END SEQUENCE ARGS\n") ;
fprintf(fd, "=============\n");
fprintf(fd, "\n");
}
}
primer3-py-2.3.1/primer3/src/libprimer3/libprimer3.h 0000664 0000000 0000000 00000162110 15247271707 0022202 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 1996,1997,1998,1999,2000,2001,2004,2006,2007,2008,2009,
2010,2011,2012
Whitehead Institute for Biomedical Research, Steve Rozen
(http://purl.com/STEVEROZEN/), Andreas Untergasser and Helen Skaletsky
All rights reserved.
This file is part of primer3 and the libprimer3 library.
Primer3 and the libprimer3 library are free software;
you can redistribute them and/or modify them under the terms
of the GNU General Public License as published by the Free
Software Foundation; either version 2 of the License, or (at
your option) any later version.
This software is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this file (file gpl-2.0.txt in the source
distribution); if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef LIBPRIMER3_H
#define LIBPRIMER3_H
#include
#include /* FILE */
#include
#include /* SHRT_MIN, ULONG_MAX */
#include /* DBL_MIN */
#ifdef __cplusplus
extern "C" {
#endif
/* ALIGN_SCORE_UNDEF is used only libprimer3 and clients, not in dpal */
#define ALIGN_SCORE_UNDEF -DBL_MAX
/* These next 5 are exposed for format_output.c -- probabaly should be reviewed. */
#define PR_INFINITE_POSITION_PENALTY -1.0
#define PR_DEFAULT_INSIDE_PENALTY PR_INFINITE_POSITION_PENALTY
#define PR_DEFAULT_OUTSIDE_PENALTY 0.0
#define PR_DEFAULT_PRODUCT_MAX_TM 1000000.0
#define PR_DEFAULT_PRODUCT_MIN_TM -1000000.0
#define PR_NULL_FORCE_POSITION -1000000
/* Exposed in the read_boulder input routine.... */
#define PR_NULL_START_CODON_POS -1000000
#define PR_DEFAULT_START_CODON_POS -2000000
#define PR_START_CODON_POS_IS_NULL(SA) ((SA)->start_codon_pos <= PR_NULL_START_CODON_POS)
#define _PR_DEFAULT_POSITION_PENALTIES(PA) \
(PR_DEFAULT_INSIDE_PENALTY == pa->inside_penalty \
&& PR_DEFAULT_OUTSIDE_PENALTY == pa->outside_penalty)
#define PR_ALIGN_SCORE_PRECISION 100.0
#define MACRO_STRING(X) #X
/* pr_progam_name must be set in main(). */
#define PR_ASSERT(COND) \
if (!(COND)) { \
fprintf(stderr, "%s:%s:%d, assertion (%s) failed\n", \
pr_program_name, __FILE__, __LINE__, \
MACRO_STRING(COND)); \
abort(); \
}
/* Enum to define tasks primer3 can do */
typedef enum task {
pick_pcr_primers = 0,
/* For backward compatibility, equivalent to
generic
plus pick_left_primer =1
plus pick_right_primer = 1
plus pick_internal_oligo = 0 */
pick_pcr_primers_and_hyb_probe = 1,
pick_left_only = 2,
pick_right_only = 3,
pick_hyb_probe_only = 4,
generic_p3 = 5,
pick_cloning_primers = 6,
pick_discriminative_primers = 7,
pick_sequencing_primers = 8,
pick_primer_list = 9,
check_primers = 10,
} task;
/* Enum explaining if output are pairs */
typedef enum p3_output_type {
primer_pairs = 0,
primer_list = 1,
} p3_output_type;
/* NOTE: NC Moved to p3_seq_lib.h to avoid circular import */
/* masker.h needed an update also */
/* pr_append_str is an append-only string ADT. */
// typedef struct pr_append_str {
// int storage_size;
// char *data;
// } pr_append_str;
#include "oligotm.h"
#include "masker.h"
#include "thal.h"
#include "thal_parameters.h"
#include "dpal.h"
/*
* Arguments to the primer program as a whole. Values for these arguments are
* retained _across_ different input records. (These are the so-called
* "Global" arguments in the documentation.)
*/
typedef struct oligo_weights {
double compl_any;
double compl_any_th;
double compl_end;
double compl_end_th;
double end_quality;
double end_stability;
double gc_content_gt;
double gc_content_lt;
double hairpin_th;
double length_gt;
double length_lt;
double num_ns;
double pos_penalty;
double repeat_sim;
double seq_quality;
double temp_cutoff;
double temp_gt;
double temp_lt;
double bound_gt;
double bound_lt;
double template_mispriming;
double template_mispriming_th;
double failure_rate;
} oligo_weights;
typedef struct pair_weights {
double primer_quality;
double io_quality;
double diff_tm;
double compl_any;
double compl_any_th;
double compl_end;
double compl_end_th;
double temp_cutoff;
double product_tm_lt;
double product_tm_gt;
double product_size_lt;
double product_size_gt;
double repeat_sim;
double template_mispriming;
double template_mispriming_th;
} pair_weights;
typedef struct sequencing_parameters {
int lead;
int spacing;
int interval;
int accuracy;
} sequencing_parameters;
#include "p3_seq_lib.h"
typedef struct args_for_one_oligo_or_primer {
seq_lib *repeat_lib;
oligo_weights weights;
double opt_tm;
double min_tm;
double max_tm;
double opt_bound;
double min_bound;
double max_bound;
double opt_gc_content;
double max_gc;
double min_gc;
/* Warning: also used for product Tm (TO DO: factor this out) */
double salt_conc;
double divalent_conc;
/*
DIVALENT_CONC and DNTP_CONC are both needed for enabling use of
divalent cations for calculation of melting temperature of short
and long oligos. The formula for converting the divalent cations
to monovalent cations is in the paper [Ahsen von N, Wittwer CT,
Schutz E (2001) "Oligonucleotide Melting Temperatures under PCR
Conditions: Nearest-Neighbor Corrections for Mg^2+,
Deoxynucleotide Triphosphate, and Dimethyl Sulfoxide
Concentrations with Comparision to Alternative Empirical
Formulas", Clinical Chemistry 47:1956-61
http://www.clinchem.org/cgi/content/full/47/11/1956] The default
is 0.0. (New in v. 1.1.0, added by Maido Remm and Triinu
Koressaar.)
*/
double dntp_conc;
double dna_conc;
double dmso_conc;
double dmso_fact;
double formamide_conc;
int num_ns_accepted;
int opt_size;
int min_size;
int max_size;
int max_poly_x; /*
* Maximum length of mononucleotide sequence in an
* oligo.
*/
int min_5_prime_overlap_of_junction; /* The number of basepairs
the primer has to
overlap an overlap
junction. */
int min_3_prime_overlap_of_junction;
int min_end_quality;
int min_quality; /* Minimum quality permitted for oligo sequence.*/
double max_self_any;
double max_self_end;
double max_self_any_th;
double max_self_end_th;
double max_hairpin_th;
double max_repeat_compl; /*
* Acceptable complementarity with repeat
* sequences.
*/
double max_template_mispriming;
double max_template_mispriming_th;
char *must_match_five_prime;
char *must_match_three_prime;
/* Primers and Oligos must match this 5 prime and 3 prime sequences.
This allows to select a set of primer pair with an identical 3' end
to avoid primer dimers. On the 5 prime end bases quenching
flourochromes can be avoided.
The sequence must be 5 nucletides long and can contain the following letters:
N Any nucleotide
A Adenine
G Guanine
C Cytosine
T Thymine
R Purine (A or G)
Y Pyrimidine (C or T)
W Weak (A or T)
S Strong (G or C)
M Amino (A or C)
K Keto (G or T)
B Not A (G or C or T)
H Not G (A or C or T)
D Not C (A or G or T)
V Not T (A or G or C)
*/
} args_for_one_oligo_or_primer;
/* Maxima needed for interface data structures. */
#define PR_MAX_INTERVAL_ARRAY 200
/*
* Maximum number of input intervals
* supported; used for targets, excluded
* regions, product-size intervals, etc.
*/
typedef struct p3_global_settings {
/* ================================================== */
/* Arguments that control behavior of choose_primers() */
task primer_task; /* 2 if left primer only, 3 if right primer
* only, 4 if internal oligo only. */
int pick_left_primer;
int pick_right_primer;
int pick_internal_oligo;
int file_flag; /* TO DO, See if this can be factored out. */
int first_base_index; /*
* The index of the first base in the input
* sequence. This parameter is ignored within
* pr_choice; pr_choice's caller must assure that
* all indexes are 0-based. However, this
* parameter should used by output routines to
* adjust base indexes.
*/
int liberal_base; /*
* If non-0 then turn characters other than
* [ATGCNatgcn] into N.
*/
int num_return; /* The number of best primer pairs to return. */
int pick_anyway; /* Pick even if input primer or oligos
violate constraints. */
int lib_ambiguity_codes_consensus;
/* If non-0, treat ambiguity codes in a mispriming/mishyb
library as representing a consensus. So, for example,
S would match C or G. N would match any nucleotide.
It turns out that this _not_ what one normally wants,
since many libraries contain strings of N, which then
match every oligo (very bad).
*/
int quality_range_min;
int quality_range_max;
/* ================================================== */
/* Arguments for individual oligos and/or primers */
args_for_one_oligo_or_primer p_args;
args_for_one_oligo_or_primer o_args;
tm_method_type tm_santalucia;
/*
tm_santalucia added by T.Koressaar for updated table
thermodynamics. Specifies details of melting temperature
calculation. (New in v. 1.1.0, added by Maido Remm and Triinu
Koressaar.)
A value of 1 (recommended) directs primer3 to use the table of
thermodynamic values and the method for melting temperature
calculation suggested in the paper [SantaLucia JR (1998) "A
unified view of polymer, dumbbell and oligonucleotide DNA
nearest-neighbor thermodynamics", Proc Natl Acad Sci 95:1460-65
http://dx.doi.org/10.1073/pnas.95.4.1460].
A value of 0 directs primer3 to a backward compatible calculation
(in other words, the only calculation availble in previous
version of primer3).
This backward compatible calculation uses the table of
thermodynamic parameters in the paper [Breslauer KJ, Frank R,
Bloecker H and Marky LA (1986) "Predicting DNA duplex stability
from the base sequence" Proc Natl Acad Sci 83:4746-50
http://dx.doi.org/10.1073/pnas.83.11.3746],
and the method in the paper [Rychlik W, Spencer WJ and Rhoads
RE (1990) "Optimization of the annealing temperature for DNA
amplification in vitro", Nucleic Acids Res 18:6409-12
http://www.pubmedcentral.nih.gov/articlerender.fcgi?tool=pubmed&pubmedid=2243783].
The default value is 0 only for backward compatibility.
*/
salt_correction_type salt_corrections;
/*
salt_corrections added by T.Koressaar for salt correction for Tm
calculation. A value of 1 (recommended) directs primer3 to use
the salt correction formula in the paper [SantaLucia JR (1998) "A
unified view of polymer, dumbbell and oligonucleotide DNA
nearest-neighbor thermodynamics", Proc Natl Acad Sci 95:1460-65
http://dx.doi.org/10.1073/pnas.95.4.1460]
A value of 0 directs primer3 to use the the salt correction
formula in the paper [Schildkraut, C, and Lifson, S (1965)
"Dependence of the melting temperature of DNA on salt
concentration", Biopolymers 3:195-208 (not available on-line)].
This was the formula used in previous version of primer3.
A value of 2 directs primer3 to use the salt correction formula
in the paper [Owczarzy R, You Y, Moreira BG, Manthey JA, Huang L,
Behlke MA and Walder JA (2004) "Effects of sodium ions on DNA
duplex oligomers: Improved predictions of melting temperatures",
Biochemistry 43:3537-54 http://dx.doi.org/10.1021/bi034621r].
The default is 0 only for backward compatibility.
*/
/* ================================================== */
/* Start of arguments applicable to primers but not
oligos */
double annealing_temp;
/* The actual annealing temperature of the PCR reaction. */
double max_end_stability;
/* The maximum value allowed for the delta
* G of disruption for the 5 3' bases of
* a primer.
*/
int max_end_gc;
/* The maximum number of allowed G or C
* for the 5 3' bases of a primer.
*/
int gc_clamp; /* Required number of GCs at 3' end. */
/* ================================================== */
/* Start of arguments related to primer and/or oligo
location in the template. */
int lowercase_masking;
/*
lowercase_masking added by T.Koressaar. Enables design of primers
from lowercase masked template. A value of 1 directs primer3 to
reject primers overlapping lowercase a base exactly at the 3'
end.
This property relies on the assumption that masked features
(e.g. repeats) can partly overlap primer, but they cannot overlap the
3'-end of the primer. In other words, lowercase bases at other
positions in the primer are accepted, assuming that the masked
features do not influence the primer performance if they do not
overlap the 3'-end of primer.
*/
sequencing_parameters sequencing; /* Used to calculate the position
of sequencing primers */
double outside_penalty; /* Multiply this value times the number of NTs
* from the 3' end to the the (unique) target to
* get the 'position penalty'.
* Meaningless if there are multiple targets
* or if the primer cannot be part of a pair
* that spans the target.
*/
double inside_penalty; /* Multiply this value times the number of NT
* positions by which the primer overlaps
* the (unique) target to the 'position penalty'.
* Meaningless if there are multiple targets
* or if the primer cannot be part of a pair
* that spans the target.
*/
/* ================================================== */
/* Arguments for primer pairs and products. */
/* Warning: Use p3_empty_gs_product_size_range and
p3_add_to_gs_product_size_range to set these next
three slots. */
int pr_min[PR_MAX_INTERVAL_ARRAY]; /* Minimum product sizes. */
int pr_max[PR_MAX_INTERVAL_ARRAY]; /* Maximum product sizes. */
int num_intervals; /*
* Number of product size intervals
* (i.e. number of elements in pr_min and
* pr_max)
*/
int product_opt_size;
double product_max_tm;
double product_min_tm;
double product_opt_tm;
double pair_max_template_mispriming;
double pair_max_template_mispriming_th;
double pair_repeat_compl;
double pair_compl_any;
double pair_compl_any_th;
double pair_compl_end;
double pair_compl_end_th;
int thermodynamic_oligo_alignment;
/*
Enables to use approach of thermodynamical alignment for dimer
and hairpin calculations.
0 = Use alignment *not* based on thermodynamics - the only dimer
calculation approach until primer3 2.2.0. No hairpins are
calculated.
1 = Use alignment based on thermodynamics. Hairpins are calculated
*/
int thermodynamic_template_alignment;
/*
Enables to use approach of thermodynamical alignment for template
mispriming calculations.
0 = Use alignment *not* based on thermodynamics.
1 = Use alignment based on thermodynamics.
*/
thal_parameters thermodynamic_parameters;
/*
The parameters for thermodynamic calculation. Default parameters
are loaded by the thermodynamic_parameters.h function and
can be overwitten by read_boulder.h functions.
*/
int show_secondary_structure_alignment;
/*
String representations of the secondary structures are calculated.
0 = Do not calculate and show secondary structure strings.
1 = Calculate and show secondary structure strings.
*/
double max_diff_tm;
/* Maximum allowed difference between temperature of primer and
temperature of product. Cannot be calculated until product is
known. */
pair_weights pr_pair_weights;
int min_left_three_prime_distance;
int min_internal_three_prime_distance;
int min_right_three_prime_distance;
/* Minimum number of base pairs between the 3' ends of any two left
or any two right primers when returning num_return primer pairs.
The objective is get 'truly different' primer pairs.
Please see the user documentation (primer3_manual.htm) for
PRIMER_{LEFT,RIGHT}_MIN_THREE_PRIME_DISTANCE.
*/
int mask_template;
int masking_parameters_changed;
/* Turn on masking of the trimmed_orig_seq (added by M. Lepamets)*/
masker_parameters mp;
/*
a struct containing all masking parameters
*/
int dump; /* dump fields for global settings and seq args if dump == 1 */
int do_log_settings;
char* log_settings_path;
} p3_global_settings;
typedef enum oligo_type { OT_LEFT = 0, OT_RIGHT = 1, OT_INTL = 2 }
oligo_type;
/* This struct captures informatin about the similarity of
an oligo (primer) to elements in a mispriming (repeat)
library (which is read in from a fasta file). */
typedef struct rep_sim {
char *name; /* Name of the sequence format with maximum
* similarity to the oligo.
*/
short min; /*
* The minimum score in slot 'score' (below).
* (Used when the objective function involves
* minimization of mispriming possibilities.)
*/
short max; /* The index of the maximum score in slot 'score'
(below). */
double *score; /*
* Array of similarity (i.e. false-priming) scores,
* one for each entry in the 'repeat_lib' slot
* of the primargs struct. In libprimer3.c,
* score is set to NULL to indicate that
* the rep_sim structure is uninitialized.
*/
} rep_sim;
#if (ULONG_MAX < 4294967295UL)
CANNOT COMPILE FOR THIS SYSTEM (< 32 bits in an unsigned long it)
#endif
typedef struct oligo_problems {
unsigned long int prob;
} oligo_problems;
typedef struct primer_rec {
rep_sim repeat_sim;
/* Information on the best repeat library (mispriming library)
* match for this oligo (primer), plus additional scores.
*/
double temp; /* The oligo melting temperature calculated for the
* primer. */
double bound; /* The fraction of primers bound at melting temperature
* temperature. */
double gc_content;
double position_penalty;
/*
* Penalty for distance from "ideal" position as specified
* by inside_penalty and outside_penalty.
*/
double quality; /* Part of objective function due to this primer. */
double end_stability;
/* Delta G of disription of 5 3' bases. */
int start; /* Position of the 5'-most base within the primer
WITH RESPECT TO THE seq_args FIELD
trimmed_seq. */
int seq_quality; /* Minimum quality score of bases included. */
int seq_end_quality; /* Minimum quality core of the 5 3' bases. */
double self_any; /* Self complementarity as local alignment * 100. */
double self_end; /* Self complementarity at 3' end * 100. */
double hairpin_th; /* hairpin, thermodynamical approach and calculated as any */
double template_mispriming;
/* Max 3' complementarity to any ectopic site in template
on the given template strand. */
double template_mispriming_r;
/* Max 3' complementarity to any ectopic site in the
template on the reverse complement of the given template
strand. */
char *self_any_struct; /* Secondary structure of self_any */
char *self_end_struct; /* Secondary structure of self_end */
char *hairpin_struct; /* Secondary structure of hairpin_th */
char *template_mispriming_struct; /* Secondary structure of template_mispriming */
char *template_mispriming_r_struct; /* Secondary structure of template_mispriming_r */
char length; /* Length of the oligo. */
char num_ns; /* Number of Ns in the oligo. */
char must_use; /* Non-0 if the oligo must be used even if it is illegal. */
char overlaps; /* Non-0 if the oligo overlaps some oligo used in one of the best pairs. */
oligo_problems problems;
char overlaps_overlap_position;
char template_mispriming_ok; /* Non-0 if the oligo was checked for this already and it is ok. */
double failure_rate; /* Primer failure rate due to non-specific priming */
} primer_rec;
const char *
p3_primer_rec_problems_to_string(const primer_rec *);
int p3_ol_is_ok(const primer_rec *);
/*
* The structure for a pair of primers and for a pair of
* primers plus an internal oligo.
*/
typedef struct primer_pair {
double pair_quality; /* Penalty value of the primer pair */
double diff_tm; /* Absolute value of the difference between melting
* temperatures for left and right primers.
*/
double product_tm; /* Estimated melting temperature of the product. */
double product_tm_oligo_tm_diff;
/* Difference in Tm between the primer with lowest Tm
the product Tm. */
double t_opt_a;
double compl_any; /*
* Local complementarity score between left and right
* primers (* 100).
*/
double compl_end; /*
* 3'-anchored global complementatory score between *
* left and right primers (* 100).
*/
double template_mispriming;
/* Maximum total mispriming score of both primers
to ectopic sites in the template, on "same"
strand (* 100). */
char *compl_any_struct; /* Secondary structure of compl_any */
char *compl_end_struct; /* Secondary structure of compl_end */
char *template_mispriming_struct; /* Secondary structure of template_mispriming */
double repeat_sim; /* Maximum total similarity of both primers to the
* sequence from given file in fasta format.
*/
primer_rec *left; /* Left primer. */
primer_rec *right; /* Right primer. */
primer_rec *intl; /* Internal oligo. */
char must_use;
int product_size; /* Product size. */
int target; /*
* 1 if there is a target between the right and left
* primers.
*/
char *rep_name;
} primer_pair;
typedef int interval_array_t[PR_MAX_INTERVAL_ARRAY][2];
typedef struct interval_array_t2 {
int pairs[PR_MAX_INTERVAL_ARRAY][2];
int count;
} interval_array_t2;
typedef struct interval_array_t4 {
int left_pairs[PR_MAX_INTERVAL_ARRAY][2];
int right_pairs[PR_MAX_INTERVAL_ARRAY][2];
int any_left; /* set to 1 if the empty pair ",," is given for any
left interval */
int any_right; /* set to 1 if the empty pair ",," is given for any
right interval */
int any_pair; /* set to 1 if both intervals are given as empty */
int count; /* total number of pairs */
} interval_array_t4;
int interval_array_t2_count(const interval_array_t2 *array);
const int *
interval_array_t2_get_pair(const interval_array_t2 *array, int i);
typedef struct oligo_stats {
int sequencing_location; /* Number of locations for sequencing primers */
int considered; /* Total number of tested oligos of given type */
int ns; /* Number of oligos rejected because of Ns */
int target; /* Overlapping targets. */
int excluded; /* Overlapping excluded regions. */
int gc; /* Unacceptable GC content. */
int gc_clamp; /* Don't have required number of GCs at 3' end. */
int gc_end_high; /* Too many G+Cs at the 3' end. */
int temp_min; /* Melting temperature below t_min. */
int temp_max; /* Melting temperature more than t_max. */
int bound_min; /* Fraction bound below min. */
int bound_max; /* Fraction bound above max. */
int size_min; /* Primer shorter than minimal size. */
int size_max; /* Primer longer than minimal size. */
int compl_any; /* Self-complementarity too high. */
int compl_end; /* Self-complementarity at 3' end too high. */
int hairpin_th; /* Hairpin structure too stable in
thermodynamical approach */
int repeat_score; /* Complementarity with repeat sequence too high.*/
int poly_x; /* Long mononucleotide sequence inside. */
int seq_quality; /* Low quality of bases included. */
int stability; /* Stability of 5 3' bases too high. */
int no_orf; /* Would not amplify any of the specified ORF
(valid for left primers only). */
int template_mispriming; /* Template mispriming score too high. */
int ok; /* Number of acceptable oligos. */
int gmasked; /* Added by T. Koressaar, number of gmasked
oligos */
int must_match_fail; /* Added by A. Untergasser, number of oligos
failing must match */
int not_in_any_left_ok_region; /* Oligo not included in any of the
left regions given in
PRIMER_PAIR_OK_REGION_LIST. */
int not_in_any_right_ok_region;/* Oligo not included in any of the
right regions given in
PRIMER_PAIR_OK_REGION_LIST. */
int does_not_overlap_a_required_point; /* Oligo does not overlap one of
the "required sites". */
} oligo_stats;
typedef struct pair_stats {
int considered; /* Total number of pairs or triples tested. */
int product; /* Pairs providing incorrect product size. */
int target; /* Pairs without any target between primers. */
int temp_diff; /* Melting temperature difference too high. */
int compl_any; /* Pairwise complementarity larger than allowed. */
int compl_end; /* The same for 3' end complementarity. */
int internal; /* Internal oligo was not found. */
int repeat_sim; /* Complementarity with repeat sequence too high.*/
int high_tm; /* Product Tm too high. */
int low_tm; /* Product Tm too low. */
int template_mispriming; /* Sum of template mispriming scores too high. */
/* Neither oligo in the pairs overlaps one of the "required sites". */
int does_not_overlap_a_required_point;
/* One of the oligos in the pair overlaps an oligo in a better_pair: */
int overlaps_oligo_in_better_pair;
/* The left and right oligos are not in any of the pair of regions given in
PRIMER_PAIR_OK_REGION_LIST. */
int not_in_any_ok_region;
/* Left primer to the right of right right primer. This can occur when
the primers are provided by the caller. */
int reversed;
int ok; /* Number that were ok. */
} pair_stats;
typedef struct pair_array_t {
int storage_size;
int num_pairs;
primer_pair *pairs;
pair_stats expl;
} pair_array_t;
/*
* Arguments relating to a single particular source sequence (for which
* we will pick primer(s), etc.
*/
typedef struct seq_args_t {
/* The net next 3 slots are presented as
* indexes within the sequence slot, but
* they are recalculated to be indexes
* within trimmed_seq (i.e. within the
* "included region").
*/
interval_array_t2 tar2; /* The targets. tar2->pairs[i][0] is the start
* of the ith target, tar2->pairs[i][1] its length. */
interval_array_t2 excl2;/* The number of excluded regions. */
interval_array_t2 excl_internal2;
/* Number of excluded regions for internal
oligo; similar to excl2.*/
interval_array_t4 ok_regions;
int primer_overlap_junctions[PR_MAX_INTERVAL_ARRAY];
/* List of overlap junction positions. */
int primer_overlap_junctions_count;
int intl_overlap_junctions[PR_MAX_INTERVAL_ARRAY];
/* List of overlap junction positions. */
int intl_overlap_junctions_count;
int incl_s; /* The 0-based start of included region. */
int incl_l; /*
* The length of the included region, which is
* also the length of the trimmed_seq field.
*/
int start_codon_pos; /* Index of first base of the start codon. */
char start_codon_seq[4]; /* Sequence of the start codon, usually ATG\0 */
int *quality; /* Vector of quality scores. */
int n_quality; /* Number of valid elements in 'quality' */
int quality_storage_size; /* Amount of storage quality points to. */
char *sequence; /* The template sequence itself as input,
not trimmed, not up-cased. */
char *sequence_name; /* An identifier for the sequence. */
char *sequence_file; /* Another identifier for the sequence. */
char *trimmed_seq; /* The included region only, _UPCASED_. */
/* Element add by T. Koressaar support lowercase masking: */
char *trimmed_orig_seq; /* Trimmed version of the original,
mixed-case sequence. */
/* Added by M. Lepamets */
char *trimmed_masked_seq; /* Masked version of the trimmed seq */
char *trimmed_masked_seq_r; /* Masked version of the other strand
of the trimmed seq */
char *upcased_seq; /* Upper case version of sequence
(_not_ trimmed). */
char *upcased_seq_r; /* Upper case version of sequence,
other strand (_not_ trimmed). */
char *left_input; /* A left primer to check or design around. */
char *right_input; /* A right primer to check or design around. */
char *internal_input; /* An internal oligo to check or design around. */
int force_left_start; /* The 0-based forced 5' start left primer. */
int force_left_end; /* The 0-based forced 3' end left primer. */
int force_right_start; /* The 0-based forced 5' start right primer. */
int force_right_end; /* The 0-based forced 3' end right primer. */
char *overhang_left; /* sequence added to the 5' end of the left primer */
char *overhang_right; /* sequence added to the 5' end of the right primer */
char *overhang_right_rv; /* the reverse complement of *overhang_right
matching the sequence */
} seq_args_t;
/* oligo_array is used to store a list of oligos or primers */
typedef struct oligo_array {
/* Array of oligo (primer) records. */
primer_rec *oligo;
/* Number of initialized elements */
int num_elem;
/* Storage lengths of oligo */
int storage_size;
/* Type of oligos in the array */
oligo_type type;
/* Primers statistics. */
oligo_stats expl;
} oligo_array;
/*
* The return value for for primer3.
* After use, free memory with destroy_p3retval().
*/
typedef struct p3retval {
/* Arrays of oligo (primer) records. */
oligo_array fwd, intl, rev;
/* Array of best primer pairs */
pair_array_t best_pairs;
/* Enum to store type of output */
p3_output_type output_type;
/* Place for error messages */
pr_append_str glob_err;
pr_append_str per_sequence_err;
pr_append_str warnings;
/*
* An optional _output_, meaninful if a
* start_codon_pos is "not null". The position of
* the intial base of the leftmost stop codon that
* is to the right of sa->start_codon_pos.
*/
int stop_codon_pos;
int upstream_stop_codon; /* TO DO needs docs */
} p3retval;
/* Deallocate a primer3 state */
void destroy_secundary_structures(const p3_global_settings *pa, p3retval *retval);
void destroy_p3retval(p3retval *);
void destroy_dpal_thal_arg_holder();
/* get elements of p3retval */
const pair_array_t *p3_get_rv_best_pairs(const p3retval *r);
const oligo_array *p3_get_rv_fwd(const p3retval *r);
const oligo_array *p3_get_rv_intl(const p3retval *r);
const oligo_array *p3_get_rv_rev(const p3retval *r);
/* TO DO -- needs more documentation
It is the responsibility of caller to free the return value. */
char *p3_get_rv_and_gs_warnings(const p3retval *retval,
const p3_global_settings *pa);
/* Return a char * describing global errors (usually/always?) errors
caused by problems detected in the p3_global_settings * argument to
choose primers. Returned storage is free'ed on calling
destroy_p3retval(r). Returns NULL if no error. */
const char *p3_get_rv_global_errors(const p3retval *r);
/* Return a char * describing per-sequence errors (usually/always?)
errors caused by problems detected in the seq_args_t* argument to
choose primers. Returned storage is free'ed on calling
destroy_p3retval(r). Returns NULL if no error. */
const char *p3_get_rv_per_sequence_errors(const p3retval *r);
/* Return a char * describing warnings generated in
choose_primers. Returned storage is free'ed on calling
destroy_p3retval(r). Returns NULL if no warnings. */
const char *p3_get_rv_warnings(const p3retval *r);
p3_output_type p3_get_rv_output_type(const p3retval *r);
int p3_get_rv_stop_codon_pos(p3retval *r);
/* Get elements of an oligo_array */
int p3_get_oa_n(const oligo_array *x);
const primer_rec *p3_get_oa_i(const oligo_array *x, int i);
/* We still need accessors (getters) for the elements of
primer_rec */
/* Functions for seq_args_t -- create, destroy, set, set slots */
seq_args_t* create_seq_arg();
void destroy_seq_args(seq_args_t* );
int p3_set_sa_sequence(seq_args_t* sargs, const char *sequence);
void p3_set_sa_primer_sequence_quality(seq_args_t* sargs, int quality);
int p3_set_sa_sequence_name(seq_args_t* sargs, const char* sequence_name);
int p3_set_sa_left_input(seq_args_t* sargs, const char *left_input);
int p3_set_sa_right_input(seq_args_t* sargs, const char *right_input);
int p3_set_sa_internal_input(seq_args_t* sargs, const char *internal_input);
void p3_set_sa_empty_quality(seq_args_t* sargs);
void p3_sa_add_to_quality_array(seq_args_t* sargs, int quality);
int p3_sa_add_to_overlap_junctions_array(seq_args_t* , int);
/* The following three functions return 0 on success,
1 on error (no space for additional intervals). */
int p3_add_to_sa_tar2(seq_args_t* , int, int);
int p3_add_to_sa_excl2(seq_args_t* , int, int);
int p3_add_to_sa_excl_internal2(seq_args_t* , int, int);
int p3_add_to_sa_ok_regions(seq_args_t* , int, int, int, int);
const interval_array_t2 *p3_get_sa_tar2(const seq_args_t* sargs);
const interval_array_t2 *p3_get_sa_excl2(const seq_args_t* sargs);
const interval_array_t2 *p3_get_sa_excl_internal2(const seq_args_t* sargs);
const interval_array_t4 *p3_get_sa_ok_regions(const seq_args_t* sargs);
const int* p3_get_sa_overlap_junctions(const seq_args_t* sargs);
/*
use p3_add_to_interval_array(interval_array_t2 *interval_arr, int i1, int i2);
to do the sets for tar2, excl2, and excl_internal2
*/
int p3_add_to_interval_array(interval_array_t2 *interval_arr, int i1, int i2);
/*
use p3_add_to_2_interval_array
to do the sets for ok_regions
*/
int p3_add_to_2_interval_array(interval_array_t4 *interval_arr, int i1, int i2, int i3, int i4);
/*
included region
*/
void p3_set_sa_incl_s(seq_args_t* sargs, int incl_s);
void p3_set_sa_incl_l(seq_args_t* sargs, int incl_l);
void p3_set_sa_n_quality(seq_args_t* sargs, int n_quality) ;
void p3_set_sa_start_codon_pos(seq_args_t* sargs, int start_codon_pos);
int p3_set_sa_sequence_file(seq_args_t* sargs, const char *sequence_file);
int p3_set_sa_trimmed_sequence(seq_args_t* sargs, const char *trimmed_sequence);
int p3_set_sa_trimmed_original_sequence(seq_args_t* sargs, const char *trimmed_original_sequence);
int p3_set_sa_upcased_sequence(seq_args_t* sargs, const char *upcased_sequencd);
/* ============================================================ */
/* Functions for p3_global_settings -- create, destroy,
set slots, get slots */
/* ============================================================ */
/* Use this for -default_version=2 (up-to-date defaults) */
p3_global_settings *p3_create_global_settings();
/* Use this for -default_version=1 (old defaults) */
p3_global_settings *p3_create_global_settings_default_version_1();
void p3_destroy_global_settings(p3_global_settings *);
void p3_set_gs_prmin (p3_global_settings * p , int val, int i);
void p3_set_gs_prmax (p3_global_settings * p , int val, int i);
void p3_set_gs_primer_opt_size(p3_global_settings * p , int val);
void p3_set_gs_primer_min_size(p3_global_settings * p , int val);
void p3_set_gs_primer_max_size(p3_global_settings * p , int val);
void p3_set_gs_primer_max_poly_x(p3_global_settings * p , int val);
void p3_set_gs_primer_opt_tm(p3_global_settings * p , double product_opt_tm);
void p3_set_gs_primer_opt_gc_percent(p3_global_settings * p , double val);
void p3_set_gs_primer_min_tm(p3_global_settings * p , double product_min_tm);
void p3_set_gs_primer_max_tm(p3_global_settings * p , double product_max_tm);
void p3_set_gs_primer_opt_bound(p3_global_settings * p , double product_opt_tm);
void p3_set_gs_primer_min_bound(p3_global_settings * p , double product_min_tm);
void p3_set_gs_primer_max_bound(p3_global_settings * p , double product_max_tm);
void p3_set_gs_primer_max_diff_tm(p3_global_settings * p , double val);
void p3_set_gs_primer_tm_santalucia(p3_global_settings * p,
tm_method_type val);
void p3_set_gs_primer_salt_corrections(p3_global_settings * p,
salt_correction_type salt_corrections);
void p3_set_gs_primer_annealing_temp(p3_global_settings * p,
double val);
void p3_set_gs_primer_min_gc(p3_global_settings * p , double val);
void p3_set_gs_primer_max_gc(p3_global_settings * p , double val);
void p3_set_gs_primer_salt_conc(p3_global_settings * p , double val);
void p3_set_gs_primer_divalent_conc(p3_global_settings * p , double val);
void p3_set_gs_primer_dntp_conc(p3_global_settings * p , double val);
void p3_set_gs_primer_dna_conc(p3_global_settings * p , double val);
void p3_set_gs_primer_dmso_conc(p3_global_settings * p , double val);
void p3_set_gs_primer_dmso_fact(p3_global_settings * p , double val);
void p3_set_gs_primer_formamide_conc(p3_global_settings * p , double val);
void p3_set_gs_primer_num_ns_accepted(p3_global_settings * p , int val);
void p3_set_gs_primer_product_opt_size(p3_global_settings * p , int val);
void p3_set_gs_primer_self_any(p3_global_settings * p , double val);
void p3_set_gs_primer_self_any_th(p3_global_settings * p , double val);
void p3_set_gs_primer_self_end(p3_global_settings * p , double val);
void p3_set_gs_primer_self_end_th(p3_global_settings * p , double val);
void p3_set_gs_primer_hairpin_th(p3_global_settings * p , double val);
void p3_set_gs_primer_file_flag(p3_global_settings * p , int val);
void p3_set_gs_primer_pick_anyway(p3_global_settings * p , int val);
void p3_set_gs_primer_gc_clamp(p3_global_settings * p , int val);
void p3_set_gs_primer_explain_flag(p3_global_settings * p , int val);
void p3_set_gs_primer_liberal_base(p3_global_settings * p , int val);
void p3_set_gs_primer_first_base_index(p3_global_settings * p , int val);
void p3_set_gs_primer_num_return(p3_global_settings * p , int val);
void p3_set_gs_primer_min_quality(p3_global_settings * p , int val);
void p3_set_gs_primer_min_end_quality(p3_global_settings * p , int val);
void p3_set_gs_primer_quality_range_min(p3_global_settings * p , int val);
void p3_set_gs_primer_quality_range_max(p3_global_settings * p , int val);
void p3_set_gs_primer_product_max_tm(p3_global_settings * p , double val);
void p3_set_gs_primer_product_min_tm(p3_global_settings * p , double val);
void p3_set_gs_primer_product_opt_tm(p3_global_settings * p , double val);
void p3_set_gs_primer_task(p3_global_settings * p , char * primer_task);
void p3_set_gs_primer_pick_left_primer(p3_global_settings * p , int pick_left_primer);
void p3_set_gs_primer_pick_right_primer(p3_global_settings * p , int pick_right_primer);
void p3_set_gs_primer_pick_internal_oligo(p3_global_settings * p , int pick_internal_oligo);
void p3_set_gs_primer_internal_oligo_opt_size(p3_global_settings * p , int val);
void p3_set_gs_primer_internal_oligo_max_size(p3_global_settings * p , int val);
void p3_set_gs_primer_internal_oligo_min_size(p3_global_settings * p , int val);
void p3_set_gs_primer_internal_oligo_max_poly_x(p3_global_settings * p , int val);
void p3_set_gs_primer_internal_oligo_opt_tm(p3_global_settings * p , double val);
void p3_set_gs_primer_internal_oligo_max_tm(p3_global_settings * p , double val);
void p3_set_gs_primer_internal_oligo_min_tm(p3_global_settings * p , double val);
void p3_set_gs_primer_internal_oligo_opt_bound(p3_global_settings * p , double val);
void p3_set_gs_primer_internal_oligo_max_bound(p3_global_settings * p , double val);
void p3_set_gs_primer_internal_oligo_min_bound(p3_global_settings * p , double val);
void p3_set_gs_primer_internal_oligo_min_gc(p3_global_settings * p , double val);
void p3_set_gs_primer_internal_oligo_max_gc(p3_global_settings * p , double val);
void p3_set_gs_primer_internal_oligo_salt_conc(p3_global_settings * p , double val);
void p3_set_gs_primer_internal_oligo_divalent_conc(p3_global_settings * p , double val);
void p3_set_gs_primer_internal_oligo_dntp_conc(p3_global_settings * p , double val);
void p3_set_gs_primer_internal_oligo_dna_conc(p3_global_settings * p , double val);
void p3_set_gs_primer_internal_oligo_dmso_conc(p3_global_settings * p , double val);
void p3_set_gs_primer_internal_oligo_dmso_fact(p3_global_settings * p , double val);
void p3_set_gs_primer_internal_oligo_formamide_conc(p3_global_settings * p , double val);
void p3_set_gs_primer_internal_oligo_num_ns(p3_global_settings * p , int val);
void p3_set_gs_primer_internal_oligo_min_quality(p3_global_settings * p , int val);
void p3_set_gs_primer_internal_oligo_self_any(p3_global_settings * p , double val);
void p3_set_gs_primer_internal_oligo_self_any_th(p3_global_settings * p , double val);
void p3_set_gs_primer_internal_oligo_self_end(p3_global_settings * p , double val);
void p3_set_gs_primer_internal_oligo_self_end_th(p3_global_settings * p , double val);
void p3_set_gs_primer_max_mispriming(p3_global_settings * p , double val);
void p3_set_gs_primer_max_mispriming_th(p3_global_settings * p , double val);
void p3_set_gs_primer_internal_oligo_max_mishyb(p3_global_settings * p , double val);
void p3_set_gs_primer_pair_max_mispriming(p3_global_settings * p , double val);
void p3_set_gs_primer_pair_max_mispriming_th(p3_global_settings * p , double val);
void p3_set_gs_primer_max_template_mispriming(p3_global_settings * p , double val);
void p3_set_gs_primer_max_template_mispriming_th(p3_global_settings * p , double val);
void p3_set_gs_primer_lib_ambiguity_codes_consensus(p3_global_settings * p , int val);
void p3_set_gs_primer_inside_penalty(p3_global_settings * p , double val);
void p3_set_gs_primer_outside_penalty(p3_global_settings * p , double val);
void p3_set_gs_primer_mispriming_library(p3_global_settings * p , char * val);
void p3_set_gs_primer_internal_oligo_mishyb_library(p3_global_settings * p , char * val);
void p3_set_gs_primer_max_end_stability(p3_global_settings * p , double val);
void p3_set_gs_primer_lowercase_masking(p3_global_settings * p , int val);
void p3_set_gs_primer_thermodynamic_oligo_alignment(p3_global_settings * p , int val);
void p3_set_gs_primer_thermodynamic_template_alignment(p3_global_settings * p , int val);
void p3_set_gs_primer_wt_tm_gt(p3_global_settings * p , double val);
void p3_set_gs_primer_wt_tm_lt(p3_global_settings * p , double val);
void p3_set_gs_primer_wt_bound_gt(p3_global_settings * p , double val);
void p3_set_gs_primer_wt_bound_lt(p3_global_settings * p , double val);
void p3_set_gs_primer_wt_gc_percent_gt(p3_global_settings * p , double val);
void p3_set_gs_primer_wt_gc_percent_lt(p3_global_settings * p , double val);
void p3_set_gs_primer_wt_size_lt(p3_global_settings * p , double val);
void p3_set_gs_primer_wt_size_gt(p3_global_settings * p , double val);
void p3_set_gs_primer_wt_compl_any(p3_global_settings * p , double val);
void p3_set_gs_primer_wt_compl_any_th(p3_global_settings * p , double val);
void p3_set_gs_primer_wt_compl_end(p3_global_settings * p , double val);
void p3_set_gs_primer_wt_compl_end_th(p3_global_settings * p , double val);
void p3_set_gs_primer_wt_hairpin_th(p3_global_settings * p , double val);
void p3_set_gs_primer_wt_num_ns(p3_global_settings * p , double val);
void p3_set_gs_primer_wt_rep_sim(p3_global_settings * p , double val);
void p3_set_gs_primer_wt_seq_qual(p3_global_settings * p , double val);
void p3_set_gs_primer_wt_end_qual(p3_global_settings * p , double val);
void p3_set_gs_primer_wt_pos_penalty(p3_global_settings * p , double val);
void p3_set_gs_primer_wt_end_stability(p3_global_settings * p , double val);
void p3_set_gs_primer_wt_template_mispriming(p3_global_settings * p , double val);
void p3_set_gs_primer_wt_template_mispriming_th(p3_global_settings * p , double val);
void p3_set_gs_primer_io_wt_tm_gt(p3_global_settings * p , double val);
void p3_set_gs_primer_io_wt_tm_lt(p3_global_settings * p , double val);
void p3_set_gs_primer_io_wt_bound_gt(p3_global_settings * p , double val);
void p3_set_gs_primer_io_wt_bound_lt(p3_global_settings * p , double val);
void p3_set_gs_primer_io_wt_gc_percent_gt(p3_global_settings * p , double val);
void p3_set_gs_primer_io_wt_gc_percent_lt(p3_global_settings * p , double val);
void p3_set_gs_primer_io_wt_size_lt(p3_global_settings * p , double val);
void p3_set_gs_primer_io_wt_size_gt(p3_global_settings * p , double val);
void p3_set_gs_primer_io_wt_wt_coml_any(p3_global_settings * p , double val);
void p3_set_gs_primer_io_wt_compl_end(p3_global_settings * p , double val);
void p3_set_gs_primer_io_wt_wt_coml_any_th(p3_global_settings * p , double val);
void p3_set_gs_primer_io_wt_compl_end_th(p3_global_settings * p , double val);
void p3_set_gs_primer_io_wt_hairpin_th(p3_global_settings * p , double val);
void p3_set_gs_primer_io_wt_num_ns(p3_global_settings * p , double val);
void p3_set_gs_primer_io_wt_rep_sim(p3_global_settings * p , double val);
void p3_set_gs_primer_io_wt_seq_qual(p3_global_settings * p , double val);
void p3_set_gs_primer_io_wt_end_qual(p3_global_settings * p , double val);
void p3_set_gs_primer_pair_wt_pr_penalty(p3_global_settings * p , double val);
void p3_set_gs_primer_pair_wt_io_penalty(p3_global_settings * p , double val);
void p3_set_gs_primer_pair_wt_diff_tm(p3_global_settings * p , double val);
void p3_set_gs_primer_pair_wt_compl_any(p3_global_settings * p , double val);
void p3_set_gs_primer_pair_wt_compl_any_th(p3_global_settings * p , double val);
void p3_set_gs_primer_pair_wt_compl_end(p3_global_settings * p , double val);
void p3_set_gs_primer_pair_wt_compl_end_th(p3_global_settings * p , double val);
void p3_set_gs_primer_pair_wt_hairpin_th(p3_global_settings * p , double val);
void p3_set_gs_primer_pair_wt_product_tm_lt(p3_global_settings * p , double val);
void p3_set_gs_primer_pair_wt_product_tm_gt(p3_global_settings * p , double val);
void p3_set_gs_primer_pair_wt_product_size_gt(p3_global_settings * p , double val);
void p3_set_gs_primer_pair_wt_product_size_lt(p3_global_settings * p , double val);
void p3_set_gs_primer_pair_wt_rep_sim(p3_global_settings * p , double val);
void p3_set_gs_primer_pair_wt_template_mispriming(p3_global_settings * p , double val);
void p3_set_gs_primer_pair_wt_template_mispriming_th(p3_global_settings * p , double val);
void p3_set_gs_first_base_index(p3_global_settings * p , int first_base_index);
void p3_set_gs_liberal_base(p3_global_settings * p , int liberal_base);
void p3_set_gs_num_return(p3_global_settings * p , int num_return);
void p3_set_gs_pick_anyway(p3_global_settings * p , int pick_anyway);
void p3_set_gs_lib_ambiguity_codes_consensus(p3_global_settings * p , int lib_ambiguity_codes_consensus);
void p3_set_gs_quality_range_min(p3_global_settings * p , int quality_range_min);
void p3_set_gs_quality_range_max(p3_global_settings * p , int quality_range_max);
void p3_empty_gs_product_size_range(p3_global_settings *pgs);
/* Return 1 on error (product size range is full);
otherwise return 0. */
int p3_add_to_gs_product_size_range(p3_global_settings *, int, int);
args_for_one_oligo_or_primer *p3_get_global_settings_p_args(p3_global_settings * p);
args_for_one_oligo_or_primer *p3_get_global_settings_o_args(p3_global_settings * p);
int p3_set_afogop_seq_lib(args_for_one_oligo_or_primer *, seq_lib *);
int p3_set_afogop_opt_tm(args_for_one_oligo_or_primer *, double);
/* max_end_gc must be >= 0 and <= 5 */
void p3_set_gs_max_end_gc(p3_global_settings *p, int max_end_gc);
void p3_set_gs_max_end_stability(p3_global_settings * p , int max_end_stability);
void p3_set_gs_gc_clamp(p3_global_settings * p , int gc_clamp);
void p3_set_gs_lowercase_masking(p3_global_settings * p , int lowercase_masking);
void p3_set_gs_outside_penalty(p3_global_settings * p , double outside_penalty);
void p3_set_gs_inside_penalty(p3_global_settings * p , double inside_penalty);
/* DO NOT USE */
/* void p3_set_gs_num_intervals(p3_global_settings * p , int num_intervals); */
void p3_set_gs_pair_max_template_mispriming(p3_global_settings * p ,
double pair_max_template_mispriming);
void p3_set_gs_pair_max_template_mispriming_th(p3_global_settings * p ,
double pair_max_template_mispriming_th);
void p3_set_gs_pair_repeat_compl(p3_global_settings * p, double pair_repeat_compl);
void p3_set_gs_pair_compl_any(p3_global_settings * p , double pair_compl_any);
void p3_set_gs_pair_compl_end(p3_global_settings * p , double pair_compl_end);
void p3_set_gs_pair_compl_any_th(p3_global_settings * p , double pair_compl_any_th);
void p3_set_gs_pair_compl_end_th(p3_global_settings * p , double pair_compl_end_th);
void p3_set_gs_min_left_three_prime_distance(p3_global_settings *p, int min_distance);
void p3_set_gs_min_internal_three_prime_distance(p3_global_settings *p, int min_distance);
void p3_set_gs_min_right_three_prime_distance(p3_global_settings *p, int min_distance);
void p3_set_gs_min_5_prime_overlap_of_junction(p3_global_settings *p, int min_5_prime);
void p3_set_gs_min_3_prime_overlap_of_junction(p3_global_settings *p, int min_3_prime);
void p3_set_gs_min_5_internal_overlap_of_junction(p3_global_settings *p, int min_5_prime);
void p3_set_gs_min_3_internal_overlap_of_junction(p3_global_settings *p, int min_3_prime);
/*
* Choose individual primers or oligos, or primer pairs, or primer
* pairs with internal oligos. On ENOMEM return NULL and set errno.
* Otherwise return retval (updated). Errors are returned in
* in retval.
*/
p3retval *choose_primers(const p3_global_settings *pa,
seq_args_t* sa);
/* For testing/debugging: print the values in pa and sa to stdout. */
void p3_print_args(const p3_global_settings *pa, seq_args_t* sa) ;
void p3_print_args_fd(const p3_global_settings *p, seq_args_t* s, FILE* fd);
/* Print out the content of one primer array */
/* Return 1 on error, otherwise 0. */
int p3_print_one_oligo_list(const seq_args_t* ,
int, const primer_rec[],
const oligo_type, const int,
const int, FILE *,int);
char *pr_oligo_sequence(const seq_args_t* , const primer_rec *);
char *pr_oligo_overhang_sequence(const seq_args_t* , const primer_rec *);
char *pr_oligo_rev_c_sequence(const seq_args_t* , const primer_rec *);
char *pr_oligo_rev_c_overhang_sequence(const seq_args_t* , const primer_rec *);
/* Return NULL on ENOMEM */
pr_append_str *create_pr_append_str();
void init_pr_append_str(pr_append_str *s);
void pr_set_empty(pr_append_str *);
int pr_is_empty(const pr_append_str *);
void destroy_pr_append_str(pr_append_str *);
void destroy_pr_append_str_data(pr_append_str *str);
/* Return 1 on ENOMEM, otherwise 0 */
int pr_append_external(pr_append_str *, const char *);
int pr_append_w_sep_external(pr_append_str *x,
const char *sep,
const char *s);
int pr_append_new_chunk_external(pr_append_str *, const char *);
const char * pr_append_str_chars(const pr_append_str *x);
/* Warning, return pointers to static storage; overwritten on each call. */
const char *p3_get_pair_array_explain_string(const pair_array_t *);
const char *p3_get_oligo_array_explain_string(const oligo_array *);
const char *libprimer3_release(void);
const char *primer3_copyright(void);
/* An accessor function for a primer_rec *. */
double oligo_max_template_mispriming(const primer_rec *);
double oligo_max_template_mispriming_thermod(const primer_rec *);
char * oligo_max_template_mispriming_struct(const primer_rec *h);
int strcmp_nocase(const char *, const char *);
void
p3_set_program_name(const char *name);
/*
* Utility function for C clients -- will not overflow
* buffer. Warning: points to static storage that is over-written
* on the next call.
*/
char* p3_read_line(FILE *file);
/*
Return 1 iff the argument 'oligo' has any problems -- i.e.
violations of design constraints.
*/
int p3_ol_has_any_problem(const primer_rec *oligo);
/*
Return a string details the the problems in 'oligo', i.e. the
constraints that 'oligo' violates. WARNING: Returns a pointer to
static storage, which is over-written on next call.
*/
const char *p3_get_ol_problem_string(const primer_rec *oligo);
/*
Creates up to three files, the names of which are based on the
argument 'file'. One file is a table of forward primers, one a table
of reverse primers, and one a table of internal hybridization
oligos, depending on what the caller to choose_primers() requested
(in the 'pa' argument). Returns 0 on success, 1 on error. On
error, check errno for ENOMEM. Used to implement P3_FILE_FLAG=1.
*/
int p3_print_oligo_lists(const p3retval*,
const seq_args_t* ,
const p3_global_settings *,
pr_append_str *err,
const char* file_name);
/*
Translate the values in the stats struct into an warning string.
Call this function only if the 'stat's contains the _errors_
associated with a given primer i.e. that primer was supplied by the
caller and pick_anyway is set.
*/
void add_must_use_warnings(pr_append_str *warning,
const char* text,
const oligo_stats *stats);
/*
Reverse and complement the sequence seq and put the result in s.
WARNING: It is up the caller to ensure that s points to enough
space.
*/
void p3_reverse_complement(const char *, char *);
#ifdef __cplusplus
}
#endif
#endif
primer3-py-2.3.1/primer3/src/libprimer3/libprimer3flex.c 0000664 0000000 0000000 00001235112 15247271707 0023060 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2023 Ben Pruitt, Nick Conway;
Copyright (c) 2014-2016 Ben Pruitt, Nick Conway; Wyss Institute for Biologically Inspired
Engineering.
This work is a derivative of the original Primer3 library, also
covered under the GPLv2:
Copyright (c) 1996,1997,1998,1999,2000,2001,2004,2006,2007,2008,2009,
2010,2011,2012,2016
Whitehead Institute for Biomedical Research, Steve Rozen
(http://purl.com/STEVEROZEN/), Andreas Untergasser and Helen Skaletsky.
All rights reserved.
This file is part of the primer3 suite and libraries.
The primer3 suite and libraries are free software;
you can redistribute them and/or modify them under the terms
of the GNU General Public License as published by the Free
Software Foundation; either version 2 of the License, or (at
your option) any later version.
This software is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this software (file gpl-2.0.txt in the source
distribution); if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* NOTE: primer3-py.
* libprimer3flex.c and libprimer3flex.h are derivatives of libprimer3.c
*
* The primary goals of this library are:
* 1. Remove global variables to make library threadsafe
* a. `pairs` and `max_j_seen` variables are passed as members of `pairs_args_t`
* b. `dpal_arg_to_use`, `thal_arg_to_use` and `thal_olgio_arg_to_use` static
* variables are now passed in as arguments to `choose_primers()`
* c. `thermodynamic_alignment_length_error` and `thermodynamic_alignment_length_error_msg`
* added into `thal_arg_holder` as a matter-of-convenience and
* i. `align_thermod` to use
* ii: `oligo_template_mispriming`
* ii. `reset_thermodynamic_alignment_length_error() to reset it
* 2. Make the library C code instead of C++ code to provide a uniform C
* interface
*
* NOTES: This library is C only and does not use C++ as the
* upstream libprimer3.cc does. It uses the `klib/khash.h` library to do this
* avoiding C++ complexity and keeping the build for the Cython code simple.
* this only affects lines that use hash maps such as the **pairs variable in
* choose_pair_or_triple (previously global values). now uses the
* `pairs_args_t` datastructure to pass around pointers to the hash map
* C++ code replaced is intentionally commented out as a reference for future
* code comparisons. in older code this replaced `std::hash_map` from
* and `#include ` as of primer3 2.6.1 now replaces
* `std::unordered_map` from `#include `
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include /* toupper */
/* NOTE: primer3-py specific include to enable C only code for hash maps */
#include "khash.h"
/* Check on which OS we compile */
#if defined(_WIN32) || defined(WIN32) || defined (__WIN32__) || defined(__CYGWIN__) || defined(__MINGW32__)
#define OS_WIN
#endif
#include "dpal.h"
#include "thal.h"
#include "oligotm.h"
#include "libprimer3.h"
#include "libprimer3flex.h"
/* #define's */
/*
* OPTIMIZE_OK_REGIONS 1 allows _optimize_ok_regions_list() to use the
* max/min product size info and the max/min oligo length to reduce
* the sizes of the ok regions (while still generating the same primer
* pairs in the same order). Set OPTIMIZE_OK_REGIONS to 0 confirm
* that the results do not change. (The output tags
* PRIMER_{LEFT,RIGHT,PAIR}_EXPLAIN _will_ likely change.)
*/
#define OPTIMIZE_OK_REGIONS 1
#ifndef MAX_PRIMER_LENGTH
#define MAX_PRIMER_LENGTH 36
#endif
#if (MAX_PRIMER_LENGTH > DPAL_MAX_ALIGN)
#error "MAX_PRIMER_LENGTH must be <= DPAL_MAX_ALIGN"
#endif
#if (MAX_PRIMER_LENGTH > THAL_MAX_ALIGN)
# error "MAX_PRIMER_LENGTH must be <= THAL_MAX_ALIGN"
#endif
#define MAX_NN_TM_LENGTH 36 /* The maxium length for which to use the
nearest neighbor model when calculating
oligo Tms. */
#define MACRO_CAT_2(A,B) A##B
#define MACRO_VALUE_AS_STRING(A) MACRO_STRING(A)
#define PR_POSITION_PENALTY_IS_NULL(PA) \
(PR_DEFAULT_INSIDE_PENALTY == (PA)->inside_penalty \
&& PR_DEFAULT_OUTSIDE_PENALTY == (PA)->outside_penalty)
#define INITIAL_LIST_LEN 2000 /* Initial size of oligo lists. */
#define INITIAL_NUM_RETURN 5 /* Initial space to allocate for pairs to
return. */
#define PAIR_OK 1
#define PAIR_FAILED 0
#define OK_OR_MUST_USE(H) (!p3_ol_has_any_problem(H) || (H)->must_use)
#define PR_UNDEFINED_INT_OPT INT_MIN
#define PR_UNDEFINED_DBL_OPT DBL_MIN
/* Undefined value for alignment score (meaning do not check) used for
maximum template mispriming or mishyb. */
#define PR_UNDEFINED_ALIGN_OPT -100.0
#define TRIMMED_SEQ_LEN(X) ((X)->incl_l)
/* primer3-py additional variable for code clarity */
#define DO_PRINTOUT 1
static jmp_buf _jmp_buf;
/* Global static variables. */
static const char* primer3_copyright_char_star = "\n"
"Copyright (c) 1996-2022\n"
"Whitehead Institute for Biomedical Research, Steve Rozen\n"
"(http://purl.com/STEVEROZEN/), Andreas Untergasser and Helen Skaletsky\n"
"All rights reserved.\n"
"\n"
" This file is part of the primer3 suite and libraries.\n"
"\n"
" The primer3 suite and libraries are free software;\n"
" you can redistribute them and/or modify them under the terms\n"
" of the GNU General Public License as published by the Free\n"
" Software Foundation; either version 2 of the License, or (at\n"
" your option) any later version.\n"
"\n"
" This software is distributed in the hope that it will be useful,\n"
" but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
" GNU General Public License for more details.\n"
"\n"
" You should have received a copy of the GNU General Public License\n"
" along with this software (file gpl-2.0.txt in the source\n"
" distribution); if not, write to the Free Software\n"
" Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA\n"
"\n"
"THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n"
"\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n"
"LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n"
"A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n"
"OWNERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n"
"SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n"
"LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n"
"DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n"
"THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n"
"(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n"
"OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
"\n";
static const char* pr_program_name = "probably primer3_core";
static const int use_end_for_th_template_mispriming = 1;
#define DEFAULT_OPT_GC_PERCENT PR_UNDEFINED_INT_OPT
/* Set the program name */
void
p3_set_program_name(const char* pname)
{
pr_program_name = pname;
}
/* ============================================================ */
/* BEGIN functions for global settings */
/* ============================================================ */
/* Allocate space for global settings and fill in defaults */
p3_global_settings*
p3_create_global_settings(void)
{
p3_global_settings* r;
// if (!(r = (p3_global_settings* ) malloc(sizeof(*r)))) {
if ( (r = (p3_global_settings* ) malloc(sizeof(p3_global_settings))) == NULL) {
return NULL;
}
pr_set_default_global_args_2(r);
return r;
}
/* Allocate space for global settings and fill in defaults */
p3_global_settings*
p3_create_global_settings_default_version_1(void)
{
p3_global_settings* r;
// if (!(r = (p3_global_settings* ) malloc(sizeof(*r)))) {
if ((r = (p3_global_settings* ) malloc(sizeof(p3_global_settings))) == NULL) {
return NULL;
}
pr_set_default_global_args_1(r);
return r;
}
/* Free the space of global settings */
void
p3_destroy_global_settings(p3_global_settings* a)
{
if (NULL != a) {
if (NULL != a->p_args.must_match_five_prime) {
free(a->p_args.must_match_five_prime);
a->p_args.must_match_five_prime = NULL;
}
if (NULL != a->p_args.must_match_three_prime) {
free(a->p_args.must_match_three_prime);
a->p_args.must_match_three_prime = NULL;
}
if (NULL != a->o_args.must_match_five_prime) {
free(a->o_args.must_match_five_prime);
a->o_args.must_match_five_prime = NULL;
}
if (NULL != a->o_args.must_match_three_prime) {
free(a->o_args.must_match_three_prime);
a->o_args.must_match_three_prime = NULL;
}
thal_free_parameters(&a->thermodynamic_parameters);
if (NULL != a->mp.list_prefix) {
free(a->mp.list_prefix);
a->mp.list_prefix = NULL;
}
if (a->log_settings_path != NULL) {
free(a->log_settings_path);
a->log_settings_path = NULL;
}
destroy_seq_lib(a->p_args.repeat_lib);
destroy_seq_lib(a->o_args.repeat_lib);
free(a);
a = NULL;
}
}
static void
pr_set_default_global_args_2(
p3_global_settings* a
) {
/* Write the default values for default_values=2 into
the p3_global_settings struct */
pr_set_default_global_args_1(a);
a->tm_santalucia = santalucia_auto;
a->salt_corrections = santalucia;
a->thermodynamic_oligo_alignment = 1;
a->thermodynamic_template_alignment = 0;
a->p_args.divalent_conc = 1.5;
a->p_args.dntp_conc = 0.6;
a->lib_ambiguity_codes_consensus = 0;
}
/* Write the default values for default_values=1 into
the p3_global_settings struct */
static void
pr_set_default_global_args_1(
p3_global_settings* a
) {
// memset(a, 0, sizeof(*a));
memset(a, 0, sizeof(p3_global_settings));
/* Arguments for primers ================================= */
a->p_args.repeat_lib = NULL;
a->o_args.repeat_lib = NULL;
a->p_args.opt_size = 20;
a->p_args.min_size = 18;
a->p_args.max_size = 27;
a->p_args.opt_tm = 60.0;
a->p_args.min_tm = 57.0;
a->p_args.max_tm = 63.0;
a->p_args.opt_bound = 97.0;
a->p_args.min_bound = -10.0;
a->p_args.max_bound = 110.0;
a->p_args.min_gc = 20.0;
a->p_args.opt_gc_content = DEFAULT_OPT_GC_PERCENT;
a->p_args.max_gc = 80.0;
a->p_args.salt_conc = 50.0;
a->p_args.divalent_conc = 0.0;
a->p_args.dntp_conc = 0.0;
a->p_args.dna_conc = 50.0;
a->p_args.dmso_conc = 0.0;
a->p_args.dmso_fact = 0.6;
a->p_args.formamide_conc = 0.0;
a->p_args.num_ns_accepted = 0;
a->p_args.max_self_any = 8.0;
a->p_args.max_self_end = 3.0;
a->p_args.max_self_any_th = 47.0;
a->p_args.max_self_end_th = 47.0;
a->p_args.max_hairpin_th = 47.0;
a->p_args.max_poly_x = 5;
a->p_args.max_repeat_compl = 12.0;
a->p_args.min_quality = 0;
a->p_args.min_end_quality = 0;
a->p_args.max_template_mispriming = PR_UNDEFINED_ALIGN_OPT;
a->p_args.max_template_mispriming_th = PR_UNDEFINED_ALIGN_OPT;
/* The following apply only to primers (and not to internal
oligos). */
a->gc_clamp = 0;
a->max_end_gc = 5;
/* Weights for objective functions for oligos and pairs. */
a->p_args.weights.compl_any = 0;
a->p_args.weights.compl_any_th = 0;
a->p_args.weights.compl_end = 0;
a->p_args.weights.compl_end_th = 0;
a->p_args.weights.end_quality = 0;
a->p_args.weights.end_stability = 0;
a->p_args.weights.gc_content_gt = 0;
a->p_args.weights.gc_content_lt = 0;
a->p_args.weights.hairpin_th = 0;
a->p_args.weights.length_gt = 1;
a->p_args.weights.length_lt = 1;
a->p_args.weights.num_ns = 0;
a->p_args.weights.pos_penalty = 1;
a->p_args.weights.repeat_sim = 0;
a->p_args.weights.seq_quality = 0;
a->p_args.weights.temp_cutoff = 5;
a->p_args.weights.temp_gt = 1;
a->p_args.weights.temp_lt = 1;
a->p_args.weights.bound_gt = 0;
a->p_args.weights.bound_lt = 0;
a->p_args.weights.template_mispriming = 0.0;
a->p_args.weights.template_mispriming_th = 0.0;
a->p_args.must_match_five_prime = NULL;
a->p_args.must_match_three_prime = NULL;
/* End of weights for objective functions for oligos and pairs. */
/* End of arguments for primers =========================== */
a->max_diff_tm = 100.0;
a->tm_santalucia = breslauer_auto;
a->salt_corrections = schildkraut;
a->annealing_temp = -10.0;
a->pair_compl_any = 8.0;
a->pair_compl_end = 3.0;
a->pair_compl_any_th = 47.0;
a->pair_compl_end_th = 47.0;
a->thermodynamic_oligo_alignment = 0;
a->thermodynamic_template_alignment = 0;
thal_set_null_parameters(&a->thermodynamic_parameters);
set_default_thal_parameters(&a->thermodynamic_parameters);
a->show_secondary_structure_alignment = 0;
a->liberal_base = 0;
a->primer_task = generic_p3;
a->pick_left_primer = 1;
a->pick_right_primer = 1;
a->pick_internal_oligo = 0;
a->first_base_index = 0;
a->num_return = 5;
a->pr_min[0] = 100;
a->pr_max[0] = 300;
a->num_intervals = 1;
a->pair_repeat_compl = 24.0;
a->quality_range_min = 0;
a->quality_range_max = 100;
a->outside_penalty = PR_DEFAULT_OUTSIDE_PENALTY;
a->inside_penalty = PR_DEFAULT_INSIDE_PENALTY;
a->max_end_stability = 100.0;
a->lowercase_masking = 0;
a->product_max_tm = PR_DEFAULT_PRODUCT_MAX_TM;
a->product_min_tm = PR_DEFAULT_PRODUCT_MIN_TM;
a->product_opt_tm = PR_UNDEFINED_DBL_OPT;
a->product_opt_size = PR_UNDEFINED_INT_OPT;
a->pair_max_template_mispriming = PR_UNDEFINED_ALIGN_OPT;
a->pair_max_template_mispriming_th = PR_UNDEFINED_ALIGN_OPT;
a->o_args.opt_size = 20;
a->o_args.min_size = 18;
a->o_args.max_size = 27;
a->o_args.opt_tm = 60.0;
a->o_args.min_tm = 57.0;
a->o_args.max_tm = 63.0;
a->o_args.opt_bound = 97.0;
a->o_args.min_bound = -10.0;
a->o_args.max_bound = 110.0;
a->o_args.min_gc = 20.0;
a->o_args.max_gc = 80.0;
a->o_args.opt_gc_content = DEFAULT_OPT_GC_PERCENT;
a->o_args.max_poly_x = 5;
a->o_args.salt_conc = 50.0;
a->o_args.divalent_conc = 0.0;
a->o_args.dntp_conc = 0.0;
a->o_args.dna_conc = 50.0;
a->o_args.dmso_conc = 0.0;
a->o_args.dmso_fact = 0.6;
a->o_args.formamide_conc = 0.0;
a->o_args.num_ns_accepted = 0;
a->o_args.max_self_any = 12.0;
a->o_args.max_self_end = 12.0;
a->o_args.max_self_any_th = 47.0;
a->o_args.max_self_end_th = 47.0;
a->o_args.max_hairpin_th = 47.0;
a->o_args.max_repeat_compl= 12.0;
a->o_args.min_quality = 0;
a->o_args.min_end_quality = 0;
a->o_args.max_template_mispriming = PR_UNDEFINED_ALIGN_OPT;
a->o_args.max_template_mispriming_th = PR_UNDEFINED_ALIGN_OPT;
a->o_args.weights.temp_gt = 1;
a->o_args.weights.temp_lt = 1;
a->o_args.weights.bound_gt = 0;
a->o_args.weights.bound_lt = 0;
a->o_args.weights.length_gt = 1;
a->o_args.weights.length_lt = 1;
a->o_args.weights.gc_content_gt = 0;
a->o_args.weights.gc_content_lt = 0;
a->o_args.weights.compl_any = 0;
a->o_args.weights.compl_end = 0;
a->o_args.weights.compl_any_th = 0;
a->o_args.weights.compl_end_th = 0;
a->o_args.weights.hairpin_th = 0;
a->o_args.weights.num_ns = 0;
a->o_args.weights.repeat_sim = 0;
a->o_args.weights.seq_quality = 0;
a->o_args.weights.end_quality = 0;
a->o_args.must_match_five_prime = NULL;
a->o_args.must_match_three_prime = NULL;
a->pr_pair_weights.primer_quality = 1;
a->pr_pair_weights.io_quality = 0;
a->pr_pair_weights.diff_tm = 0;
a->pr_pair_weights.compl_any = 0;
a->pr_pair_weights.compl_end = 0;
a->pr_pair_weights.compl_any_th = 0;
a->pr_pair_weights.compl_end_th = 0;
a->pr_pair_weights.temp_cutoff = 5;
a->pr_pair_weights.repeat_sim = 0;
a->pr_pair_weights.product_tm_lt = 0;
a->pr_pair_weights.product_tm_gt = 0;
a->pr_pair_weights.product_size_lt = 0;
a->pr_pair_weights.product_size_gt = 0;
a->lib_ambiguity_codes_consensus = 1;
/* Set to 1 for backward compatibility. This _NOT_ what
one normally wants, since many libraries contain
strings of N, which then match every oligo (very bad).
*/
a->min_left_three_prime_distance = -1;
a->min_internal_three_prime_distance = -1;
a->min_right_three_prime_distance = -1;
a->sequencing.lead = 50;
a->sequencing.spacing = 500;
a->sequencing.interval = 250;
a->sequencing.accuracy = 20;
a->p_args.min_5_prime_overlap_of_junction = 7;
a->p_args.min_3_prime_overlap_of_junction = 4;
a->o_args.min_5_prime_overlap_of_junction = 3;
a->o_args.min_3_prime_overlap_of_junction = 3;
a->mask_template = 0;
a->masking_parameters_changed = 0;
a->mp.mdir = both_separately;
a->mp.failure_rate = 0.1;
a->mp.nucl_masked_in_5p_direction = 1;
a->mp.nucl_masked_in_3p_direction = 0;
a->mp.print_sequence = 0;
a->mp.do_soft_masking = 1;
a->mp.nlists = DEFAULT_NLISTS;
a->mp.list_prefix = (char*) pr_safe_malloc(
strlen (DEFAULT_LIST_FILE_PREFIX) + 1
);
strcpy (a->mp.list_prefix, DEFAULT_LIST_FILE_PREFIX);
a->mp.fp = NULL;
a->mp.formula_intercept = DEFAULT_INTERCEPT;
}
/* Add a pair of integers to an array of intervals */
int
p3_add_to_interval_array(
interval_array_t2* interval_arr,
int i1,
int i2
) {
int c = interval_arr->count;
if (c >= PR_MAX_INTERVAL_ARRAY) return 1;
interval_arr->pairs[c][0] = i1;
interval_arr->pairs[c][1] = i2;
interval_arr->count++;
return 0;
}
/* Add 2 pairs of integers to an array of 2 intervals */
int
p3_add_to_2_interval_array(
interval_array_t4* interval_arr,
int i1,
int i2,
int i3,
int i4
) {
int c = interval_arr->count;
if (c >= PR_MAX_INTERVAL_ARRAY) return 1;
/* for a region either both values are given, or none is given */
if (((i1 == -1) && (i2 != -1)) || ((i1 != -1) && (i2 == -1)))
return 2;
if (((i3 == -1) && (i4 != -1)) || ((i3 != -1) && (i4 == -1)))
return 2;
interval_arr->left_pairs[c][0] = i1;
interval_arr->left_pairs[c][1] = i2;
interval_arr->right_pairs[c][0] = i3;
interval_arr->right_pairs[c][1] = i4;
if ((i1 == -1) && (i2 == -1))
interval_arr->any_left = 1;
if ((i3 == -1) && (i4 == -1))
interval_arr->any_right = 1;
if ((i1 == -1) && (i2 == -1) && (i3 == -1) && (i4 == -1))
interval_arr->any_pair = 1;
interval_arr->count++;
return 0;
}
/* ============================================================ */
/* END functions for global settings */
/* ============================================================ */
int
interval_array_t2_count(const interval_array_t2* array)
{
return array->count;
}
const int*
interval_array_t2_get_pair(
const interval_array_t2* array,
int i
) {
if (i > array->count) abort();
if (i < 0) abort();
return array->pairs[i];
}
/* ============================================================ */
/* BEGIN functions for p3retval */
/* ============================================================ */
/* Allocate a new primer3 state. Return NULL if out of memory. Assuming
malloc sets errno to ENOMEM according to Unix98, set errno to ENOMEM
on out-of-memory error. */
static p3retval*
create_p3retval(void)
{
// p3retval* state = (p3retval* )malloc(sizeof(*state));
p3retval* state = (p3retval* )malloc(sizeof(p3retval));
if (!state)
return NULL;
// state->fwd.oligo
// = (primer_rec* ) malloc(sizeof(*state->fwd.oligo) * INITIAL_LIST_LEN);
state->fwd.oligo = (primer_rec* ) malloc(
sizeof(primer_rec) * INITIAL_LIST_LEN
);
// state->rev.oligo
// = (primer_rec* ) malloc(sizeof(*state->rev.oligo) * INITIAL_LIST_LEN);
state->rev.oligo = (primer_rec* ) malloc(
sizeof(primer_rec) * INITIAL_LIST_LEN
);
// state->intl.oligo
// = (primer_rec* ) malloc(sizeof(*state->intl.oligo) * INITIAL_LIST_LEN);
state->intl.oligo = (primer_rec* ) malloc(
sizeof(primer_rec) * INITIAL_LIST_LEN
);
if (
(state->fwd.oligo == NULL) ||
(state->rev.oligo == NULL) ||
(state->intl.oligo == NULL)
) {
free(state);
state = NULL;
return NULL;
}
state->fwd.storage_size = INITIAL_LIST_LEN;
state->rev.storage_size = INITIAL_LIST_LEN;
state->intl.storage_size = INITIAL_LIST_LEN;
state->fwd.num_elem = 0;
state->rev.num_elem = 0;
state->intl.num_elem = 0;
state->fwd.type = OT_LEFT;
state->intl.type = OT_INTL;
state->rev.type = OT_RIGHT;
state->best_pairs.storage_size = 0;
state->best_pairs.pairs = NULL;
state->best_pairs.num_pairs = 0;
init_pr_append_str(&state->glob_err);
init_pr_append_str(&state->per_sequence_err);
init_pr_append_str(&state->warnings);
memset(
&state->fwd.expl,
0,
sizeof(state->fwd.expl)
);
memset(
&state->rev.expl,
0,
sizeof(state->rev.expl)
);
memset(
&state->intl.expl,
0,
sizeof(state->intl.expl)
);
memset(
&state->best_pairs.expl,
0,
sizeof(state->best_pairs.expl)
);
return state;
}
/* ============================================================ */
/* BEGIN functions for dpal_arg_holder */
/* ============================================================ */
/* Create the dpal arg holder */
dpal_arg_holder*
create_dpal_arg_holder()
{
dpal_arg_holder* h = (dpal_arg_holder* ) pr_safe_malloc(
sizeof(dpal_arg_holder)
);
// h->local = (dpal_args* ) pr_safe_malloc(sizeof(*h->local));
h->local = (dpal_args* ) pr_safe_malloc(
sizeof(dpal_args)
);
set_dpal_args(h->local);
h->local->flag = DPAL_LOCAL;
// h->end = (dpal_args* ) pr_safe_malloc(sizeof(*h->end));
h->end = (dpal_args* ) pr_safe_malloc(
sizeof(dpal_args)
);
set_dpal_args(h->end);
h->end->flag = DPAL_GLOBAL_END;
// h->local_end = (dpal_args* ) pr_safe_malloc(sizeof(*h->local_end));
h->local_end = (dpal_args* ) pr_safe_malloc(
sizeof(dpal_args)
);
set_dpal_args(h->local_end);
h->local_end->flag = DPAL_LOCAL_END;
// h->local_ambig = (dpal_args* ) pr_safe_malloc(sizeof(*h->local_ambig));
h->local_ambig = (dpal_args* ) pr_safe_malloc(
sizeof(dpal_args)
);
*h->local_ambig = *h->local;
PR_ASSERT(dpal_set_ambiguity_code_matrix(h->local_ambig));
// h->local_end_ambig = (dpal_args* ) pr_safe_malloc(sizeof(*h->local_end_ambig));
h->local_end_ambig = (dpal_args* ) pr_safe_malloc(
sizeof(dpal_args)
);
*h->local_end_ambig = *h->local_end;
PR_ASSERT(dpal_set_ambiguity_code_matrix(h->local_end_ambig));
return h;
}
/* Free the dpal arg holder */
void
destroy_dpal_arg_holder(
dpal_arg_holder* h
) {
if (h != NULL) {
if (h->local != NULL) {
free(h->local);
h->local = NULL;
}
if (h->end != NULL) {
free(h->end);
h->end = NULL;
}
if (h->local_end != NULL) {
free(h->local_end);
h->local_end = NULL;
}
if (h->local_ambig != NULL) {
free(h->local_ambig);
h->local_ambig = NULL;
}
if (h->local_end_ambig != NULL) {
free(h->local_end_ambig);
h->local_end_ambig = NULL;
}
free(h);
h = NULL;
}
}
/* ============================================================ */
/* END functions for dpal_arg_holder */
/* ============================================================ */
/* ============================================================ */
/* BEGIN functions for thal_arg_holder */
/* ============================================================ */
/* Create the thal arg holder */
thal_arg_holder*
create_thal_arg_holder(
const args_for_one_oligo_or_primer* po_args
) {
thal_arg_holder* h = (thal_arg_holder*) pr_safe_malloc(
sizeof(thal_arg_holder)
);
h->any = (thal_args*) pr_safe_malloc(
sizeof(thal_args)
);
set_thal_default_args(h->any);
h->any->type = thal_any;
h->any->mv = po_args->salt_conc;
h->any->dv = po_args->divalent_conc;
h->any->dntp = po_args->dntp_conc;
h->any->dna_conc = po_args->dna_conc;
h->end1 = (thal_args*) pr_safe_malloc(
sizeof(thal_args)
);
set_thal_default_args(h->end1);
h->end1->type = thal_end1;
h->end1->mv = po_args->salt_conc;
h->end1->dv = po_args->divalent_conc;
h->end1->dntp = po_args->dntp_conc;
h->end1->dna_conc = po_args->dna_conc;
h->end2 = (thal_args*) pr_safe_malloc(
sizeof(thal_args)
);
set_thal_default_args(h->end2);
h->end2->type = thal_end2;
h->end2->mv = po_args->salt_conc;
h->end2->dv = po_args->divalent_conc;
h->end2->dntp = po_args->dntp_conc;
h->end2->dna_conc = po_args->dna_conc;
h->hairpin_th = (thal_args*) pr_safe_malloc(
sizeof(thal_args)
);
set_thal_default_args(h->hairpin_th);
h->hairpin_th->type = thal_hairpin;
h->hairpin_th->mv = po_args->salt_conc;
h->hairpin_th->dv = po_args->divalent_conc;
h->hairpin_th->dntp = po_args->dntp_conc;
h->hairpin_th->dna_conc = po_args->dna_conc;
h->hairpin_th->dimer = 0;
h->thermodynamic_alignment_length_error = 0;
h->thermodynamic_alignment_length_error_msg = NULL;
return h;
}
/* Free the thal arg holder */
void
destroy_thal_arg_holder(
thal_arg_holder* h
) {
if (h != NULL) {
if (h->any != NULL) {
free(h->any);
h->any = NULL;
}
if (h->end1 != NULL) {
free(h->end1);
h->end1 = NULL;
}
if (h->end2 != NULL) {
free(h->end2);
h->end2 = NULL;
}
if (h->hairpin_th != NULL) {
free(h->hairpin_th);
h->hairpin_th = NULL;
}
if (h->thermodynamic_alignment_length_error_msg != NULL) {
free(h->thermodynamic_alignment_length_error_msg);
h->thermodynamic_alignment_length_error_msg = NULL;
}
free(h);
h = NULL;
}
}
void reset_thermodynamic_alignment_length_error(
thal_arg_holder* h
) {
if (h->thermodynamic_alignment_length_error_msg != NULL) {
free(h->thermodynamic_alignment_length_error_msg);
h->thermodynamic_alignment_length_error_msg = NULL;
}
h->thermodynamic_alignment_length_error = 0;
}
/* ============================================================ */
/* END functions for thal_arg_holder */
/* ============================================================ */
/* Deallocate a primer3 state */
void
destroy_p3retval(
p3retval* state
) {
if (!state)
return;
free_repeat_sim_score(state);
free(state->fwd.oligo);
state->fwd.oligo = NULL;
free(state->rev.oligo);
state->rev.oligo = NULL;
free(state->intl.oligo);
state->intl.oligo = NULL;
if (
(state->best_pairs.storage_size != 0) &&
(state->best_pairs.pairs)
) {
free(state->best_pairs.pairs);
state->best_pairs.pairs = NULL;
}
destroy_pr_append_str_data(&state->glob_err);
destroy_pr_append_str_data(&state->per_sequence_err);
destroy_pr_append_str_data(&state->warnings);
free(state);
state = NULL;
}
void
destroy_dpal_thal_arg_holder() {
/* Locally scoped by primer3-py so here for legacy*/
}
const oligo_array*
p3_get_rv_fwd(const p3retval* r) {
return &r->fwd;
}
const oligo_array*
p3_get_rv_intl(const p3retval* r) {
return &r->intl;
}
const oligo_array*
p3_get_rv_rev(const p3retval* r) {
return &r->rev;
}
const pair_array_t*
p3_get_rv_best_pairs(const p3retval* r) {
return &r->best_pairs;
}
/* ============================================================ */
/* END functions for p3retval */
/* ============================================================ */
/* ============================================================ */
/* BEGIN functions for seq_arg_holder */
/* ============================================================ */
/* Create and initialize a seq_args_t data structure */
seq_args_t *
create_seq_arg()
{
// seq_args_t* r = (seq_args_t*) malloc(sizeof(*r));
seq_args_t *r = (seq_args_t *) malloc(sizeof(seq_args_t));
if (r == NULL) return NULL; /* Out of memory */
memset(r, 0, sizeof(seq_args_t));
r->start_codon_pos = PR_DEFAULT_START_CODON_POS;
r->start_codon_seq[0] = 'A';
r->start_codon_seq[1] = 'T';
r->start_codon_seq[2] = 'G';
r->start_codon_seq[3] = '\0';
r->incl_l = -1; /* Indicates logical NULL. */
r->force_left_start = PR_NULL_FORCE_POSITION; /* Indicates logical NULL. */
r->force_left_end = PR_NULL_FORCE_POSITION; /* Indicates logical NULL. */
r->force_right_start = PR_NULL_FORCE_POSITION; /* Indicates logical NULL. */
r->force_right_end = PR_NULL_FORCE_POSITION; /* Indicates logical NULL. */
r->primer_overlap_junctions_count = 0;
r->intl_overlap_junctions_count = 0;
r->n_quality = 0;
r->quality = NULL;
r->overhang_left = NULL;
r->overhang_right = NULL;
r->overhang_right_rv = NULL;
return r;
}
/* Free a seq_arg data structure */
void
destroy_seq_args(seq_args_t* sa)
{
if (sa == NULL) return;
if (sa->internal_input != NULL) {
free(sa->internal_input);
sa->internal_input = NULL;
}
if (sa->left_input != NULL) {
free(sa->left_input);
sa->left_input = NULL;
}
if (sa->right_input != NULL) {
free(sa->right_input);
sa->right_input = NULL;
}
if (sa->sequence != NULL) {
free(sa->sequence);
sa->sequence = NULL;
}
if (sa->quality != NULL) {
free(sa->quality);
sa->quality = NULL;
}
if (sa->trimmed_seq != NULL) {
free(sa->trimmed_seq);
sa->trimmed_seq = NULL;
}
if (sa->overhang_left != NULL) {
free(sa->overhang_left);
sa->overhang_left = NULL;
}
if (sa->overhang_right != NULL) {
free(sa->overhang_right);
sa->overhang_right = NULL;
}
if (sa->overhang_right_rv != NULL) {
free(sa->overhang_right_rv);
sa->overhang_right_rv = NULL;
}
/* edited by T. Koressaar for lowercase masking */
if (sa->trimmed_orig_seq != NULL) {
free(sa->trimmed_orig_seq);
sa->trimmed_orig_seq = NULL;
}
if (sa->trimmed_masked_seq_r != NULL) {
free(sa->trimmed_masked_seq_r);
sa->trimmed_masked_seq_r = NULL;
}
if (sa->trimmed_masked_seq != NULL) {
free(sa->trimmed_masked_seq);
sa->trimmed_masked_seq = NULL;
}
if (sa->upcased_seq != NULL) {
free(sa->upcased_seq);
sa->upcased_seq = NULL;
}
if (sa->upcased_seq_r != NULL) {
free(sa->upcased_seq_r);
sa->upcased_seq_r = NULL;
}
if (sa->sequence_name != NULL) {
free(sa->sequence_name);
sa->sequence_name = NULL;
}
free(sa);
sa = NULL;
}
/* ============================================================ */
/* END functions for seq_arg_holder */
/* ============================================================ */
/* Function used to de-allocate the memory used by the hash maps
allocated in choose_pair_or_triple. */
static void free_pair_memory(int rev_num_elem, pairs_args_t* pairs_args)
{
// std::hash_map *hmap;
// std::hash_map::iterator it;
khash_t(primer_pair_map) *hmap = NULL;
khiter_t it;
primer_pair* pp = NULL;
int i;
if (pairs_args->max_j_seen != NULL) {
free( pairs_args->max_j_seen );
pairs_args->max_j_seen = NULL;
}
for (i=0; i < rev_num_elem; i++) {
hmap = pairs_args->pairs[i];
if (hmap != NULL) {
// for (it=hmap->begin(); it!=hmap->end(); it++) {
for (it = kh_begin(hmap); it != kh_end(hmap); ++it) {
// pp = it->second;
// if (pp != NULL) {
// // delete pp;
// }
if (kh_exist(hmap, it)) {
pp = kh_value(hmap, it);
if (pp != NULL) {
free(pp);
kh_value(hmap, it) = NULL;
pp = NULL;
}
}
}
// delete hmap;
kh_destroy(primer_pair_map, hmap);
}
}
if (pairs_args->pairs != NULL) {
free(pairs_args->pairs);
pairs_args->pairs = NULL;
}
}
void print_masking_parameters(const masker_parameters* mp, FILE* fd);
/* ============================================================ */
/* BEGIN choose_primers() */
/* The main primer3 interface */
/* See libprimer3.h for documentation. */
/* ============================================================ */
p3retval*
choose_primers(
const p3_global_settings* pa,
seq_args_t* sa
) {
/* Create retval and set were to find the results */
p3retval* retval = create_p3retval();
if (retval == NULL) { return NULL; }
/* primer3-py update: `dpal_arg_to_use`, `thal_arg_to_use`, and
*`thal_oligo_arg_to_use` are function local from global scope for thread safety
*/
dpal_arg_holder* dpal_arg_to_use = NULL;
dpal_arg_to_use = create_dpal_arg_holder();
if (dpal_arg_to_use == NULL) {
printf("Argument Failure: dpal_arg_to_use == NULL\n");
return NULL;
}
thal_arg_holder* thal_arg_to_use = NULL;
thal_arg_to_use = create_thal_arg_holder(
&pa->p_args
);
if (thal_arg_to_use == NULL) {
printf("Argument Failure: thal_arg_to_use == NULL\n");
destroy_dpal_arg_holder(dpal_arg_to_use);
return NULL;
}
thal_arg_holder* thal_oligo_arg_to_use = NULL;
thal_oligo_arg_to_use = create_thal_arg_holder(
&pa->o_args
);
if (thal_oligo_arg_to_use == NULL) {
printf("Argument Failure: thal_oligo_arg_to_use == NULL\n");
destroy_dpal_arg_holder(dpal_arg_to_use);
destroy_thal_arg_holder(thal_arg_to_use);
return NULL;
}
PR_ASSERT(NULL != pa);
PR_ASSERT(NULL != sa);
/* primer3-py update: 2023.03.21 moved pairs, max_j_seen from global /
choose_pair_or_triple to support thread safety improvements
*/
pairs_args_t pairs_args = {NULL, NULL};
/* NOTE: primer3-py added to debugging arguments `pa` and `sa` */
if (pa->do_log_settings) {
FILE* logf_ptr = fopen(pa->log_settings_path, "ab");
if (logf_ptr == NULL) {
printf(
"Error opening file %s\n",
pa->log_settings_path
);
fflush(stdout);
destroy_dpal_arg_holder(dpal_arg_to_use);
destroy_thal_arg_holder(thal_arg_to_use);
destroy_thal_arg_holder(thal_oligo_arg_to_use);
exit(1);
}
p3_print_args_fd(pa, sa, logf_ptr);
print_masking_parameters(&(pa->mp), logf_ptr);
fclose(logf_ptr);
}
if (pa->dump) {
printf("Start of choose_primers:\n");
p3_print_args(pa, sa) ;
}
/* Set the general output type */
if (
(pa->pick_left_primer) &&
(pa->pick_right_primer)
) {
retval->output_type = primer_pairs;
} else {
retval->output_type = primer_list;
}
if (
(pa->primer_task == pick_primer_list) ||
(pa->primer_task == pick_sequencing_primers)
) {
retval->output_type = primer_list;
}
/*
* For catching ENOMEM. WARNING: We can only use longjmp to escape
* from errors that have been called through choose_primers().
* Therefore, if we subsequently update other static functions in
* this file to have external linkage then we need to check whether
* they call (or use functions that in turn call) longjmp to handle
* ENOMEM.
*/
if (setjmp(_jmp_buf) != 0) {
/* Check if this was a thermodynamic alignment length error. */
if (thal_arg_to_use->thermodynamic_alignment_length_error == 1) {
thal_arg_to_use->thermodynamic_alignment_length_error = 0;
/* Set per sequence error */
pr_append_new_chunk(
&retval->per_sequence_err,
thal_arg_to_use->thermodynamic_alignment_length_error_msg
);
if (thal_arg_to_use->thermodynamic_alignment_length_error_msg != NULL) {
free(thal_arg_to_use->thermodynamic_alignment_length_error_msg);
thal_arg_to_use->thermodynamic_alignment_length_error_msg = NULL;
}
/* Other necessary cleanup. */
free_pair_memory(retval->rev.num_elem, &pairs_args);
destroy_dpal_arg_holder(dpal_arg_to_use);
destroy_thal_arg_holder(thal_arg_to_use);
destroy_thal_arg_holder(thal_oligo_arg_to_use);
return retval;
}
/* This was a memory error. */
destroy_p3retval(retval);
destroy_dpal_arg_holder(dpal_arg_to_use);
destroy_thal_arg_holder(thal_arg_to_use);
destroy_thal_arg_holder(thal_oligo_arg_to_use);
return NULL; /* If we get here, that means errno should be ENOMEM. */
}
/* Change some parameters to fit the task */
_adjust_seq_args(
pa,
sa,
&retval->per_sequence_err,
&retval->warnings
);
if (pa->dump) {
printf("After _adjust_seq_args\n");
p3_print_args(pa, sa) ;
}
if (!pr_is_empty(&retval->per_sequence_err)) {
destroy_dpal_arg_holder(dpal_arg_to_use);
destroy_thal_arg_holder(thal_arg_to_use);
destroy_thal_arg_holder(thal_oligo_arg_to_use);
return retval;
}
/* TO DO -- move the check below to pr_data_control and issue a
warning if it fails. */
/* if (pa->p_args.min_quality != 0
&& pa->p_args.min_end_quality < pa->p_args.min_quality)
... issue warning ...
pa->p_args.min_end_quality = pa->p_args.min_quality; */
/* Check if the input in sa and pa makes sense */
if (
_pr_data_control(
pa,
sa,
&retval->glob_err, /* Fatal errors */
&retval->per_sequence_err, /* Non-fatal errors */
&retval->warnings
) !=0
) {
destroy_dpal_arg_holder(dpal_arg_to_use);
destroy_thal_arg_holder(thal_arg_to_use);
destroy_thal_arg_holder(thal_oligo_arg_to_use);
return retval;
}
set_retval_both_stop_codons(sa, retval);
/* Set the parameters for alignment functions
if dpal_arg_to_use, a static variable that has 'file'
scope, has not yet been initialized. */
if (pa->primer_task == pick_primer_list) {
make_complete_primer_lists(
retval,
pa,
sa,
dpal_arg_to_use,
thal_arg_to_use,
thal_oligo_arg_to_use
);
} else if (pa->primer_task == pick_sequencing_primers) {
pick_sequencing_primer_list(
retval,
pa,
sa,
dpal_arg_to_use,
thal_arg_to_use
);
} else if (pa->primer_task == check_primers) {
add_primers_to_check(
retval,
pa, sa,
dpal_arg_to_use,
thal_arg_to_use,
thal_oligo_arg_to_use
);
} else { /* The general way to pick primers */
/* Populate the forward and reverse primer lists */
if (
make_detection_primer_lists(
retval,
pa,
sa,
dpal_arg_to_use,
thal_arg_to_use
) != 0
) {
/* There was an error */
destroy_dpal_arg_holder(dpal_arg_to_use);
destroy_thal_arg_holder(thal_arg_to_use);
destroy_thal_arg_holder(thal_oligo_arg_to_use);
return retval;
}
/* Populate the internal oligo lists */
if ( pa->pick_internal_oligo) {
if (
make_internal_oligo_list(
retval,
pa,
sa,
dpal_arg_to_use,
thal_oligo_arg_to_use
) != 0
) {
/* There was an error*/
destroy_dpal_arg_holder(dpal_arg_to_use);
destroy_thal_arg_holder(thal_arg_to_use);
destroy_thal_arg_holder(thal_oligo_arg_to_use);
return retval;
}
}
}
if (
(pa->pick_right_primer) &&
(pa->primer_task != pick_sequencing_primers)
) {
sort_primer_array(&retval->rev);
}
if (
(pa->pick_left_primer) &&
(pa->primer_task != pick_sequencing_primers)
) {
sort_primer_array(&retval->fwd);
}
/* If we are returning a list of internal oligos, sort them by their
'goodness'. We do not care if these are sorted if we end up in
choose_pair_or_triple(), since this calls
choose_internal_oligo(), which selects the best internal oligo
for a given primer pair. */
if (
(retval->output_type == primer_list) &&
(pa->pick_internal_oligo == 1)
) {
sort_primer_array(&retval->intl);
}
/* Select primer pairs if needed */
if (retval->output_type == primer_pairs) {
choose_pair_or_triple(
retval,
pa,
sa,
dpal_arg_to_use,
thal_arg_to_use,
thal_oligo_arg_to_use,
&retval->best_pairs,
&pairs_args
);
}
/* Calculate secondary structures only for the selected primers */
if (pa->show_secondary_structure_alignment == 1) {
recalc_secundary_structures(
pa,
sa,
dpal_arg_to_use,
thal_arg_to_use,
thal_oligo_arg_to_use,
retval
);
}
if (pa->dump) {
printf("End of choose_primers:\n");
p3_print_args(pa, sa) ;
}
destroy_dpal_arg_holder(dpal_arg_to_use);
destroy_thal_arg_holder(thal_arg_to_use);
destroy_thal_arg_holder(thal_oligo_arg_to_use);
return retval;
}
/* ============================================================ */
/* END choose_primers() */
/* ============================================================ */
/* ============================================================ */
/* BEGIN choose_pair_or_triple
This function uses retval->fwd and retval->rev and
updates the oligos in these array.
This function posibly uses retval->intl and updates its
elements via choose_internal_oligo().
This function examines primer pairs or triples to find
pa->num_return pairs or triples to return.
Results are returned in best_pairs and in
retval->best_pairs.expl */
/* ============================================================ */
static void
choose_pair_or_triple(
p3retval* retval,
const p3_global_settings* pa,
const seq_args_t* sa,
const dpal_arg_holder* dpal_arg_to_use,
const thal_arg_holder* thal_arg_to_use,
const thal_arg_holder* thal_oligo_arg_to_use,
pair_array_t* best_pairs,
pairs_args_t *pairs_args
) {
int i, j; /* Loop index. */
int n_int; /* Index of the internal oligo */
int more_intl_oligos = 1;
int valid_intl;
int update_stats = 1; /* Flag to indicate whether pair_stats
should be updated. */
primer_pair h; /* The current pair which is being evaluated. */
primer_pair the_best_pair; /* The best pair is being "remembered". */
pair_stats* pair_expl = &retval->best_pairs.expl; /* For statistics */
int *max_j_seen = NULL;
khash_t(primer_pair_map) **pairs = NULL;
int product_size_range_index = 0;
int trace_me = 0;
int the_best_i, the_best_j;
/* Hash maps used to store pairs that were computed */
/* std::hash_map **pairs; */
/* pairs is an array of pointers to hash maps. It will be indexed
by the indices of the reverse primers in retval->rev. -- global var now */
// std::hash_map *hmap, *best_hmap = NULL;
khash_t(primer_pair_map) *hmap = NULL;
khash_t(primer_pair_map) *best_hmap = NULL;
/* hmap and best_hmap will be pointers to hash maps also pointed to
by elements of pairs. */
// std::hash_map::iterator it;
khiter_t it; // khash iterator / key hybrid type
int ret; // return value for error code on khash
primer_pair* pp = NULL;
primer_pair* best_pp = NULL;
int pair_found = 0;
// only to avoid compiler warning for unused function
kh_clear(primer_pair_map, hmap);
// pairs =
// (std::hash_map**)
// calloc (retval->rev.num_elem,
// sizeof(std::hash_map*));
pairs_args->pairs = (khash_t(primer_pair_map) **) calloc (
retval->rev.num_elem,
sizeof(khash_t(primer_pair_map) *)
);
pairs = pairs_args->pairs;
if (!pairs) { longjmp(_jmp_buf, 1); }
memset(&the_best_pair, 0, sizeof(the_best_pair));
pairs_args->max_j_seen = (int*) malloc(
sizeof(int) * retval->rev.num_elem
);
max_j_seen = pairs_args->max_j_seen;
for (i = 0; i < retval->rev.num_elem; i++) {
max_j_seen[i] = -1;
}
/* Pick pairs till we have enough. */
while(1) {
/* FIX ME, is this memset really needed? Apparently slow */
memset(&the_best_pair, 0, sizeof(the_best_pair));
the_best_i = -1;
the_best_j = -1;
/* To start put penalty to the maximum */
the_best_pair.pair_quality = DBL_MAX;
/* Iterate over the reverse primers. */
for (i = 0; i < retval->rev.num_elem; i++) {
hmap = pairs[i];
/* Pairs[i] is NULL if there has never been an assignment to
pairs[i] because pairs was allocated by calloc, which
sets the allocated memory to 0. */
/* Only use a primer that *might be* legal or that the caller
has provided and specified as "must use". Primers are *NOT*
FULLY ASSESSED until the call to characterize_pair(), in
order to avoid expensive computations (mostly alignments)
unless necessary. */
if (!OK_OR_MUST_USE(&retval->rev.oligo[i])) {
/* Can free the memory used by the hmap associated to this
reverse primer */
if (hmap) {
// for (it=hmap->begin(); it!=hmap->end(); it++) {
for (it = kh_begin(hmap); it != kh_end(hmap); ++it) {
/* it->second is the second element (i.e. the 'value', as
opposed to the 'key'). */
// pp = it->second;
// delete pp;{
if (kh_exist(hmap, it)) {
pp = kh_value(hmap, it);
if (pp != NULL) {
free(pp);
kh_value(hmap, it) = NULL;
pp = NULL;
}
}
}
if (hmap == best_hmap) { best_hmap = NULL; }
// delete hmap;
kh_destroy(primer_pair_map, hmap);
hmap = NULL;
pairs[i] = NULL;
}
continue;
}
/* If the pair cannot be better than the one already
* selected, then we can skip remaining reverse primers */
if (
(
pa->pr_pair_weights.primer_quality *
(retval->rev.oligo[i].quality + retval->fwd.oligo[0].quality)
) > the_best_pair.pair_quality
) {
break;
}
if (!more_intl_oligos) {
break;
}
if (retval->rev.oligo[i].overlaps) {
/* The stats will not keep track of the pair correctly
after the first pass, because an oligo might
have been legal on one pass but become illegal on
a subsequent pass. */
if (update_stats) {
if (trace_me) {
fprintf(
stderr,
"i=%d, j=%d, overlaps_oligo_in_better_pair++\n",
i, j
);
}
pair_expl->overlaps_oligo_in_better_pair++;
}
/* Can free the memory used by the hmap associated to this reverse primer */
if (hmap) {
// for (it=hmap->begin(); it!=hmap->end(); it++) {
for (it = kh_begin(hmap); it != kh_end(hmap); ++it) {
/* it->second is the second element (i.e. the 'value', as
opposed to the 'key'). */
// pp = it->second;
// delete pp;
if (kh_exist(hmap, it)) {
pp = kh_value(hmap, it);
if (pp != NULL) {
free(pp);
kh_value(hmap, it) = NULL;
pp = NULL;
}
}
}
if (hmap == best_hmap) { best_hmap = NULL; }
// delete hmap;
kh_destroy(primer_pair_map, hmap);
hmap = NULL;
pairs[i] = NULL;
}
continue;
}
/* Loop over forward primers */
for (j = 0; j < retval->fwd.num_elem; j++) {
int must_use;
double product_size;
/* We check the reverse oligo again, because we may
have determined that it is "not ok", even though
(as a far as we knew), it was ok above. */
if (!OK_OR_MUST_USE(&retval->rev.oligo[i])) {
/* Can free the memory used by the hmap associated to this reverse primer */
if (hmap) {
// for (it=hmap->begin(); it!=hmap->end(); it++) {
for (it = kh_begin(hmap); it != kh_end(hmap); ++it) {
/* it->second is the second element (i.e. the 'value', as
opposed to the 'key'). */
// pp = it->second;
// delete pp;
if (kh_exist(hmap, it)) {
pp = kh_value(hmap, it);
if (pp != NULL) {
free(pp);
kh_value(hmap, it) = NULL;
pp = NULL;
}
}
}
if (hmap == best_hmap) { best_hmap = NULL; }
// delete hmap;
kh_destroy(primer_pair_map, hmap);
hmap = NULL;
pairs[i] = NULL;
}
break;
}
/* Only use a primer that is legal, or that the caller
has provided and specified as "must use". */
if (!OK_OR_MUST_USE(&retval->fwd.oligo[j])) continue;
/* If the pair cannot be better than the one already
* selected, then we can skip remaining forward primers
* for this reverse primer */
if (
(
pa->pr_pair_weights.primer_quality *
(retval->fwd.oligo[j].quality + retval->rev.oligo[i].quality)
)
> the_best_pair.pair_quality
) {
break;
}
if (!more_intl_oligos) {
break;
}
/* Need to have this here because if we break just above, then,
at a later iteration, we may need to examine the oligo
pair with reverse oligo at i and forward oligo at j. */
update_stats = 0;
if (j > max_j_seen[i]) {
if (trace_me) {
fprintf(
stderr,
"updates ON: i=%d, j=%d, max_j_seen[%d]=%d\n",
i, j, i, max_j_seen[i]
);
}
max_j_seen[i] = j;
if (trace_me) {
fprintf(
stderr,
"max_j_seen[%d] --> %d\n",
i, max_j_seen[i]
);
}
if (trace_me) { fprintf(stderr, "updates on\n"); }
update_stats = 1;
}
if (retval->fwd.oligo[j].overlaps) {
/* The stats will not keep track of the pair correctly
after the first pass, because an oligo might
have been legal on one pass but become illegal on
a subsequent pass. */
if (update_stats) {
if (trace_me) {
fprintf(
stderr,
"i=%d, j=%d, overlaps_oligo_in_better_pair++\n",
i, j
);
}
pair_expl->overlaps_oligo_in_better_pair++;
}
continue;
}
/* Some simple checks first, before searching the hashmap */
must_use = 0;
if (
(pa->primer_task == check_primers) ||
(
(retval->fwd.oligo[j].must_use != 0) &&
(retval->rev.oligo[i].must_use != 0)
)
) {
must_use = 1;
}
/* Determine if overlap with an overlap point is required, and
if so, whether one of the primers in the pairs overlaps
that point. */
if (
(sa->primer_overlap_junctions_count > 0) &&
!(
(retval->rev.oligo[i].overlaps_overlap_position) ||
(retval->fwd.oligo[j].overlaps_overlap_position)
)
) {
if (update_stats) {
pair_expl->considered++;
pair_expl->does_not_overlap_a_required_point++;
}
if (!must_use) continue;
}
/* Check product size now */
product_size = (
retval->rev.oligo[i].start - retval->fwd.oligo[j].start+ 1
);
if (
(product_size < pa->pr_min[product_size_range_index]) ||
(product_size > pa->pr_max[product_size_range_index])
) {
if (update_stats) {
/* This line NEW */
if (!must_use) {
pair_expl->considered++;
}
pair_expl->product++;
}
if (!must_use) { continue; }
}
/* Check if pair was already computed */
pair_found = 0;
if (hmap) {
// it = hmap->find(j);
it = kh_get(primer_pair_map, hmap, j);
// if (it != hmap->end()) {
if (it != kh_end(hmap)) {
pair_found = 1;
/* it->second is the second element (i.e. the 'value', as
opposed to the 'key'). */
// pp = it->second;
pp = kh_value(hmap, it);
if (pp) {
/* The pair was computed, it isn't illegal and it wasn't
selected yet */
if (update_stats) {
pair_expl->considered++;
if (trace_me) {
fprintf(stderr, "ok++\n");
}
pair_expl->ok++;
}
/* Check if this is a better pair */
if (compare_primer_pair(pp, &the_best_pair) < 0) {
the_best_pair = *pp;
the_best_i = i;
the_best_j = j;
best_hmap = hmap;
best_pp = pp;
}
/* There cannot be a better pair */
if (the_best_pair.pair_quality == 0) {
break;
}
} /* else - pp is NULL - it's illegal or already selected */
}
} else {
/* Create this hashmap */
// hmap = new std::hash_map;
hmap = kh_init(primer_pair_map);
if (!hmap) {
longjmp(_jmp_buf, 1);
}
pairs[i] = hmap;
}
if (!pair_found) {
/* Characterize the pair. h is initialized by this
call. */
int tmp = 0;
tmp = characterize_pair(
retval,
pa,
sa,
j,
i,
product_size_range_index,
&h,
dpal_arg_to_use,
thal_arg_to_use,
update_stats
);
if (tmp == PAIR_OK) {
/* Choose internal oligo if needed */
if (
(pa->pick_right_primer) &&
(pa->pick_left_primer) &&
(pa->pick_internal_oligo)
) {
if (
choose_internal_oligo(
retval,
h.left,
h.right,
&n_int,
&more_intl_oligos,
sa,
pa,
dpal_arg_to_use,
thal_oligo_arg_to_use,
thal_oligo_arg_to_use
) != 0
) {
/* We were UNable to choose an internal oligo. */
if (update_stats) {
pair_expl->internal++;
}
/* Mark the pair as not good - the entry in the hash
map will be a NULL */
// (*hmap)[j] = NULL;
it = kh_get(primer_pair_map, hmap, j);
if (it == kh_end(hmap)) {
it = kh_put(primer_pair_map, hmap, j, &ret);
if (!ret) { kh_del(primer_pair_map, hmap, it); }
}
kh_value(hmap, it) = NULL;
continue;
} else {
/* We DID choose an internal oligo, and we
set h.intl to point to it. */
h.intl = &retval->intl.oligo[n_int];
}
}
if (update_stats) {
if (trace_me) {
fprintf(stderr, "ok++\n");
}
pair_expl->ok++;
}
/* Calculate the pair penalty */
h.pair_quality = obj_fn(pa, &h);
PR_ASSERT(h.pair_quality >= 0.0);
/* Save the pair */
// pp = new primer_pair;
pp = (primer_pair* ) malloc(sizeof(primer_pair));
if (!pp) {
longjmp(_jmp_buf, 1);
}
*pp = h;
// (*hmap)[j] = pp;
it = kh_get(primer_pair_map, hmap, j);
if (it == kh_end(hmap)) {
it = kh_put(primer_pair_map, hmap, j, &ret);
}
kh_value(hmap, it) = pp;
/* The current pair (h) is the new best pair if it is
better than the best pair so far. */
if (compare_primer_pair(&h, &the_best_pair) < 0) {
the_best_pair = h;
the_best_i = i;
the_best_j = j;
best_hmap = hmap;
best_pp = pp;
}
/* There cannot be a better pair */
if (the_best_pair.pair_quality == 0) {
break;
}
} else if (tmp == PAIR_FAILED) {
/* Illegal pair */
// (*hmap)[j] = NULL;
it = kh_get(primer_pair_map, hmap, j);
if (it == kh_end(hmap)) {
it = kh_put(primer_pair_map, hmap, j, &ret);
}
kh_value(hmap, it) = NULL;
}
}
} /* for (j=0; jfwd.num_elem; j++) -- inner loop */
/* Check if there cannot be a better pair than best found */
if (the_best_pair.pair_quality == 0) {
break;
}
} /* for (i = 0; i < retval->rev.num_elem; i++) --- outer loop */
if (!more_intl_oligos) {
/* No more internal oligos left */
break;
}
if (the_best_pair.pair_quality == DBL_MAX) {
/* No pair was found. Try another product-size-range,
if one exists. */
product_size_range_index++;
/* Re-set the high-water marks for the indices
for reverse and forward primers: */
for (i = 0; i < retval->rev.num_elem; i++) {
max_j_seen[i] = -1;
}
if (!(product_size_range_index < pa->num_intervals)) {
/* We ran out of product-size-ranges. Exit the while loop. */
break;
/* Our bookkeeping was incorrect unless the assertion below is
true. If num_intervals > 1 or min_three_*_prime_distance >
-1 the assertion below might not be true. */
PR_ASSERT(
!((pa->num_intervals == 1) &&
((pa->min_left_three_prime_distance == -1) ||
(pa->min_right_three_prime_distance == -1))) ||
(best_pairs->num_pairs == pair_expl->ok)
);
}
} else {
/* Store the best primer for output */
if (trace_me) {
fprintf(stderr, "ADD pair i=%d, j=%d\n", the_best_i, the_best_j);
}
if (!pa->pick_internal_oligo || !(sa->intl_overlap_junctions_count > 0)) {
add_pair(&the_best_pair, best_pairs);
} else {
valid_intl = 1;
for (j = 0; j < best_pairs->num_pairs; j++) {
if (intl_oligo_in_pair_overlaps_used_oligo(
best_pairs->pairs[j].intl,
&the_best_pair,
pa->min_internal_three_prime_distance)
) {
valid_intl = 0;
}
}
if (valid_intl) {
add_pair(&the_best_pair, best_pairs);
}
}
/* Mark the pair as already selected */
// delete best_pp;
// (*best_hmap)[the_best_j] = NULL;
if (best_pp != NULL) {
free(best_pp);
best_pp = NULL;
}
it = kh_get(primer_pair_map, best_hmap, the_best_j);
if (it == kh_end(best_hmap)) {
it = kh_put(primer_pair_map, best_hmap, the_best_j, &ret);
}
kh_value(best_hmap, it) = NULL;
/* Update the overlaps flags */
for (i = 0; i < retval->rev.num_elem; i++) {
if (
right_oligo_in_pair_overlaps_used_oligo(
&retval->rev.oligo[i],
&the_best_pair,
pa->min_right_three_prime_distance
)
) {
retval->rev.oligo[i].overlaps = 1;
}
}
for (j = 0; j < retval->fwd.num_elem; j++) {
if (
left_oligo_in_pair_overlaps_used_oligo(
&retval->fwd.oligo[j],
&the_best_pair,
pa->min_left_three_prime_distance
)
) {
retval->fwd.oligo[j].overlaps = 1;
}
}
/* Only exclude oligos if a overlap position is given */
if (
(pa->pick_internal_oligo) &&
(sa->intl_overlap_junctions_count > 0)
) {
for (j = 0; j < retval->intl.num_elem; j++) {
if (intl_oligo_in_pair_overlaps_used_oligo(
&retval->intl.oligo[j],
&the_best_pair,
pa->min_internal_three_prime_distance)
) {
retval->intl.oligo[j].overlaps = 1;
}
}
}
/* If we have enough then stop the while loop */
if (pa->num_return == best_pairs->num_pairs) {
break;
}
}
} /* end of while(continue_trying == 1) */
/* Final cleanup of dynamically allocated storage for this
function. */
free_pair_memory(retval->rev.num_elem, pairs_args);
}
/* ============================================================ */
/* END choose_pair_or_triple */
/* ============================================================ */
/* ============================================================ */
/* BEGIN choose_internal_oligo */
/* Choose best internal oligo for given pair of left and right
primers. */
/* ============================================================ */
static int
choose_internal_oligo(
p3retval* retval,
const primer_rec* left,
const primer_rec* right,
int* nm,
int* more_intl_oligos,
const seq_args_t* sa,
const p3_global_settings* pa,
const dpal_arg_holder* dpal_arg_to_use,
const thal_arg_holder* thal_arg_to_use,
const thal_arg_holder* thal_oligo_arg_to_use
) {
int k;
double min = 1000000.;
int i = -1;
char oligo_seq[MAX_PRIMER_LENGTH + 1];
char revc_oligo_seq[MAX_PRIMER_LENGTH + 1];
primer_rec* h = NULL;
*more_intl_oligos = 0;
for (k=0; k < retval->intl.num_elem; k++) {
h = &retval->intl.oligo[k]; /* h is the record for the oligo currently
under consideration */
if (h->overlaps) {
if (!(h)->must_use) { continue; }
} else {
*more_intl_oligos = 1;
}
if (
(h->start > (left->start + (left->length - 1))) &&
((h->start + (h->length - 1)) < (right->start - right->length + 1)) &&
(h->quality < min) &&
(OK_OR_MUST_USE(h))
) {
if (
(h->self_any == ALIGN_SCORE_UNDEF) &&
(pa->thermodynamic_oligo_alignment == 0)
) {
_pr_substr(
sa->trimmed_seq,
h->start,
h->length,
oligo_seq
);
p3_reverse_complement(
oligo_seq,
revc_oligo_seq
);
oligo_compl(
h,
&pa->o_args,
&retval->intl.expl,
dpal_arg_to_use,
oligo_seq,
revc_oligo_seq
);
if (!OK_OR_MUST_USE(h)) { continue; }
}
if (
(h->self_any == ALIGN_SCORE_UNDEF) &&
(pa->thermodynamic_oligo_alignment == 1)
) {
_pr_substr(
sa->trimmed_seq,
h->start,
h->length,
oligo_seq
);
p3_reverse_complement(
oligo_seq,
revc_oligo_seq
);
oligo_compl_thermod(
h,
&pa->o_args,
&retval->intl.expl,
thal_oligo_arg_to_use,
oligo_seq,
oligo_seq
);
if (!OK_OR_MUST_USE(h)) { continue; }
}
if (
(h->hairpin_th == ALIGN_SCORE_UNDEF) &&
(pa->thermodynamic_oligo_alignment == 1)
) {
_pr_substr(
sa->trimmed_seq,
h->start,
h->length,
oligo_seq
);
oligo_hairpin(
h,
&pa->o_args,
&retval->intl.expl,
thal_oligo_arg_to_use,
oligo_seq
);
if (!OK_OR_MUST_USE(h)) { continue; }
}
if (h->repeat_sim.score == NULL) {
oligo_repeat_library_mispriming(
h,
pa,
sa,
OT_INTL,
&retval->intl.expl,
dpal_arg_to_use,
&retval->glob_err
);
if (!OK_OR_MUST_USE(h)) { continue; }
}
min = h->quality;
i = k;
} /* if ((h->start.... */
} /* for (k=0;..... */
*nm = i;
if (*nm < 0) return 1;
return 0;
}
/* ============================================================ */
/* END choose_internal_oligo */
/* ============================================================ */
/*
Translate the values in the stats struct into an warning string.
Call this function only if the 'stat's contains the _errors_
associated with a given primer i.e. that primer was supplied by the
caller and pick_anyway is set.
*/
void
add_must_use_warnings(
pr_append_str* warning,
const char* text,
const oligo_stats* stats
) {
const char* sep = "/";
pr_append_str s;
s.data = NULL;
s.storage_size = 0;
if (stats->size_min) {
pr_append_w_sep(&s, sep, "Too short");
}
if (stats->size_max) {
pr_append_w_sep(&s, sep, "Too long");
}
if (stats->ns) {
pr_append_w_sep(&s, sep, "Too many Ns");
}
if (stats->target) {
pr_append_w_sep(&s, sep, "Overlaps Target");
}
if (stats->excluded) {
pr_append_w_sep(&s, sep, "Overlaps Excluded Region");
}
if (stats->gc) {
pr_append_w_sep(&s, sep, "Unacceptable GC content");
}
if (stats->gc_clamp) {
pr_append_w_sep(&s, sep, "No GC clamp");
}
if (stats->temp_min) {
pr_append_w_sep(&s, sep, "Tm too low");
}
if (stats->temp_max) {
pr_append_w_sep(&s, sep, "Tm too high");
}
if (stats->bound_min) {
pr_append_w_sep(&s, sep, "Fraction bound too low");
}
if (stats->bound_max) {
pr_append_w_sep(&s, sep, "Fraction bound too high");
}
if (stats->compl_any) {
pr_append_w_sep(&s, sep, "High self complementarity");
}
if (stats->compl_end) {
pr_append_w_sep(&s, sep, "High end self complementarity");
}
if (stats->hairpin_th) {
pr_append_w_sep(&s, sep, "High hairpin stability (thermod. approach)");
}
if (stats->repeat_score) {
pr_append_w_sep(&s, sep, "High similarity to mispriming or mishyb library");
}
if (stats->poly_x) {
pr_append_w_sep(&s, sep, "Long poly-X");
}
if (stats->seq_quality) {
pr_append_w_sep(&s, sep, "Low sequence quality");
}
if (stats->stability) {
pr_append_w_sep(&s, sep, "High 3' stability");
}
if (stats->no_orf) {
pr_append_w_sep(&s, sep, "Would not amplify any ORF");
}
if (stats->not_in_any_left_ok_region) {
pr_append_w_sep(&s, sep, "Not in any ok left region");
}
if (stats->not_in_any_right_ok_region) {
pr_append_w_sep(&s, sep, "Not in any ok right region");
}
/* edited by T. Koressaar for lowercase masking: */
if (stats->gmasked) {
pr_append_w_sep(&s, sep, "Masked with lowercase letter");
}
if (stats->must_match_fail) {
pr_append_w_sep(&s, sep, "Failed must_match requirements");
}
if (s.data) {
pr_append_new_chunk(warning, text);
pr_append(warning, " is unacceptable: ");
pr_append(warning, s.data);
free(s.data);
s.data = NULL;
}
}
/*
Also see the documentation in librimer3.h,
p3_global_settings.min_{left/right_}three_prime_distance.
If min_dist == -1, return 0
If min_dist == 0:
Return 1 if the left or the right
primer is identical to the left or right
primer (respectively) in best_pair.
Otherwise return 0.
If min_dist > 0:
Return 1 if EITHER:
(1) The 3' end of the left primer in pair is
< min_dist from the 3' end of the left primer
in best_pair
OR
(2) The 3' end of the right primer in pair is
< min_dist from the 3' end of the right primer
in best_pair
*/
static int
right_oligo_in_pair_overlaps_used_oligo(
const primer_rec* right,
const primer_pair* best_pair,
int min_dist
) {
int best_pos, pair_pos;
if (min_dist == -1) {
return 0;
}
best_pos = best_pair->right->start - best_pair->right->length + 1;
pair_pos = right->start - right->length + 1;
if (
(abs(best_pos - pair_pos) < min_dist) &&
(min_dist != 0)
) { return 1; }
if (
(best_pair->right->length == right->length) &&
(best_pair->right->start == right->start) &&
(min_dist == 0)
) {
return 1;
}
return 0;
}
static int
left_oligo_in_pair_overlaps_used_oligo(
const primer_rec* left,
const primer_pair* best_pair,
int min_dist
) {
int best_pos, pair_pos;
if (min_dist == -1) {
return 0;
}
best_pos = best_pair->left->start + best_pair->left->length - 1;
pair_pos = left->start + left->length - 1;
if (
(abs(best_pos - pair_pos) < min_dist) &&
(min_dist != 0)
) { return 1; }
if (
(best_pair->left->length == left->length) &&
(best_pair->left->start == left->start) &&
(min_dist == 0)
) {
return 1;
}
return 0;
}
static int
intl_oligo_in_pair_overlaps_used_oligo(
const primer_rec* left,
const primer_pair* best_pair,
int min_dist
) {
int best_pos, pair_pos;
if (min_dist == -1)
return 0;
best_pos = best_pair->intl->start + best_pair->intl->length - 1;
pair_pos = left->start + left->length - 1;
if ((abs(best_pos - pair_pos) < min_dist)
&& (min_dist != 0)) { return 1; }
if (
(best_pair->intl->length == left->length) &&
(best_pair->intl->start == left->start) &&
(min_dist == 0)
) {
return 1;
}
return 0;
}
/* Add 'pair' to 'retpair'; always appends. */
static void
add_pair(
const primer_pair* pair,
pair_array_t* retpair
) {
/* If array is not initialised, initialise it with the size of pairs
to return */
if (0 == retpair->storage_size) {
retpair->storage_size = INITIAL_NUM_RETURN;
// retpair->pairs
// = (primer_pair* )
// pr_safe_malloc(retpair->storage_size * sizeof(*retpair->pairs));
retpair->pairs = (primer_pair*) pr_safe_malloc(
retpair->storage_size * sizeof(primer_pair)
);
} else {
if (retpair->storage_size == retpair->num_pairs) {
/* We need more space, so realloc double the space*/
retpair->storage_size *= 2;
// retpair->pairs
// = (primer_pair* )
// pr_safe_realloc(retpair->pairs,
// retpair->storage_size * sizeof(*retpair->pairs));
retpair->pairs = (primer_pair*) pr_safe_realloc(
retpair->pairs,
retpair->storage_size * sizeof(primer_pair)
);
}
}
/* Copy the pair into the storage place */
retpair->pairs[retpair->num_pairs] = *pair;
retpair->num_pairs++;
}
/*
* Make lists of acceptable left and right primers. After return, the
* lists are stored in retval->fwd.oligo and retval->rev.oligo and the
* coresponding list sizes are stored in retval->fwd.num_elem and
* retval->rev.num_elem. Return 1 if one of lists is empty or if
* leftmost left primer and rightmost right primer do not provide
* sufficient product size.
*/
static int
make_detection_primer_lists(
p3retval* retval,
const p3_global_settings* pa,
const seq_args_t* sa,
const dpal_arg_holder* dpal_arg_to_use,
const thal_arg_holder* thal_arg_to_use
) {
int left, right;
int length, start;
int i,n,/*k,*/ pr_min;
int tar_l, tar_r, f_b, r_b;
/* To store the statistics for pairs */
pair_stats* pair_expl = &retval->best_pairs.expl;
/* Var to save the very left and very right primer */
left = right = 0;
/* Set pr_min to the very smallest
allowable product size. */
pr_min = INT_MAX;
for (i=0; i < pa->num_intervals; i++) {
if (pa->pr_min[i] < pr_min) {
pr_min = pa->pr_min[i];
}
}
/* Get the length of the sequence */
PR_ASSERT(INT_MAX > (n = (int) strlen(sa->trimmed_seq)));
tar_r = 0; /* Target start position */
tar_l = n; /* Target length */
/* Iterate over target array */
for (i=0; i < sa->tar2.count; i++) {
/* Select the rightmost target start */
if (sa->tar2.pairs[i][0] > tar_r) {
tar_r = sa->tar2.pairs[i][0];
}
/* Select the rightmost target end */
if ((sa->tar2.pairs[i][0] + sa->tar2.pairs[i][1] - 1) < tar_l) {
tar_l = sa->tar2.pairs[i][0] + sa->tar2.pairs[i][1] - 1;
}
}
if (_PR_DEFAULT_POSITION_PENALTIES(pa)) {
if (0 == tar_r) { tar_r = n;}
if (tar_l == n) {tar_l = 0;}
} else {
tar_r = n;
tar_l = 0;
}
/* We use some global information to restrict the region
of the input sequence in which we generate candidate
oligos. */
if (
(retval->output_type == primer_list) &&
(pa->pick_left_primer == 1)
) {
f_b = n - 1;
} else if (
((tar_r - 1) < (n - pr_min + pa->p_args.max_size - 1)) &&
!(
pa->pick_anyway &&
sa->left_input
)
) {
f_b=tar_r - 1;
} else {
f_b = n - pr_min + pa->p_args.max_size - 1;
}
if (pa->pick_left_primer) {
/* We will need a left primer. */
left=n; right=0;
length = f_b - pa->p_args.min_size + 1;
start = pa->p_args.min_size - 1;
/* Use the primer provided */
if (sa->left_input) {
add_one_primer(
sa->left_input,
&left,
&retval->fwd,
pa,
sa,
dpal_arg_to_use,
thal_arg_to_use,
retval
);
}
/* Pick primers at one position */
else if (
(sa->force_left_start > -1) ||
(sa->force_left_end > -1)
) {
pick_primers_by_position(
sa->force_left_start,
sa->force_left_end,
&left,
&retval->fwd,
pa,
sa,
dpal_arg_to_use,
thal_arg_to_use,
retval
);
}
/* Or pick all good in the given range */
else {
pick_primer_range(
start,
length,
&left,
&retval->fwd,
pa,
sa,
dpal_arg_to_use,
thal_arg_to_use,
retval
);
}
} /* if (pa->pick_left_primer) */
if (
(retval->output_type == primer_list) &&
(pa->pick_right_primer == 1)
) {
r_b = 0;
} else if (
((tar_l + 1) > (pr_min - pa->p_args.max_size)) &&
!(
pa->pick_anyway &&
sa->right_input
)
) {
r_b = tar_l+1;
} else {
r_b = pr_min - pa->p_args.max_size;
}
if ( pa->pick_right_primer ) {
/* We will need a right primer */
length = n-pa->p_args.min_size - r_b + 1;
start = r_b;
/* Use the primer provided */
if (sa->right_input) {
add_one_primer(
sa->right_input,
&right,
&retval->rev,
pa,
sa,
dpal_arg_to_use,
thal_arg_to_use,
retval
);
/* pick_right_primers(start, length, &right, &retval->rev,
pa, sa, dpal_arg_to_use, retval);*/
}
/* Pick primers at one position */
else if (
(sa->force_right_start > -1) ||
(sa->force_right_end > -1)
) {
pick_primers_by_position(
sa->force_right_start,
sa->force_right_end,
&right,
&retval->rev,
pa,
sa,
dpal_arg_to_use,
thal_arg_to_use,
retval
);
}
/* Or pick all good in the given range */
else {
pick_primer_range(
start,
length,
&right,
&retval->rev,
pa,
sa,
dpal_arg_to_use,
thal_arg_to_use,
retval
);
}
}
/*
* Return 1 if either the left primer list or the right primer
* list is empty or if leftmost left primer and
* rightmost right primer do not provide sufficient product size.
*/
if (
(
pa->pick_left_primer &&
(0 == retval->fwd.num_elem)
) ||
(
(pa->pick_right_primer) &&
(0 == retval->rev.num_elem)
)
) {
return 1;
} else if (
!(
(sa->right_input) && (sa->left_input)
) &&
pa->pick_left_primer &&
pa->pick_right_primer &&
((right - left) < (pr_min - 1))
) {
pair_expl->product = 1;
pair_expl->considered = 1;
return 1;
} else { return 0; }
} /* make_detection_primer_lists */
/*
* Make complete list of acceptable internal oligos in retval->intl.oligo.
* and place the number of valid elements in mid in retval->intl.num_elem. Return 1 if
* there are no acceptable internal oligos; otherwise return 0.
*/
static int
make_internal_oligo_list(
p3retval* retval,
const p3_global_settings* pa,
const seq_args_t* sa,
const dpal_arg_holder* dpal_arg_to_use,
const thal_arg_holder* thal_arg_to_use
) {
int ret;
int left = 0;
/* Use the primer provided */
if (
(sa->internal_input) ||
(pa->primer_task == check_primers)
){
ret = add_one_primer(
sa->internal_input,
&left,
&retval->intl,
pa,
sa,
dpal_arg_to_use,
thal_arg_to_use,
retval
);
}
else {
/* Pick all good in the given range */
/* Use the settings to select a proper range */
int length = (int) strlen(sa->trimmed_seq) - pa->o_args.min_size;
int start = pa->o_args.min_size - 1;
int left = 0;
ret = pick_primer_range(
start,
length,
&left,
&retval->intl,
pa,
sa,
dpal_arg_to_use,
thal_arg_to_use,
retval
);
}
return ret;
} /* make_internal_oligo_list */
/*
* Make lists of acceptable left and right primers. After return, the
* lists are stored in retval->fwd.oligo and retval->rev.oligo and the
* coresponding list sizes are stored in retval->fwd.num_elem and
* retval->rev.num_elem. Return 1 if one of lists is empty or if
* leftmost left primer and rightmost right primer do not provide
* sufficient product size.
*/
static int
make_complete_primer_lists(
p3retval* retval,
const p3_global_settings* pa,
const seq_args_t* sa,
const dpal_arg_holder* dpal_arg_to_use,
const thal_arg_holder* thal_arg_to_use,
const thal_arg_holder* thal_oligo_arg_to_use
) {
int extreme;
int length, start;
int n;
/* Get the length of the sequence */
PR_ASSERT(INT_MAX > ( n = (int) strlen(sa->trimmed_seq)));
if (pa->pick_left_primer) {
/* We will need a left primer. */
extreme = 0;
length = n - pa->p_args.min_size;
start = pa->p_args.min_size - 1;
/* Pick all good in the given range */
pick_primer_range(
start,
length,
&extreme,
&retval->fwd,
pa,
sa,
dpal_arg_to_use,
thal_arg_to_use,
retval
);
} /* if (pa->pick_left_primer) */
if ( pa->pick_right_primer ) {
/* We will need a right primer */
extreme = n;
length = n - pa->p_args.min_size + 1;
start = 0;
/* Pick all good in the given range */
pick_primer_range(
start,
length,
&extreme,
&retval->rev,
pa,
sa,
dpal_arg_to_use,
thal_arg_to_use,
retval
);
}
if ( pa->pick_internal_oligo ) {
/* We will need a internal oligo */
length = n - pa->o_args.min_size;
start = pa->o_args.min_size - 1;
extreme = 0;
/* Pick all good in the given range */
pick_primer_range(
start,
length,
&extreme,
&retval->intl,
pa,
sa,
dpal_arg_to_use,
thal_oligo_arg_to_use,
retval
);
}
return 0;
} /* make_complete_primer_lists */
/*
* Add caller-specified primers to retval->fwd, retval->rev, and/or
* retval->intl. The primers do not have to be "legal". It is possible
* to add more than one primer to retval->fwd, etc, if the input
* primer is found in multiple locations in the template. Similar to
* make_complete_primer_lists.
*/
static int
add_primers_to_check(
p3retval* retval,
const p3_global_settings* pa,
const seq_args_t* sa,
const dpal_arg_holder* dpal_arg_to_use,
const thal_arg_holder* thal_arg_to_use,
const thal_arg_holder* thal_oligo_arg_to_use
) {
/* Required when calling `add_one_primer` but not used in the current function. */
int extreme = 0;
if (sa->left_input) {
add_one_primer(
sa->left_input,
&extreme,
&retval->fwd,
pa,
sa,
dpal_arg_to_use,
thal_arg_to_use,
retval
);
}
if (sa->right_input) {
add_one_primer(
sa->right_input,
&extreme,
&retval->rev,
pa,
sa,
dpal_arg_to_use,
thal_arg_to_use,
retval
);
}
if (sa->internal_input) {
add_one_primer(
sa->internal_input,
&extreme,
&retval->intl,
pa,
sa,
dpal_arg_to_use,
thal_oligo_arg_to_use,
retval
);
}
return 0;
} /* add_primers_to_check */
/*
* Make lists of acceptable left and right primers. After return, the
* lists are stored in retval->fwd.oligo and retval->rev.oligo and the
* coresponding list sizes are stored in retval->fwd.num_elem and
* retval->rev.num_elem. Return 1 if one of lists is empty or if
* leftmost left primer and rightmost right primer do not provide
* sufficient product size.
*/
static int
pick_sequencing_primer_list(
p3retval* retval,
const p3_global_settings* pa,
const seq_args_t* sa,
const dpal_arg_holder* dpal_arg_to_use,
const thal_arg_holder* thal_arg_to_use
) {
int length, start;
int n, rest_accuracy;
int primer_nr; /* number of primers we need to pick */
int tar_n; /* counter for the targets */
int step_nr; /* counter to step through the targets */
int sequenced_len; /* bp sequenced in good quality */
int extra_seq; /* bp sequenced additionally on both sides */
/* best location for the 3' end of the fwd primer: */
int pr_position_f;
/* best location for the 3' end of the rev primer: */
int pr_position_r;
/* Get the length of the sequence */
PR_ASSERT(INT_MAX > ( n = (int) strlen(sa->trimmed_seq)));
/* For each target needed loop*/
for (tar_n=0; tar_n < sa->tar2.count; tar_n++) {
/* Calculate the amount of primers needed */
primer_nr = 1;
if ((pa->pick_left_primer) && (pa->pick_right_primer)) {
sequenced_len = pa->sequencing.interval;
while(sequenced_len < sa->tar2.pairs[tar_n][1]) {
primer_nr++;
sequenced_len = pa->sequencing.spacing * (primer_nr - 1)
+ pa->sequencing.interval;
}
} else {
sequenced_len = pa->sequencing.spacing;
while(sequenced_len < sa->tar2.pairs[tar_n][1]) {
primer_nr++;
sequenced_len = pa->sequencing.spacing * primer_nr;
}
}
/* Calculate the overlap on the sides */
extra_seq = (sequenced_len - sa->tar2.pairs[tar_n][1]) / 2;
/* Pick primers for each position */
for ( step_nr = 0 ; step_nr < primer_nr ; step_nr++ ) {
pr_position_f = (
sa->tar2.pairs[tar_n][0] - extra_seq +
( pa->sequencing.spacing * step_nr ) -
pa->sequencing.lead
);
if ((pa->pick_left_primer) && (pa->pick_right_primer)) {
pr_position_r = (
sa->tar2.pairs[tar_n][0] - extra_seq +
( pa->sequencing.spacing * step_nr ) +
pa->sequencing.interval +
pa->sequencing.lead
);
} else {
pr_position_r = sa->tar2.pairs[tar_n][0] - extra_seq
+ ( pa->sequencing.spacing * (step_nr+1))
+ pa->sequencing.lead;
}
/* Check if calculated positions make sense */
/* position_f cannot be outside included region */
if (pr_position_f < (pa->p_args.min_size -1)) {
pr_position_f = pa->p_args.min_size - 1;
}
if (pr_position_f > (n - pa->p_args.min_size - 1)) {
pr_position_f = n - pa->p_args.min_size - 1;
/* Actually this should never happen */
pr_append_new_chunk(
&retval->warnings,
"Calculation error in forward "
"sequencing position calculation"
);
}
/* position_r cannot be outside included region */
if (pr_position_r < (pa->p_args.min_size - 1)) {
pr_position_r = pa->p_args.min_size - 1;
/* Actually this should never happen */
pr_append_new_chunk(
&retval->warnings,
"Calculation error in reverse "
"sequencing position calculation"
);
}
if (pr_position_r > (n - pa->p_args.min_size - 1)) {
pr_position_r = n - pa->p_args.min_size - 1;
}
/* Now all pr_positions are within the sequence */
if (pa->pick_left_primer) {
/* Set the start and length for the regions */
start = pr_position_f - pa->sequencing.accuracy;
if (start < 0) {
rest_accuracy = pr_position_f + 1;
start = 0;
} else {
rest_accuracy = pa->sequencing.accuracy;
}
length = rest_accuracy + pa->sequencing.accuracy ;
if ((start + length) > n) {
length = n - start;
}
/* Pick all good in the given range */
retval->fwd.expl.sequencing_location++;
pick_only_best_primer(
start,
length,
&retval->fwd,
pa,
sa,
dpal_arg_to_use,
thal_arg_to_use,
retval
);
}
if (pa->pick_right_primer) {
start = pr_position_r - pa->sequencing.accuracy;
if (start < 0) {
rest_accuracy = pr_position_r + 1;
start = 0;
} else {
rest_accuracy = pa->sequencing.accuracy;
}
length = rest_accuracy + pa->sequencing.accuracy ;
if ((start + length) > n) {
length = n - start;
}
/* Pick all good in the given range */
retval->rev.expl.sequencing_location++;
pick_only_best_primer(
start,
length,
&retval->rev,
pa,
sa,
dpal_arg_to_use,
thal_arg_to_use,
retval
);
}
}
} /* End of Target Loop */
retval->fwd.expl.ok = retval->fwd.num_elem;
retval->rev.expl.ok = retval->rev.num_elem;
/* Print an error if not all primers will be printed */
if (
(retval->fwd.num_elem > pa->num_return) ||
(retval->rev.num_elem > pa->num_return)
) {
pr_append_new_chunk( &retval->warnings,
"Increase PRIMER_NUM_RETURN to obtain all sequencing primers");
}
return 0;
} /* pick_sequencing_primer_list */
static void
add_oligo_to_oligo_array(oligo_array* oarray, primer_rec orec) {
/* Allocate some space for primers if needed */
if (NULL == oarray->oligo) {
oarray->storage_size = INITIAL_LIST_LEN;
oarray->oligo = (primer_rec* ) pr_safe_malloc(
sizeof(primer_rec) * oarray->storage_size
);
}
/* If there is no space on the array, allocate new space */
if ((oarray->num_elem + 1) >= oarray->storage_size) { /* TO DO, is +1 really needed? */
oarray->storage_size += (oarray->storage_size >> 1);
oarray->oligo = (primer_rec* ) pr_safe_realloc(
oarray->oligo,
oarray->storage_size * sizeof(primer_rec)
);
}
oarray->oligo[oarray->num_elem] = orec;
oarray->num_elem++;
}
/* pick_primer_range picks all primers which have their 3' end in the range
* from start to start+length and store only the best *oligo */
static int
pick_only_best_primer(
const int start,
const int length,
oligo_array* oligo,
const p3_global_settings* pa,
const seq_args_t* sa,
const dpal_arg_holder* dpal_arg_to_use,
const thal_arg_holder* thal_arg_to_use,
p3retval* retval
) {
/* Variables for the loop */
int i, j, primer_size_small, primer_size_large;
int n, found_primer;
char number[20];
char*p_number = &number[0];
int temp_value;
/* Array to store one primer sequences in */
char oligo_seq[MAX_PRIMER_LENGTH+1];
/* Struct to store the primer parameters in */
primer_rec h;
primer_rec best;
memset(
&h,
0,
sizeof(primer_rec)
);
memset(
&best,
0,
sizeof(primer_rec)
);
best.quality = 1000.00;
found_primer = 0;
/* Set n to the length of included region */
PR_ASSERT(INT_MAX > (n=(int)strlen(sa->trimmed_seq)));
/* Conditions for primer length */
if (oligo->type == OT_INTL) {
primer_size_small = pa->o_args.min_size;
primer_size_large = pa->o_args.max_size;
}
else {
primer_size_small = pa->p_args.min_size;
primer_size_large = pa->p_args.max_size;
}
/* Loop over locations in the sequence */
for(i = start + length - 1; i >= start; i--) {
oligo_seq[0] = '\0';
/* Loop over possible primer lengths, from min to max */
for (j = primer_size_small; j <= primer_size_large; j++) {
/* Set the length of the primer */
h.length = j;
/* Set repeat_sim to NULL as indicator that the repeat_sim
struct is not initialized. */
h.repeat_sim.score = NULL;
/* Figure out positions for left primers and internal oligos */
if (oligo->type != OT_RIGHT) {
/* Break if the primer is bigger than the sequence left */
if ( (i - j) < -1) continue;
/* Set the start of the primer */
h.start = i - j + 1;
/* Put the real primer sequence in oligo_seq */
_pr_substr(
sa->trimmed_seq,
h.start,
j,
oligo_seq
);
} else {
/* Figure out positions for reverse primers */
/* Break if the primer is bigger than the sequence left*/
if (i+j > n) continue;
/* Set the start of the primer */
h.start = i+j-1;
/* Put the real primer sequence in s */
_pr_substr(
sa->trimmed_seq,
i,
j,
oligo_seq
);
}
/* Do not force primer3 to use this oligo */
h.must_use = 0;
h.overlaps = 0;
/* Add it to the considered statistics */
oligo->expl.considered++;
/* Calculate all the primer parameters */
calc_and_check_oligo_features(
pa,
&h,
oligo->type,
dpal_arg_to_use,
thal_arg_to_use,
sa,
&oligo->expl,
retval,
oligo_seq
);
/* If primer has to be used or is OK */
if (OK_OR_MUST_USE(&h)) {
/* Calculate the penalty */
h.quality = p_obj_fn(pa, &h, oligo->type);
/* Save the primer in the array */
if (h.quality < best.quality) {
/* Free memory used by previous best primer. */
free_primer_repeat_sim_score(&best);
best = h;
found_primer = 1;
} else {
/* Free memory used by this primer. */
free_primer_repeat_sim_score(&h);
}
} else {
/* Free memory used by this primer. */
free_primer_repeat_sim_score(&h);
if (any_5_prime_ol_extension_has_problem(&h)) {
/* Break from the inner for loop, because there is no
legal longer oligo with the same 3' sequence. */
break;
}
}
} /* j: Loop over possible primer length from min to max */
} /* i: Loop over the sequence */
if (found_primer == 1) {
/* Add the best to the array */
add_oligo_to_oligo_array(oligo, best);
/* Update statistics with how many primers are good */
oligo->expl.ok = oligo->expl.ok + 1;
} else {
if (oligo->type == OT_RIGHT) {
pr_append_new_chunk(
&retval->warnings,
"No right primer found in range "
);
} else {
pr_append_new_chunk(
&retval->warnings,
"No left primer found in range "
);
}
temp_value = start + pa->first_base_index;
sprintf(p_number, "%d", temp_value);
pr_append(
&retval->warnings,
p_number
);
pr_append(
&retval->warnings,
" - "
);
temp_value = (start + length + pa->first_base_index);
sprintf(p_number, "%d", temp_value);
pr_append(
&retval->warnings,
p_number
);
}
if (oligo->num_elem == 0) { return 1; }
else { return 0; }
} /* pick_only_best_primer */
/* pick_primer_range picks all legal primers in the range from start
to start+length and stores them in *oligo */
static int
pick_primer_range(
const int start,
const int length,
int* extreme,
oligo_array* oligo,
const p3_global_settings* pa,
const seq_args_t* sa,
const dpal_arg_holder* dpal_arg_to_use,
const thal_arg_holder* thal_arg_to_use,
p3retval* retval
) {
/* Variables for the loop */
int i, j;
int primer_size_small, primer_size_large;
int pr_min, n;
/* Array to store one primer sequences in */
char oligo_seq[MAX_PRIMER_LENGTH+1];
/* Struct to store the primer parameters in */
primer_rec h;
memset(&h, 0, sizeof(primer_rec));
/* Set pr_min to the very smallest
allowable product size. */
pr_min = INT_MAX;
for (i=0; i < pa->num_intervals; i++) {
if (pa->pr_min[i] < pr_min) {
pr_min = pa->pr_min[i];
}
}
/* Set n to the length of included region */
PR_ASSERT(INT_MAX > (n = (int) strlen(sa->trimmed_seq)));
if (oligo->type == OT_INTL) {
primer_size_small=pa->o_args.min_size;
primer_size_large=pa->o_args.max_size;
} else {
primer_size_small=pa->p_args.min_size;
primer_size_large=pa->p_args.max_size;
}
/* Loop over locations in the sequence */
for(i = start + length; i >= start; i--) {
oligo_seq[0] = '\0';
/* Loop over possible primer lengths, from min to max */
for (j = primer_size_small; j <= primer_size_large; j++) {
/* Set the length of the primer */
h.length = j;
/* Figure out positions for left primers and internal oligos */
if (oligo->type != OT_RIGHT) {
/* Check if the product is of sufficient size */
if (
(i-j > n-pr_min-1) &&
(retval->output_type == primer_pairs) &&
(oligo->type == OT_LEFT)
) { continue; }
/* Break if the primer is bigger than the sequence left */
if ( (i - j) < -1) break;
/* Set the start of the primer */
h.start = i - j + 1;
/* Put the real primer sequence in oligo_seq */
_pr_substr(
sa->trimmed_seq,
h.start,
j,
oligo_seq
);
} else {
/* Figure out positions for reverse primers */
/* Check if the product is of sufficient size */
if (
(i+j < pr_min) &&
(retval->output_type == primer_pairs)
) {
continue;
}
/* Break if the primer is bigger than the sequence left*/
if ( (i + j) > n) { break; }
/* Set the start of the primer */
h.start = i + j - 1;
/* Put the real primer sequence in s */
_pr_substr(sa->trimmed_seq, i, j, oligo_seq);
}
/* Do not force primer3 to use this oligo */
h.must_use = 0;
h.overlaps = 0;
/* Add it to the considered statistics */
oligo->expl.considered++;
/* Calculate all the primer parameters */
calc_and_check_oligo_features(
pa,
&h,
oligo->type,
dpal_arg_to_use,
thal_arg_to_use,
sa,
&oligo->expl,
retval,
oligo_seq
);
/* If primer has to be used or is OK */
if (OK_OR_MUST_USE(&h)) {
/* Calculate the penalty */
h.quality = p_obj_fn(pa, &h, oligo->type);
/* Save the primer in the array */
add_oligo_to_oligo_array(oligo, h);
/* Update the most extreme primer variable */
if (( h.start < *extreme) && (oligo->type != OT_RIGHT))
*extreme = h.start;
/* Update the most extreme primer variable */
if ((h.start > *extreme) && (oligo->type == OT_RIGHT))
*extreme = h.start;
} else {
/* Free memory used by this primer. */
free_primer_repeat_sim_score(&h);
if (any_5_prime_ol_extension_has_problem(&h)) {
/* Break from the inner for loop, because there is no
legal longer oligo with the same 3' sequence. */
break;
}
}
} /* j: Loop over possible primer length from min to max */
} /* i: Loop over the sequence */
/* Update statistics with how many primers are good */
oligo->expl.ok = oligo->num_elem;
if (oligo->num_elem == 0) { return 1; }
else { return 0; }
} /* pick_primer_range */
/* add_one_primer finds one primer in the trimmed sequence and stores
* it in *oligo The main difference to the general fuction is that it
* calculates its length and it will add a primer of any length to the
* list */
static int
add_one_primer(
const char* primer,
int* extreme,
oligo_array* oligo,
const p3_global_settings* pa,
const seq_args_t* sa,
const dpal_arg_holder* dpal_arg_to_use,
const thal_arg_holder* thal_arg_to_use,
p3retval* retval
) {
/* Variables for the loop */
int i, j;
int n;
/* Array to store one primer sequences in */
char oligo_seq[MAX_PRIMER_LENGTH+1] , test_oligo[MAX_PRIMER_LENGTH+1];
/* Struct to store the primer parameters in */
primer_rec h;
memset(&h, 0, sizeof(primer_rec));
/* Copy *primer into test_oligo */
test_oligo[0] = '\0';
if (oligo->type != OT_RIGHT) {
strncat(test_oligo, primer, MAX_PRIMER_LENGTH);
} else {
p3_reverse_complement(primer, test_oligo);
}
PR_ASSERT(INT_MAX > (n=(int)strlen(sa->trimmed_seq)));
/* This time we already know the size of the primer */
j = (int) strlen(primer);
/* Loop over the whole sequence */
for(i = (int) strlen(sa->trimmed_seq); i >= 0; i--) {
oligo_seq[0] = '\0';
/* Set the length of the primer */
h.length = j;
/* Figure out positions for forward primers */
if (oligo->type != OT_RIGHT) {
/* Break if the primer is bigger than the sequence left*/
if ( (i - j) < -1) continue;
/* Set the start of the primer */
h.start = i - j +1;
/* Put the real primer sequence in s */
_pr_substr(sa->trimmed_seq, h.start, j, oligo_seq);
}
/* Figure out positions for reverse primers */
else {
/* Break if the primer is bigger than the sequence left*/
if ((i + j) > n) continue;
/* Set the start of the primer */
h.start = (i + j) - 1;
/* Put the real primer sequence in s */
_pr_substr(sa->trimmed_seq, i, j, oligo_seq);
}
/* Compare the primer with the sequence */
if (strcmp_nocase(test_oligo, oligo_seq)) {
continue;
}
/* Force primer3 to use this oligo */
h.must_use = (1 && pa->pick_anyway);
h.overlaps = 0;
/* Add it to the considered statistics */
oligo->expl.considered++;
/* Calculate all the primer parameters */
calc_and_check_oligo_features(
pa,
&h,
oligo->type,
dpal_arg_to_use,
thal_arg_to_use,
sa,
&oligo->expl,
retval,
oligo_seq
);
/* If primer has to be used or is OK */
if (OK_OR_MUST_USE(&h)) {
/* Calculate the penalty */
h.quality = p_obj_fn(pa, &h, oligo->type);
/* Save the primer in the array */
add_oligo_to_oligo_array(oligo, h);
/* Update the most extreme primer variable */
if ((h.start < *extreme) && (oligo->type != OT_RIGHT)) {
*extreme = h.start;
}
/* Update the most extreme primer variable */
if ((h.start > *extreme) && (oligo->type == OT_RIGHT)) {
*extreme = h.start;
}
} else {
/* Free memory used by this primer. */
free_primer_repeat_sim_score(&h);
}
} /* i: Loop over the sequence */
/* Update array with how many primers are good */
/* Update statistics with how many primers are good */
oligo->expl.ok = oligo->num_elem;
if (oligo->num_elem == 0) { return 1; }
else {
if (oligo->num_elem > 1) {
pr_append_new_chunk(&retval->warnings,
"More than one position in template for input oligo ");
pr_append(&retval->warnings, primer);
}
return 0; /* Success */
}
}
/* add_one_primer finds one primer in the trimmed sequence and stores
* it in *oligo The main difference to the general fuction is that it
* calculates its length and it will add a primer of any length to the
* list */
static int
add_one_primer_by_position(
int start,
int length,
int* extreme,
oligo_array* oligo,
const p3_global_settings* pa,
const seq_args_t* sa,
const dpal_arg_holder* dpal_arg_to_use,
const thal_arg_holder* thal_arg_to_use,
p3retval* retval
) {
/* Variables for the loop */
int i;
int n, found_primer;
/* Array to store one primer sequences in */
char oligo_seq[MAX_PRIMER_LENGTH+1];
/* Struct to store the primer parameters in */
primer_rec h;
memset(&h, 0, sizeof(primer_rec));
/* Retun 1 for no primer found */
found_primer = 1;
PR_ASSERT(INT_MAX > (n = (int) strlen(sa->trimmed_seq)));
/* Just to be sure */
if (start < 0) {
return 1;
}
if (start >= n) {
return 1;
}
if (oligo->type != OT_RIGHT) {
if ((start + length) > n) {
return 1;
}
} else {
if ((start - length + 1) < 0) {
return 1;
}
}
oligo_seq[0] = '\0';
/* Set the length of the primer */
h.length = length;
/* Figure out positions for forward primers */
if (oligo->type != OT_RIGHT) {
/* Set the start of the primer */
h.start = start;
/* Put the real primer sequence in s */
_pr_substr(
sa->trimmed_seq,
h.start,
length,
oligo_seq
);
}
/* Figure out positions for reverse primers */
else {
i = start - length + 1;
/* Set the start of the primer */
h.start = start;
/* Put the real primer sequence in s */
_pr_substr(
sa->trimmed_seq,
i,
length,
oligo_seq
);
}
/* Force primer3 to use this oligo */
h.must_use = (1 && pa->pick_anyway);
h.overlaps = 0;
/* Add it to the considered statistics */
oligo->expl.considered++;
/* Calculate all the primer parameters */
calc_and_check_oligo_features(
pa,
&h,
oligo->type,
dpal_arg_to_use,
thal_arg_to_use,
sa,
&oligo->expl,
retval,
oligo_seq
);
/* If primer has to be used or is OK */
if (OK_OR_MUST_USE(&h)) {
/* Calculate the penalty */
h.quality = p_obj_fn(pa, &h, oligo->type);
/* Save the primer in the array */
add_oligo_to_oligo_array(oligo, h);
found_primer = 0;
/* Update the most extreme primer variable */
if (( h.start < *extreme) &&
(oligo->type != OT_RIGHT)) {
*extreme = h.start;
}
/* Update the most extreme primer variable */
if (( h.start > *extreme) &&
(oligo->type == OT_RIGHT)) {
*extreme = h.start;
}
/* Update the number of primers */
} else {
/* Free memory used by this primer. */
free_primer_repeat_sim_score(&h);
}
/* Update array with how many primers are good */
/* Update statistics with how many primers are good */
oligo->expl.ok = oligo->num_elem;
/* return 0 for success */
return found_primer;
}
static int
pick_primers_by_position(
const int start,
const int end,
int* extreme,
oligo_array* oligo,
const p3_global_settings* pa,
const seq_args_t* sa,
const dpal_arg_holder* dpal_arg_to_use,
const thal_arg_holder* thal_arg_to_use,
p3retval* retval
) {
int found_primer, length, j, ret, new_start;
found_primer = 1;
ret = 1;
if (start > -1 && end > -1) {
if (oligo->type != OT_RIGHT) {
length = end - start + 1;
} else {
length = start - end + 1;
}
found_primer = add_one_primer_by_position(
start,
length,
extreme,
oligo,
pa,
sa,
dpal_arg_to_use,
thal_arg_to_use,
retval
);
return found_primer;
} else if (start > -1) {
/* Loop over possible primer lengths, from min to max */
ret = 0;
for (j = pa->p_args.min_size; j <= pa->p_args.max_size; j++) {
ret += add_one_primer_by_position(
start,
j,
extreme,
oligo,
pa,
sa,
dpal_arg_to_use,
thal_arg_to_use,
retval
);
if (ret == 0) {
found_primer = 0;
}
}
return found_primer;
} else if (end > -1) {
/* Loop over possible primer lengths, from min to max */
ret = 0;
for (j = pa->p_args.min_size; j <= pa->p_args.max_size; j++) {
if (oligo->type != OT_RIGHT) {
new_start = end - j + 1;
} else {
new_start = end + j - 1;
}
ret += add_one_primer_by_position(
new_start,
j,
extreme,
oligo,
pa,
sa,
dpal_arg_to_use,
thal_arg_to_use,
retval
);
if (ret == 0) {
found_primer = 0;
}
}
return found_primer;
} else {
/* Actually this should never happen */
pr_append_new_chunk(&retval->warnings,
"Calculation error in forced primer position calculation");
return 1;
}
}
/*
* Compute various characteristics of the oligo, and determine
* if it is acceptable.
*/
#define OUTSIDE_START_WT 30.0
#define INSIDE_START_WT 20.0
#define INSIDE_STOP_WT 100.0
#define OUTSIDE_STOP_WT 0.5
static void
calc_and_check_oligo_features(
const p3_global_settings* pa,
primer_rec* h,
oligo_type otype,
const dpal_arg_holder* dpal_arg_to_use,
const thal_arg_holder* thal_arg_to_use,
const seq_args_t* sa,
oligo_stats* stats,
p3retval* retval,
/* This is 5'->3' on the template sequence: */
const char* input_oligo_seq
) {
int i, j, k, for_i, gc_count, overhang_len;
tm_ret tm_calc; /* structure with Tm and bound (primer fraction) */
int three_prime_pos; /* position of 3' base of oligo */
oligo_type l = otype;
int must_use = h->must_use;
int three_conditions = (
must_use || pa->file_flag || retval->output_type == primer_list
);
const thal_args* thal_args_for_template_mispriming = (
use_end_for_th_template_mispriming
? thal_arg_to_use->end1
: thal_arg_to_use->any
);
char s1_rev[MAX_PRIMER_LENGTH+1];
const char* oligo_seq;
const char* revc_oligo_seq;
char oligo_seq_overhang[THAL_MAX_ALIGN+1];
char revc_oligo_seq_overhang[THAL_MAX_ALIGN+1];
const char* p_oligo_seq_overhang;
const char* p_revc_oligo_seq_overhang;
const args_for_one_oligo_or_primer* po_args;
#if !defined(OS_WIN)
oligo_pair op = {0};
#endif
/* Initialize slots in h */
initialize_op(h);
h->overlaps = 0;
/* Set repeat_sim to NULL as indicator that the repeat_sim
struct is not initialized. */
h->repeat_sim.score = NULL;
/* Set all struct to NULL, will be calculated later */
h->self_any_struct = NULL;
h->self_end_struct = NULL;
h->hairpin_struct = NULL;
h->template_mispriming_struct = NULL;
h->template_mispriming_r_struct = NULL;
h->gc_content = h->num_ns = 0;
h->overlaps_overlap_position = 0;
h->template_mispriming = h->template_mispriming_r = ALIGN_SCORE_UNDEF;
h->template_mispriming_ok = 0;
PR_ASSERT(OT_LEFT == l || OT_RIGHT == l || OT_INTL == l);
p3_reverse_complement(
input_oligo_seq,
s1_rev
);
if (OT_RIGHT == l) {
oligo_seq = s1_rev;
revc_oligo_seq = input_oligo_seq;
} else {
oligo_seq = input_oligo_seq;
revc_oligo_seq = s1_rev;
}
if (OT_INTL == l) {
po_args = &pa->o_args;
} else {
po_args = &pa->p_args;
}
/* Set j and k, and sanity check */
if ((OT_LEFT == otype) || (OT_INTL == otype)) {
j = h->start;
three_prime_pos = k = j+h->length-1;
} else {
three_prime_pos = j = h->start-h->length+1;
k = h->start;
}
PR_ASSERT(k >= 0);
PR_ASSERT(k < TRIMMED_SEQ_LEN(sa));
if (
(otype == OT_LEFT) &&
!PR_START_CODON_POS_IS_NULL(sa) &&
/* Make sure the primer would amplify at least part of
the ORF. */
(
(0 != (h->start - sa->start_codon_pos) % 3) ||
(h->start <= retval->upstream_stop_codon) ||
((retval->stop_codon_pos != -1) &&
(h->start >= retval->stop_codon_pos))
)
) {
stats->no_orf++;
op_set_does_not_amplify_orf(h);
if (!pa->pick_anyway) { return; }
}
/* edited by T. Koressaar and M. Lepamets for lowercase masking */
if (pa->lowercase_masking == 1) {
char*sequence_check = sa->trimmed_orig_seq;
if (pa->mask_template == 1) {
if (l == OT_LEFT) {
sequence_check = sa->trimmed_masked_seq;
} else if (l == OT_RIGHT) {
sequence_check = sa->trimmed_masked_seq_r;
}
}
if (is_lowercase_masked(
three_prime_pos,
sequence_check,
h,
stats)
) {
if (!must_use) { return; }
}
} else if (
(pa->lowercase_masking == 0) &&
(pa->mask_template == 1)
) {
pr_append_new_chunk(
&retval->warnings,
"Use PRIMER_LOWERCASE_MASKING=1 when using PRIMER_MASK_TEMPLATE=1."
);
return;
}
/* end T. Koressar's changes */
/* edited by A. Untergasser for forcing sequence use */
if (
(po_args->must_match_five_prime != NULL) ||
(po_args->must_match_three_prime != NULL)
) {
if (primer_must_match(
pa,
h,
stats,
oligo_seq,
po_args->must_match_three_prime,
po_args->must_match_five_prime)
) {
if (!must_use) {
op_set_must_match_err(h);
return;
}
}
}
/* end A. Untergasser's changes */
gc_and_n_content(j, k-j+1, sa->trimmed_seq, h);
if (h->num_ns > po_args->num_ns_accepted) {
op_set_too_many_ns(h);
stats->ns++;
if (!must_use) { return; }
}
/* Upstream error checking has ensured that we use non-default position
penalties only when there is 0 or 1 target. */
PR_ASSERT(sa->tar2.count <= 1 || _PR_DEFAULT_POSITION_PENALTIES(pa));
if (pa->primer_task == pick_sequencing_primers) {
h->position_penalty = 0.0;
} else if (
(l != OT_INTL) &&
_PR_DEFAULT_POSITION_PENALTIES(pa) &&
oligo_overlaps_interval(
j,
k-j+1,
sa->tar2.pairs,
sa->tar2.count
)
) {
h->position_penalty = 0.0;
bf_set_infinite_pos_penalty(h,1);
bf_set_overlaps_target(h,1);
} else if (l != OT_INTL && !_PR_DEFAULT_POSITION_PENALTIES(pa)
&& 1 == sa->tar2.count) {
compute_position_penalty(pa, sa, h, l);
if (bf_get_infinite_pos_penalty(h)) {
bf_set_overlaps_target(h,1);
}
} else {
h->position_penalty = 0.0;
bf_set_infinite_pos_penalty(h,0);
}
if (!PR_START_CODON_POS_IS_NULL(sa)) {
if (OT_LEFT == l) {
if (sa->start_codon_pos > h->start)
h->position_penalty
= (sa->start_codon_pos - h->start) * OUTSIDE_START_WT;
else
h->position_penalty
= (h->start - sa->start_codon_pos) * INSIDE_START_WT;
} else if (OT_RIGHT == l) {
if (-1 == retval->stop_codon_pos) {
h->position_penalty = (TRIMMED_SEQ_LEN(sa) - h->start - 1) * INSIDE_STOP_WT;
} else if (retval->stop_codon_pos < h->start) {
h->position_penalty
= (h->start - retval->stop_codon_pos) * OUTSIDE_STOP_WT;
} else {
h->position_penalty
= (retval->stop_codon_pos - h->start) * INSIDE_STOP_WT;
}
}
}
/* TO DO Simplify logic here */
if (
(l != OT_INTL) &&
oligo_overlaps_interval(
j,
k-j+1,
sa->excl2.pairs,
sa->excl2.count
)
) {
bf_set_overlaps_excl_region(h,1);
}
if (
(l == OT_INTL) &&
oligo_overlaps_interval(
j,
k-j+1,
sa->excl_internal2.pairs,
sa->excl_internal2.count)
) {
bf_set_overlaps_excl_region(h,1);
}
if (l != OT_INTL && bf_get_overlaps_target(h)) {
op_set_overlaps_target(h);
stats->target++;
if (!must_use) { return; }
}
if (bf_get_overlaps_excl_region(h)){
op_set_overlaps_excluded_region(h);
stats->excluded++;
if (!must_use) { return; }
}
/* Check if the oligo is included in any ok region */
if (
(l == OT_LEFT) &&
(sa->ok_regions.count > 0) &&
(!sa->ok_regions.any_left)
) {
int included = 0;
for (i=0; i < sa->ok_regions.count; i++) {
if (
(j >= sa->ok_regions.left_pairs[i][0]) &&
(k <= sa->ok_regions.left_pairs[i][0] + sa->ok_regions.left_pairs[i][1] - 1)
) {
included = 1;
break;
}
}
if (!included) {
op_set_not_in_any_ok_region(h);
stats->not_in_any_left_ok_region++;
if (!must_use) return;
}
}
if (
(l == OT_RIGHT) &&
(sa->ok_regions.count > 0) &&
(!sa->ok_regions.any_right)
) {
int included = 0;
for (i=0; i < sa->ok_regions.count; i++) {
if (
(j >= sa->ok_regions.right_pairs[i][0]) &&
(k <= sa->ok_regions.right_pairs[i][0] + sa->ok_regions.right_pairs[i][1] - 1)
) {
included = 1;
break;
}
}
if (!included) {
op_set_not_in_any_ok_region(h);
stats->not_in_any_right_ok_region++;
if (!must_use) return;
}
}
if (h->gc_content < po_args->min_gc) {
op_set_low_gc_content(h);
stats->gc++;
if (!must_use) return;
} else if (h->gc_content > po_args->max_gc) {
op_set_high_gc_content(h);
stats->gc++;
if (!must_use) return;
}
if ((OT_LEFT == l) || (OT_RIGHT == l)) {
/* gc_clamp is applicable only to primers (as opposed
to primers and hybridzations oligos. */
for (i = 0; i < pa->gc_clamp; i++) {
/* We want to look at the 3' end of the oligo being
assessed, so we look in the 5' end of its reverse-complement */
if (revc_oligo_seq[i] != 'G' && revc_oligo_seq[i] != 'C') {
op_set_no_gc_glamp(h);
stats->gc_clamp++;
if (!must_use) return; else break;
}
}
}
#if 0
/* Old code, works */
if (pa->gc_clamp != 0){
if (OT_LEFT == l) {
for(i=k-pa->gc_clamp+1; i<= k; i++)if (seq[i] !='G'&&seq[i] !='C'){
op_set_no_gc_glamp(h);
stats->gc_clamp++;
if (!must_use) return; else break;
}
}
if (OT_RIGHT == l){
for(i=j; igc_clamp; i++)if (seq[i] != 'G' && seq[i] != 'C'){
op_set_no_gc_glamp(h);
stats->gc_clamp++;
if (!must_use) return; else break;
}
}
}
#endif
if (
(pa->max_end_gc < 5) &&
(OT_LEFT == l || OT_RIGHT == l)
) {
/* The CGs are only counted in the END of primers (as opposed
to primers and hybridzations oligos. */
gc_count=0;
for (i = 0; i < 5; i++) {
/* We want to look at the 3' end of the oligo being
assessed, so we look in the 5' end of its reverse-complement */
if (revc_oligo_seq[i] == 'G' || revc_oligo_seq[i] == 'C') {
gc_count++;
}
}
if (gc_count > pa->max_end_gc) {
op_set_too_many_gc_at_end(h);
stats->gc_end_high++;
if (!must_use) return;
}
}
/* Tentative interface for generic oligo testing
function */
if (
(!sequence_quality_is_ok(
pa,
h,
l,
sa,
j,
k,
stats,
po_args
)) && (!must_use)
) {
return;
}
if (_pr_violates_poly_x(oligo_seq, po_args->max_poly_x)) {
op_set_high_poly_x(h);
stats->poly_x++;
if (!must_use) { return; }
}
/* Oligo/primer melting temperature */
tm_calc = seqtm(
oligo_seq,
po_args->dna_conc,
po_args->salt_conc,
po_args->divalent_conc,
po_args->dntp_conc,
po_args->dmso_conc,
po_args->dmso_fact,
po_args->formamide_conc,
MAX_NN_TM_LENGTH,
pa->tm_santalucia,
pa->salt_corrections,
pa->annealing_temp
);
h->temp = tm_calc.Tm;
h->bound = tm_calc.bound;
if (h->temp < po_args->min_tm) {
op_set_low_tm(h);
stats->temp_min++;
if (!must_use) return;
}
if (h->temp > po_args->max_tm) {
op_set_high_tm(h);
stats->temp_max++;
if (!must_use) return;
}
if (pa->annealing_temp > 0.0) {
if (h->bound < po_args->min_bound) {
op_set_low_bound(h);
stats->bound_min++;
if (!must_use) { return; }
}
if (h->bound > po_args->max_bound) {
op_set_high_bound(h);
stats->bound_max++;
if (!must_use) { return; }
}
}
/* End stability is applicable only to primers
(not to oligos) */
if (OT_LEFT == l || OT_RIGHT == l) {
if (
(h->end_stability = end_oligodg(
oligo_seq,
5,
pa->tm_santalucia)
) > pa->max_end_stability
) {
/* Must not be called on a hybridization probe / internal oligo: */
op_set_high_end_stability(h);
stats->stability++;
if (!must_use) return;
}
}
p_oligo_seq_overhang = oligo_seq;
p_revc_oligo_seq_overhang = revc_oligo_seq;
if (OT_LEFT == l) {
if (NULL != sa->overhang_left) {
overhang_len = strlen(sa->overhang_left);
strcpy(
oligo_seq_overhang,
sa->overhang_left
);
strcpy(
oligo_seq_overhang + overhang_len,
oligo_seq
);
p3_reverse_complement(
oligo_seq_overhang,
revc_oligo_seq_overhang
);
p_oligo_seq_overhang = oligo_seq_overhang;
p_revc_oligo_seq_overhang = revc_oligo_seq_overhang;
}
}
if (OT_RIGHT == l) {
if (NULL != sa->overhang_right) {
overhang_len = strlen(sa->overhang_right);
strcpy(
oligo_seq_overhang,
sa->overhang_right
);
strcpy(
oligo_seq_overhang + overhang_len,
oligo_seq
);
p3_reverse_complement(
oligo_seq_overhang,
revc_oligo_seq_overhang
);
p_oligo_seq_overhang = oligo_seq_overhang;
p_revc_oligo_seq_overhang = revc_oligo_seq_overhang;
}
}
if (
(
must_use ||
pa->file_flag ||
(retval->output_type == primer_list) ||
po_args->weights.compl_any ||
po_args->weights.compl_end
) &&
(pa->thermodynamic_oligo_alignment == 0)
) {
oligo_compl(
h,
po_args,
stats,
dpal_arg_to_use,
p_oligo_seq_overhang,
p_revc_oligo_seq_overhang
);
/* oligo_seq, revc_oligo_seq); */
if ((!(p3_ol_is_uninitialized(h))) && !must_use) {
PR_ASSERT(!p3_ol_is_ok(h));
return;
}
} else {
/* Thermodynamical approach: for primers only */
if (
(
must_use ||
pa->file_flag ||
(retval->output_type == primer_list) ||
po_args->weights.compl_any_th ||
po_args->weights.compl_end_th
) && (pa->thermodynamic_oligo_alignment == 1)
) {
oligo_compl_thermod(
h,
po_args,
stats,
thal_arg_to_use,
p_oligo_seq_overhang,
p_oligo_seq_overhang
);
if ((!(p3_ol_is_uninitialized(h))) && !must_use) {
PR_ASSERT(!p3_ol_is_ok(h));
return;
}
} else {
h->self_any = h->self_end = ALIGN_SCORE_UNDEF;
}
}
if ((three_conditions
|| po_args->weights.hairpin_th
#if 0
|| po_args->weights.compl_any_th /* Triinu, is this needed? */
|| po_args->weights.compl_end_th /* Triinu, is this needed? */
#endif
)
&& (pa->thermodynamic_oligo_alignment == 1)
) {
oligo_hairpin(
h,
po_args,
stats,
thal_arg_to_use,
p_oligo_seq_overhang
);
if ((!(p3_ol_is_uninitialized(h))) && !must_use) {
PR_ASSERT(!p3_ol_is_ok(h));
return;
}
} else {
/* This will get calculated later if necessary, in characterize_pair. */
h->hairpin_th = ALIGN_SCORE_UNDEF;
}
/* end of thermod. approach */
#if 0
/* FIX ME FIXME */
if (((must_use
|| pa->file_flag
|| retval->output_type == primer_list
|| po_args->weights.repeat_sim
|| ((OT_RIGHT == l || OT_LEFT == l)
&& pa->p_args.weights.template_mispriming))
&& pa->thermodynamic_oligo_alignment==0)
|| (pa->thermodynamic_oligo_alignment==1 && po_args->weights.repeat_sim)) {
oligo_repeat_library_mispriming(h, pa, sa, l, stats,
dpal_arg_to_use, &retval->glob_err);
if (pa->thermodynamic_template_alignment==0 && OK_OR_MUST_USE(h)) {
oligo_template_mispriming(h, pa, sa, l, stats,
dpal_arg_to_use->local_end,
thal_args_for_template_mispriming);
}
}
if ((must_use
|| pa->file_flag
|| retval->output_type == primer_list
|| ((OT_RIGHT == l || OT_LEFT == l)
&& pa->p_args.weights.template_mispriming_th))
&& pa->thermodynamic_template_alignment==1)
{
oligo_template_mispriming(h, pa, sa, l, stats,
dpal_arg_to_use->local_end,
thal_args_for_template_mispriming);
}
/* END FIX ME FIXME */
#else
if (three_conditions || po_args->weights.repeat_sim) {
oligo_repeat_library_mispriming(
h,
pa,
sa,
l,
stats,
dpal_arg_to_use,
&retval->glob_err
);
}
if (!OK_OR_MUST_USE(h)) { return; }
if (
three_conditions ||
( /* Do we need template mispriming for the penalty function? */
(OT_RIGHT == l || OT_LEFT == l) &&
(
(
(pa->p_args.weights.template_mispriming) &&
!(pa->thermodynamic_template_alignment)
) ||
(
(pa->p_args.weights.template_mispriming_th) &&
(pa->thermodynamic_template_alignment)
)
)
)
) {
if (OK_OR_MUST_USE(h)) {
oligo_template_mispriming(
h,
pa,
sa,
l,
stats,
dpal_arg_to_use->local_end,
thal_args_for_template_mispriming,
(thal_arg_holder *) thal_arg_to_use
);
}
}
#endif
if (h->length > po_args->max_size ) {
op_set_too_long(h);
stats->size_max++;
if (!must_use) { return; }
}
if (h->length < po_args->min_size ) {
op_set_too_short(h);
stats->size_min++;
if (!must_use) { return; }
}
for (for_i=0; for_i < sa->primer_overlap_junctions_count; for_i++) {
if (
(OT_LEFT == l) &&
(
((h->start + pa->p_args.min_5_prime_overlap_of_junction - 1) <=
sa->primer_overlap_junctions[for_i])
) &&
(
(h->start + h->length - pa->p_args.min_3_prime_overlap_of_junction) >
sa->primer_overlap_junctions[for_i]
)
) {
h->overlaps_overlap_position = 1;
/* no need to continue checking for more overlaps */
break;
}
if (
(OT_RIGHT == l) &&
(
(h->start - h->length + pa->p_args.min_3_prime_overlap_of_junction) <=
sa->primer_overlap_junctions[for_i]
) &&
(
(h->start - pa->p_args.min_5_prime_overlap_of_junction + 1) > sa->primer_overlap_junctions[for_i]
)
) {
h->overlaps_overlap_position = 1;
/* no need to continue checking for more overlaps */
break;
}
}
if ((OT_INTL == l) && (sa->intl_overlap_junctions_count > 0)) {
for (for_i=0; for_i < sa->intl_overlap_junctions_count; for_i++) {
if (
(
(h->start + pa->o_args.min_5_prime_overlap_of_junction - 1) <=
sa->intl_overlap_junctions[for_i]
) && (
(h->start + h->length - pa->o_args.min_3_prime_overlap_of_junction) >
sa->intl_overlap_junctions[for_i]
)
) {
h->overlaps_overlap_position = 1;
/* no need to continue checking for more overlaps */
break;
}
}
if ((!h->overlaps_overlap_position) && (!must_use)) {
stats->does_not_overlap_a_required_point ++;
op_set_must_match_err(h);
return;
}
}
/* Calculate failure rate */
/* Added by M. Lepamets */
h->failure_rate = 0.0;
#if !defined(OS_WIN)
if (pa->mask_template && h->length >= pa->mp.window_size) {
op.fwd = string_to_word(
oligo_seq,
h->length,
pa->mp.window_size
);
op.rev = op.fwd; /* not used in this calculation */
calculate_scores(
&op,
&pa->mp,
pa->mp.window_size
);
h->failure_rate = op.score_fwd;
}
#endif
/* FIX ME FIXME Steve, is this really needed? */
op_set_completely_written(h);
} /* calc_and_check_oligo_features */
#undef OUTSIDE_START_WT
#undef INSIDE_START_WT
#undef INSIDE_STOP_WT
#undef OUTSIDE_STOP_WT
/* Calculate the minimum sequence quality and the minimum sequence
quality of the 3' end of a primer or oligo. Set h->seq_quality
and h->seq_end_quality with these values. Return 1 (== ok)
if sa->quality is undefined. Otherwise, return 1 (ok)
if h->seq_quality and h->seq_end_quality are within
range, or else return 0.
*/
static int
sequence_quality_is_ok(
const p3_global_settings* pa,
primer_rec* h,
oligo_type l,
const seq_args_t* sa,
int j, int k,
oligo_stats* global_oligo_stats,
const args_for_one_oligo_or_primer* po_args
) {
int i, min_q, min_q_end, m, q;
int retval = 1;
if (sa->quality == NULL) {
h->seq_end_quality = h->seq_quality = pa->quality_range_max;
return 1;
}
q = pa->quality_range_max;
min_q = po_args->min_quality;
if ((OT_LEFT == l) || (OT_RIGHT == l)) {
min_q_end = po_args->min_end_quality;
} else {
min_q_end = min_q;
}
if ((OT_LEFT == l) || (OT_INTL == l)) {
for(i = k - 4; i <= k; i++) {
if (i < j) { continue; }
m = sa->quality[i + sa->incl_s];
if (m < q) { q = m; }
}
min_q_end = q;
for(i = j; i <= k - 5; i++) {
m = sa->quality[i + sa->incl_s];
if (m < q) { q = m; }
}
min_q = q;
} else if (OT_RIGHT == l) {
for(i = j; i < j + 5; i++) {
if (i > k) { break; }
m = sa->quality[i + sa->incl_s];
if (m < q) { q = m; }
}
min_q_end = q;
for(i = j + 5; i <= k; i++) {
m = sa->quality[i + sa->incl_s];
if (m < q) { q = m; }
}
min_q = q;
} else {
PR_ASSERT(0); /* Programming error. */
}
h->seq_quality = min_q;
h->seq_end_quality = min_q_end;
if (h->seq_quality < po_args->min_quality) {
op_set_low_sequence_quality(h);
global_oligo_stats->seq_quality++;
retval = 0;
return retval;
}
if ((OT_LEFT == l) || (OT_RIGHT == l)) {
if (h->seq_end_quality < po_args->min_end_quality) {
op_set_low_end_sequence_quality(h);
global_oligo_stats->seq_quality++;
retval = 0;
}
}
return retval;
}
/*
* Set h->gc_content to the GC % of the 'len' bases starting at 'start' in
* 'sequence' (excluding 'N's). Set h->num_ns to the number of 'N's in that
* subsequence.
*/
static void
gc_and_n_content(
int start,
int len,
const char* sequence,
primer_rec* h
) {
const char* p = &sequence[start];
const char* stop = p + len;
int num_gc = 0, num_gcat = 0, num_n = 0;
while (p < stop) {
if ('N' == *p) {
num_n++;
} else {
num_gcat++;
if (('C' == *p) || ('G' == *p)) { num_gc++; }
}
p++;
}
h->num_ns = num_n;
if (0 == num_gcat) { h->gc_content = 0.0; }
else { h->gc_content = 100.0 * ((double) num_gc) / num_gcat; }
}
static int
oligo_overlaps_interval(
int start,
int len,
const interval_array_t intervals,
int num_intervals
) {
int i;
int last = start + len - 1;
for (i = 0; i < num_intervals; i++) {
if (
!(
(last < intervals[i][0]) ||
(start > (intervals[i][0] + intervals[i][1] - 1))
)
) {
return 1;
}
}
return 0;
}
/* Calculate the part of the objective function due to one primer. */
static double
p_obj_fn(
const p3_global_settings* pa,
primer_rec* h,
int j
) {
double sum;
sum = 0;
if ((j == OT_LEFT) || (j == OT_RIGHT)) {
if (
(pa->p_args.weights.temp_gt) &&
(h->temp > pa->p_args.opt_tm)
) {
sum += (
pa->p_args.weights.temp_gt * (h->temp - pa->p_args.opt_tm)
);
}
if (
(pa->p_args.weights.temp_lt) &&
(h->temp < pa->p_args.opt_tm)
) {
sum += (
pa->p_args.weights.temp_lt * (pa->p_args.opt_tm - h->temp)
);
}
if (pa->annealing_temp > 0.0) {
if (
(pa->p_args.weights.bound_gt) &&
(h->bound > pa->p_args.opt_bound)
) {
sum += (
pa->p_args.weights.bound_gt *
(h->bound - pa->p_args.opt_bound)
);
}
if (
(pa->p_args.weights.bound_lt) &&
(h->bound < pa->p_args.opt_bound)
) {
sum += (
pa->p_args.weights.bound_lt *
(pa->p_args.opt_bound - h->bound)
);
}
}
if (
(pa->p_args.weights.gc_content_gt) &&
(h->gc_content > pa->p_args.opt_gc_content)
) {
sum += (
pa->p_args.weights.gc_content_gt *
(h->gc_content - pa->p_args.opt_gc_content)
);
}
if (
(pa->p_args.weights.gc_content_lt) &&
(h->gc_content < pa->p_args.opt_gc_content)
) {
sum += (
pa->p_args.weights.gc_content_lt *
(pa->p_args.opt_gc_content - h->gc_content)
);
}
if (
(pa->p_args.weights.length_lt) &&
(h->length < pa->p_args.opt_size)
) {
sum += (pa->p_args.weights.length_lt * (pa->p_args.opt_size - h->length));
}
if (
(pa->p_args.weights.length_gt) &&
(h->length > pa->p_args.opt_size)
) {
sum += (pa->p_args.weights.length_gt * (h->length - pa->p_args.opt_size));
}
/* edited by M. Lepamets */
if (pa->p_args.weights.failure_rate) {
sum += (pa->p_args.weights.failure_rate * h->failure_rate);
}
/* BEGIN: secondary structures */
if (pa->thermodynamic_oligo_alignment==0) {
if (pa->p_args.weights.compl_any) {
sum += (pa->p_args.weights.compl_any * h->self_any);
}
if (pa->p_args.weights.compl_end) {
sum += (pa->p_args.weights.compl_end * h->self_end);
}
} else if (pa->thermodynamic_oligo_alignment==1) {
if (pa->p_args.weights.compl_any_th) {
if ((h->temp - pa->p_args.weights.temp_cutoff) <= h->self_any) {
sum += (
pa->p_args.weights.compl_any_th *
(h->self_any - (h->temp - pa->p_args.weights.temp_cutoff - 1.0))
); /* -1.0 is added for the case where == */
} else {
sum += (
pa->p_args.weights.compl_any_th *
(1 / (h->temp - pa->p_args.weights.temp_cutoff + 1.0 - h->self_any))
);
}
}
if (pa->p_args.weights.compl_end_th) {
if ((h->temp - pa->p_args.weights.temp_cutoff) <= h->self_end) {
sum += (
pa->p_args.weights.compl_end_th *
(h->self_end - (h->temp - pa->p_args.weights.temp_cutoff - 1.0))
);
} else {
sum += (
pa->p_args.weights.compl_end_th *
(1 / (h->temp - pa->p_args.weights.temp_cutoff + 1.0 - h->self_end))
);
}
}
if (pa->p_args.weights.hairpin_th) {
if ((h->temp - pa->p_args.weights.temp_cutoff) <= h->hairpin_th) {
sum += (
pa->p_args.weights.hairpin_th *
(h->hairpin_th - (h->temp - pa->p_args.weights.temp_cutoff - 1.0))
);
} else {
sum += (
pa->p_args.weights.hairpin_th *
(1 / (h->temp - pa->p_args.weights.temp_cutoff + 1.0 - h->hairpin_th))
);
}
}
} else {
PR_ASSERT(0)
/* Programming error,
illegal value for pa->thermodynamic_oligo_alignment */
}
/* END: secondary structures */
if (pa->p_args.weights.num_ns) {
sum += (pa->p_args.weights.num_ns * h->num_ns);
}
if (pa->p_args.weights.repeat_sim) {
sum += (
pa->p_args.weights.repeat_sim *
h->repeat_sim.score[h->repeat_sim.max]
);
}
if (!bf_get_overlaps_target(h)) {
/* We might be evaluating p_obj_fn with h->target if
the client supplied 'pick_anyway' and specified
a primer or oligo. */
PR_ASSERT(!(bf_get_infinite_pos_penalty(h)));
if (pa->p_args.weights.pos_penalty) {
sum += (pa->p_args.weights.pos_penalty * h->position_penalty);
}
}
if (pa->p_args.weights.end_stability) {
sum += (pa->p_args.weights.end_stability * h->end_stability);
}
/* FIX ME QUALITY WT Change here */
if (pa->p_args.weights.seq_quality) {
sum += (
pa->p_args.weights.seq_quality *
(pa->quality_range_max - h->seq_quality)
); /* Look for end seq quality */
}
if (
(pa->p_args.weights.template_mispriming) &&
(pa->thermodynamic_template_alignment == 0)
) {
PR_ASSERT(oligo_max_template_mispriming(h) != ALIGN_SCORE_UNDEF);
sum += (
pa->p_args.weights.template_mispriming *
oligo_max_template_mispriming(h)
);
}
if (
(pa->p_args.weights.template_mispriming_th) &&
(pa->thermodynamic_template_alignment == 1)
) {
PR_ASSERT(oligo_max_template_mispriming_thermod(h) != ALIGN_SCORE_UNDEF);
if (
(h->temp - pa->p_args.weights.temp_cutoff) <= oligo_max_template_mispriming_thermod(h)
) {
sum += (
pa->p_args.weights.template_mispriming_th *
(oligo_max_template_mispriming_thermod(h) - (h->temp - pa->p_args.weights.temp_cutoff - 1.0))
);
}
if (
(h->temp - pa->p_args.weights.temp_cutoff) > oligo_max_template_mispriming_thermod(h)
) {
sum += (
pa->p_args.weights.template_mispriming_th *
(1 / (h->temp - pa->p_args.weights.temp_cutoff + 1.0 - oligo_max_template_mispriming_thermod(h)))
);
}
}
return sum;
} else if (j == OT_INTL) {
if (
(pa->o_args.weights.temp_gt) &&
(h->temp > pa->o_args.opt_tm)
) {
sum += (pa->o_args.weights.temp_gt * (h->temp - pa->o_args.opt_tm));
}
if (
(pa->o_args.weights.temp_lt) &&
(h->temp < pa->o_args.opt_tm)
) {
sum += (pa->o_args.weights.temp_lt * (pa->o_args.opt_tm - h->temp));
}
if (
(pa->o_args.weights.bound_gt) &&
(h->bound > pa->o_args.opt_bound)
) {
sum += (
pa->o_args.weights.bound_gt * (h->bound - pa->o_args.opt_bound)
);
}
if (
(pa->o_args.weights.bound_lt) &&
(h->bound < pa->o_args.opt_bound)
) {
sum += (
pa->o_args.weights.bound_lt * (pa->o_args.opt_bound - h->bound)
);
}
if (
(pa->o_args.weights.gc_content_gt) &&
(h->gc_content > pa->o_args.opt_gc_content)
) {
sum += (
pa->o_args.weights.gc_content_gt *
(h->gc_content - pa->o_args.opt_gc_content)
);
}
if (
(pa->o_args.weights.gc_content_lt) &&
(h->gc_content < pa->o_args.opt_gc_content)
) {
sum += (
pa->o_args.weights.gc_content_lt *
(pa->o_args.opt_gc_content - h->gc_content)
);
}
if (
(pa->o_args.weights.length_lt) &&
(h->length < pa->o_args.opt_size)
) {
sum += pa->o_args.weights.length_lt * (pa->o_args.opt_size - h->length);
}
if (
(pa->o_args.weights.length_gt) &&
(h->length > pa->o_args.opt_size)
) {
sum += pa->o_args.weights.length_gt * (h->length - pa->o_args.opt_size);
}
if (
(pa->o_args.weights.compl_any) &&
(pa->thermodynamic_oligo_alignment == 0)
) {
sum += pa->o_args.weights.compl_any * h->self_any;
}
if (
(pa->o_args.weights.compl_end) &&
(pa->thermodynamic_oligo_alignment == 0)
) {
sum += pa->o_args.weights.compl_end * h->self_end;
}
/* begin thermodynamical approach */
if (pa->thermodynamic_oligo_alignment==1) {
if (pa->o_args.weights.compl_any_th) {
if ((h->temp - pa->o_args.weights.temp_cutoff) <= h->self_any) {
sum += (
pa->o_args.weights.compl_any_th *
(h->self_any - (h->temp - pa->o_args.weights.temp_cutoff - 1.0))
); /* -1.0 is added for the case where == */
} else {
sum += (
pa->o_args.weights.compl_any_th *
(1/(h->temp - pa->o_args.weights.temp_cutoff + 1.0 - h->self_any))
);
}
}
if (pa->o_args.weights.compl_end_th) {
if ((h->temp - pa->o_args.weights.temp_cutoff) <= h->self_end) {
sum += (
pa->o_args.weights.compl_end_th *
(h->self_end - (h->temp - pa->o_args.weights.temp_cutoff - 1.0))
);
} else {
sum += (
pa->o_args.weights.compl_end_th *
(1/(h->temp - pa->o_args.weights.temp_cutoff + 1.0 - h->self_end))
);
}
}
if (pa->o_args.weights.hairpin_th) {
if ((h->temp - pa->o_args.weights.temp_cutoff) <= h->hairpin_th) {
sum += (
pa->o_args.weights.hairpin_th *
(h->hairpin_th - (h->temp - pa->o_args.weights.temp_cutoff - 1.0))
);
} else {
sum += (
pa->o_args.weights.hairpin_th *
(1 / (h->temp - pa->o_args.weights.temp_cutoff + 1.0 - h->hairpin_th))
);
}
}
}
/* end thermodynamical approach */
if (pa->o_args.weights.num_ns) {
sum += pa->o_args.weights.num_ns * h->num_ns;
}
if (pa->o_args.weights.repeat_sim) {
sum += pa->o_args.weights.repeat_sim
* h->repeat_sim.score[h->repeat_sim.max];
}
/* FIX ME QUALITY WT */
if (pa->o_args.weights.seq_quality) {
sum += pa->o_args.weights.seq_quality *
(pa->quality_range_max - h->seq_quality);
}
return sum;
} else {
PR_ASSERT(0); /* Programming error. */
return -1.0;
}
}
// <<<<<<<<<<<<<<<<<<<<<<<
/* Return max of h->template_mispriming and h->template_mispriming_r (max
template mispriming on either strand). */
double
oligo_max_template_mispriming(
const primer_rec* h
) {
return h->template_mispriming > h->template_mispriming_r ?
h->template_mispriming : h->template_mispriming_r;
}
double
oligo_max_template_mispriming_thermod(
const primer_rec* h
) {
return h->template_mispriming > h->template_mispriming_r ?
h->template_mispriming : h->template_mispriming_r;
}
char*
oligo_max_template_mispriming_struct(
const primer_rec* h
) {
return h->template_mispriming > h->template_mispriming_r ?
h->template_mispriming_struct : h->template_mispriming_r_struct;
}
/* Sort a given primer array by penalty */
static void
sort_primer_array(
oligo_array* oligo
) {
qsort(
&oligo->oligo[0],
oligo->num_elem,
sizeof(primer_rec),
primer_rec_comp
);
}
/* Compare function for sorting primer records. */
static int
primer_rec_comp(
const void *x1,
const void *x2
) {
const primer_rec* a1 = (const primer_rec* ) x1;
const primer_rec* a2 = (const primer_rec* ) x2;
if (a1->quality < a2->quality) return -1;
if (a1->quality > a2->quality) return 1;
/*
* We want primer_rec_comp to always return a non-0 result, because
* different implementations of qsort differ in how they treat "equal"
* elements, making it difficult to compare test output on different
* systems.
*/
if (a1->start > a2->start) return -1;
if (a1->start < a2->start) return 1;
if (a1->length < a2->length) return -1;
return 1;
}
/* Compare function for sorting primer records. */
static int
compare_primer_pair(
const void *x1,
const void *x2
) {
const primer_pair* a1 = (const primer_pair* ) x1;
const primer_pair* a2 = (const primer_pair* ) x2;
const double epsilon = 1e-6;
int y1, y2;
if ((a1->pair_quality + epsilon) < a2->pair_quality) return -1;
if (a1->pair_quality > (a2->pair_quality + epsilon)) return 1;
/*
* The following statements ensure that we get a stable order that
* is the same on all systems.
*/
y1 = a1->left->start;
y2 = a2->left->start;
if (y1 > y2) return -1; /* prefer left primers to the right. */
if (y1 < y2) return 1;
y1 = a1->right->start;
y2 = a2->right->start;
if (y1 < y2) return -1; /* prefer right primers to the left. */
if (y1 > y2) return 1;
y1 = a1->left->length;
y2 = a2->left->length;
if (y1 < y2) return -1; /* prefer shorter primers. */
if (y1 > y2) return 1;
y1 = a1->right->length;
y2 = a2->right->length;
if (y1 < y2) return -1; /* prefer shorter primers. */
if (y1 > y2) return 1;
return 0;
}
/*
* Defines parameter values for given primer pair. Returns PAIR_OK if the pair is
* acceptable; PAIR_FAILED otherwise. This function sets the
* various elements of *ppair, and also calculates some key EXPENSIVE
* parameters for individual primers if they have not been set yet.
*/
static int
characterize_pair(
p3retval* retval,
const p3_global_settings* pa,
const seq_args_t* sa,
int m,
int n,
int int_num,
primer_pair* ppair,
const dpal_arg_holder* dpal_arg_to_use,
const thal_arg_holder* thal_arg_to_use,
int update_stats
) {
char s1[THAL_MAX_ALIGN+1], s2[THAL_MAX_ALIGN+1];
char s1_rev[THAL_MAX_ALIGN+1], s2_rev[THAL_MAX_ALIGN+1];
double compl_end, compl_end2;
pair_stats* pair_expl = &retval->best_pairs.expl;
int must_use = 0;
double min_oligo_tm;
int i, overhang_len;
tm_ret tm_calc; /* structure with Tm and bound (primer fraction) */
const thal_args* thal_args_for_template_mispriming = (
use_end_for_th_template_mispriming
? thal_arg_to_use->end1
: thal_arg_to_use->any
);
// memset(ppair, 0, sizeof(*ppair));
memset(ppair, 0, sizeof(primer_pair));
ppair->left = &retval->fwd.oligo[m];
ppair->right = &retval->rev.oligo[n];
ppair->product_size = (
retval->rev.oligo[n].start - retval->fwd.oligo[m].start+1
);
ppair->target = 0;
ppair->compl_any = ppair->compl_end = 0;
ppair->compl_any_struct = NULL;
ppair->compl_end_struct = NULL;
ppair->template_mispriming_struct = NULL;
if (update_stats) {
pair_expl->considered++;
}
if (pa->primer_task == check_primers) {
must_use = 1;
}
/* We must use the pair if the caller specifed
both the left and the right primer. */
if (ppair->left->must_use != 0 &&
ppair->right->must_use != 0) {
/* But if caller specified primers are in
reversed order we cannot analyze them
as a pair. */
if (ppair->product_size < 1) {
pair_expl->reversed++;
return PAIR_FAILED;
}
must_use = 1;
}
ppair->must_use = must_use;
if (sa->tar2.count > 0) {
if (pair_spans_target(ppair, sa)) {
ppair->target = 1;
} else {
ppair->target = -1;
if (update_stats) { pair_expl->target++; }
if (!must_use) { return PAIR_FAILED; }
}
}
/* ============================================================= */
/* Check that the pair is included in one of the specified ok regions */
if (
(sa->ok_regions.count > 0) &&
(!sa->ok_regions.any_pair)
) {
int included = 0;
int l_start = ppair->left->start;
int l_end = ppair->left->start + ppair->left->length - 1;
int r_start = ppair->right->start - ppair->right->length + 1;
int r_end = ppair->right->start;
for (i=0; iok_regions.count; i++) {
if (sa->ok_regions.left_pairs[i][0] == -1) {
/* any left primer, check right primer */
if (
(r_start >= sa->ok_regions.right_pairs[i][0]) &&
(r_end <= sa->ok_regions.right_pairs[i][0] + sa->ok_regions.right_pairs[i][1] - 1)
) {
included = 1;
break;
}
} else if (sa->ok_regions.right_pairs[i][0] == -1) {
/* any right primer, check the left primer */
if (
(l_start >= sa->ok_regions.left_pairs[i][0]) &&
(l_end <= sa->ok_regions.left_pairs[i][0] + sa->ok_regions.left_pairs[i][1] - 1)
) {
included = 1;
break;
}
} else {
/* check both primers */
if (
(l_start >= sa->ok_regions.left_pairs[i][0]) &&
(l_end <= sa->ok_regions.left_pairs[i][0] + sa->ok_regions.left_pairs[i][1] - 1) &&
(r_start >= sa->ok_regions.right_pairs[i][0]) &&
(r_end <= sa->ok_regions.right_pairs[i][0] + sa->ok_regions.right_pairs[i][1] - 1)
) {
included = 1;
break;
}
}
}
if (!included) {
if (update_stats) { pair_expl->not_in_any_ok_region++; }
if (!must_use) { return PAIR_FAILED; }
}
}
/* ============================================================= */
/* Compute product Tm and related parameters; check constraints. */
if (ppair->right->start - ppair->left->start + 1 <= 0) {
fprintf(stderr, "temporary");
}
PR_ASSERT(ppair->right->start - ppair->left->start + 1 > 0)
tm_calc = long_seq_tm(
sa->trimmed_seq,
ppair->left->start,
ppair->right->start - ppair->left->start + 1,
/* TO DO -- skewed, it would be better to not use p_args elements here */
pa->p_args.salt_conc,
pa->p_args.divalent_conc,
pa->p_args.dntp_conc,
pa->p_args.dmso_conc,
pa->p_args.dmso_fact,
pa->p_args.formamide_conc
);
ppair->product_tm = tm_calc.Tm;
PR_ASSERT(ppair->product_tm != OLIGOTM_ERROR);
min_oligo_tm = (
ppair->left->temp > ppair->right->temp
? ppair->right->temp
: ppair->left->temp
);
ppair->product_tm_oligo_tm_diff = ppair->product_tm - min_oligo_tm;
ppair->t_opt_a = (0.3 * min_oligo_tm) + (0.7 * ppair->product_tm) - 14.9;
if (
(pa->product_min_tm != PR_DEFAULT_PRODUCT_MIN_TM) &&
(ppair->product_tm < pa->product_min_tm)
) {
if (update_stats) { pair_expl->low_tm++; }
if (!must_use) { return PAIR_FAILED; }
}
if (
(pa->product_max_tm != PR_DEFAULT_PRODUCT_MAX_TM) &&
(ppair->product_tm > pa->product_max_tm)
) {
if (update_stats) { pair_expl->high_tm++; }
if (!must_use) { return PAIR_FAILED; }
}
ppair->diff_tm = fabs(
retval->fwd.oligo[m].temp - retval->rev.oligo[n].temp
);
if (ppair->diff_tm > pa->max_diff_tm) {
if (update_stats) { pair_expl->temp_diff++; }
if (!must_use) { return PAIR_FAILED; }
}
/* End of product-temperature related computations. */
/* ============================================================= */
/* ============================================================= */
/* BEGIN "EXPENSIVE" computations on _individual_ primers
in the pair. These have been postponed until
this point in the interests of efficiency.
*/
/* ============================================================= */
/* Estimate secondary structure and primer-dimer of _individual_
primers if not already calculated. */
/* s1 is the forward oligo. */
if (sa->overhang_left != NULL) {
overhang_len = strlen(sa->overhang_left);
strcpy(
s1,
sa->overhang_left
);
_pr_shift_substr(
sa->trimmed_seq,
retval->fwd.oligo[m].start,
retval->fwd.oligo[m].length,
overhang_len,
s1
);
} else {
_pr_substr(
sa->trimmed_seq,
retval->fwd.oligo[m].start,
retval->fwd.oligo[m].length,
s1
);
}
/* s2 is the reverse oligo. */
_pr_substr(
sa->trimmed_seq,
retval->rev.oligo[n].start - retval->rev.oligo[n].length + 1,
retval->rev.oligo[n].length,
s2
);
if (sa->overhang_right != NULL) {
overhang_len = strlen(sa->overhang_right);
_pr_shift_substr(
sa->overhang_right_rv,
0,
overhang_len,
retval->rev.oligo[n].length,
s2
);
}
p3_reverse_complement(s1, s1_rev);
p3_reverse_complement(s2, s2_rev);
if (
(retval->fwd.oligo[m].self_any == ALIGN_SCORE_UNDEF) &&
(pa->thermodynamic_oligo_alignment == 0)
) {
/* We have not yet computed the 'self_any' paramter,
which is an estimate of self primer-dimer and secondary
structure propensity. */
oligo_compl(
&retval->fwd.oligo[m],
&pa->p_args,
&retval->fwd.expl,
dpal_arg_to_use,
s1,
s1_rev
);
if (!OK_OR_MUST_USE(&retval->fwd.oligo[m])) {
pair_expl->considered--;
if (!must_use) { return PAIR_FAILED; }
}
}
/* Thermodynamic approach, fwd-primer */
if (
(retval->fwd.oligo[m].self_any == ALIGN_SCORE_UNDEF) &&
(pa->thermodynamic_oligo_alignment == 1)
) {
oligo_compl_thermod(
&retval->fwd.oligo[m],
&pa->p_args,
&retval->fwd.expl,
thal_arg_to_use,
s1,
s1
); /* ! s1, s1_rev */
if (!OK_OR_MUST_USE(&retval->fwd.oligo[m])) {
pair_expl->considered--;
if (!must_use) { return PAIR_FAILED; }
}
}
if (
(retval->fwd.oligo[m].hairpin_th == ALIGN_SCORE_UNDEF) &&
(pa->thermodynamic_oligo_alignment == 1)
) {
oligo_hairpin(
&retval->fwd.oligo[m],
&pa->p_args,
&retval->fwd.expl,
thal_arg_to_use,
s1
);
if (!OK_OR_MUST_USE(&retval->fwd.oligo[m])) {
pair_expl->considered--;
if (!must_use) { return PAIR_FAILED; }
}
}
/* End of thermodynamic approach */
if (
(retval->rev.oligo[n].self_any == ALIGN_SCORE_UNDEF) &&
(pa->thermodynamic_oligo_alignment == 0)
) {
oligo_compl(
&retval->rev.oligo[n],
&pa->p_args,
&retval->rev.expl,
dpal_arg_to_use,
s2_rev,
s2
);
if (!OK_OR_MUST_USE(&retval->rev.oligo[n])) {
pair_expl->considered--;
if (!must_use) { return PAIR_FAILED; }
}
}
/* Thermodynamic approach */
if (
(retval->rev.oligo[n].self_any == ALIGN_SCORE_UNDEF) &&
(pa->thermodynamic_oligo_alignment == 1)
) {
oligo_compl_thermod(
&retval->rev.oligo[n],
&pa->p_args,
&retval->rev.expl,
thal_arg_to_use,
s2_rev,
s2_rev
); /* s2_rev, s2 */
if (!OK_OR_MUST_USE(&retval->rev.oligo[n])) {
pair_expl->considered--;
if (!must_use) { return PAIR_FAILED; }
}
}
if (
(retval->rev.oligo[n].hairpin_th == ALIGN_SCORE_UNDEF) &&
(pa->thermodynamic_oligo_alignment == 1)
) {
oligo_hairpin(
&retval->rev.oligo[n],
&pa->p_args,
&retval->rev.expl,
thal_arg_to_use,
s2_rev
);
if (!OK_OR_MUST_USE(&retval->rev.oligo[n])) {
pair_expl->considered--;
if (!must_use) { return PAIR_FAILED; }
}
}
/* End of thermodynamic approach */
/* End of secondary structure and primer-dimer of _individual_
primers. */
/* ============================================================= */
/* ============================================================= */
/* Mispriming of _individual_ primers to template and
to repeat libraries. */
if (retval->fwd.oligo[m].repeat_sim.score == NULL) {
/* We have not yet checked the oligo against the repeat library. */
oligo_repeat_library_mispriming(
&retval->fwd.oligo[m],
pa,
sa,
OT_LEFT,
&retval->fwd.expl,
dpal_arg_to_use,
&retval->glob_err
);
if (OK_OR_MUST_USE(&retval->fwd.oligo[m])) {
oligo_template_mispriming(
&retval->fwd.oligo[m],
pa,
sa,
OT_LEFT,
&retval->fwd.expl,
dpal_arg_to_use->local_end,
thal_args_for_template_mispriming,
(thal_arg_holder *) thal_arg_to_use
);
}
if (!OK_OR_MUST_USE(&retval->fwd.oligo[m])) {
pair_expl->considered--;
if (!must_use) { return PAIR_FAILED; }
}
}
if (retval->rev.oligo[n].repeat_sim.score == NULL) {
oligo_repeat_library_mispriming(
&retval->rev.oligo[n],
pa,
sa,
OT_RIGHT,
&retval->rev.expl,
dpal_arg_to_use,
&retval->glob_err
);
if (OK_OR_MUST_USE(&retval->rev.oligo[n])) {
oligo_template_mispriming(
&retval->rev.oligo[n],
pa,
sa,
OT_RIGHT,
&retval->rev.expl,
dpal_arg_to_use->local_end,
thal_args_for_template_mispriming,
(thal_arg_holder *) thal_arg_to_use
);
}
if (!OK_OR_MUST_USE(&retval->rev.oligo[n])) {
pair_expl->considered--;
if (!must_use) { return PAIR_FAILED; }
}
}
/* End of mispriming of _individual_ primers to template and
to repeat libraries. */
/* ============================================================= */
/* ============================================================= */
/*
* Similarity between s1 and s2 is equivalent to complementarity between
* s2's complement and s1. (Both s1 and s2 are taken from the same strand.)
*/
if (pa->thermodynamic_oligo_alignment == 0) {
ppair->compl_any = align(
s1,
s2,
dpal_arg_to_use->local
);
if (ppair->compl_any > pa->pair_compl_any) {
if (update_stats) { pair_expl->compl_any++; }
if (!must_use) { return PAIR_FAILED; }
}
ppair->compl_end = align(
s1,
s2,
dpal_arg_to_use->end
);
if (ppair->compl_end > pa->pair_compl_end) {
if (update_stats) { pair_expl->compl_end++; }
if (!must_use) { return PAIR_FAILED; }
}
} else {
/* thermodynamical approach */
ppair->compl_any = align_thermod(
s1,
s2_rev,
thal_arg_to_use->any,
(thal_arg_holder*) thal_arg_to_use
);
if (ppair->compl_any > pa->pair_compl_any_th) {
if (update_stats) {
pair_expl->compl_any++;
}
if (!must_use) { return PAIR_FAILED; }
}
ppair->compl_end = align_thermod(
s1,
s2_rev,
thal_arg_to_use->end1,
(thal_arg_holder*) thal_arg_to_use
);
compl_end = align_thermod(
s1,
s2_rev,
thal_arg_to_use->end2,
(thal_arg_holder*) thal_arg_to_use
); /* Triinu Please check */
if (ppair->compl_end < compl_end) {
ppair->compl_end = compl_end;
}
if (ppair->compl_end > pa->pair_compl_end_th) {
if (update_stats) {
pair_expl->compl_end++;
}
if (!must_use) { return PAIR_FAILED; }
}
}
/*
* It is conceivable (though unlikely) that
* align(s2_rev, s1_rev, end_args) > align(s1,s2,end_args).
*/
if (
(pa->thermodynamic_oligo_alignment == 0) &&
((compl_end = align(s2_rev, s1_rev, dpal_arg_to_use->end)) > ppair->compl_end)
) {
if (compl_end > pa->p_args.max_self_end) {
if (update_stats) { pair_expl->compl_end++; }
if (!must_use) { return PAIR_FAILED; }
}
ppair->compl_end = compl_end;
}
if (
(ppair->repeat_sim = pair_repeat_sim(ppair, pa)) > pa->pair_repeat_compl
) {
if (update_stats) { pair_expl->repeat_sim++; }
if (!must_use) { return PAIR_FAILED; }
}
/* thermodynamic approach */
if (pa->thermodynamic_oligo_alignment == 1) {
compl_end = align_thermod(
s2,
s1_rev,
thal_arg_to_use->end1,
(thal_arg_holder*) thal_arg_to_use
);
compl_end2 = align_thermod(
s2,
s1_rev,
thal_arg_to_use->end2,
(thal_arg_holder*) thal_arg_to_use
);
if (compl_end2 > compl_end) {
compl_end = compl_end2;
}
if (compl_end > ppair->compl_end) {
if (compl_end > pa->p_args.max_self_end_th) {
if (update_stats) {
pair_expl->compl_end++;
}
if (!must_use) { return PAIR_FAILED; }
}
ppair->compl_end = compl_end;
}
}
/* ============================================================= */
/* ============================================================= */
/* Calculate _pair_ mispriming, if necessary. */
if (pa->thermodynamic_template_alignment == 0) {
if (!_pr_need_pair_template_mispriming(pa)) {
ppair->template_mispriming = ALIGN_SCORE_UNDEF;
} else {
PR_ASSERT(ppair->left->template_mispriming != ALIGN_SCORE_UNDEF);
PR_ASSERT(ppair->left->template_mispriming_r != ALIGN_SCORE_UNDEF);
PR_ASSERT(ppair->right->template_mispriming != ALIGN_SCORE_UNDEF);
PR_ASSERT(ppair->right->template_mispriming_r != ALIGN_SCORE_UNDEF);
ppair->template_mispriming = (
ppair->left->template_mispriming +
ppair->right->template_mispriming_r
);
if (
(ppair->left->template_mispriming_r + ppair->right->template_mispriming) > ppair->template_mispriming
) {
ppair->template_mispriming = (
ppair->left->template_mispriming_r + ppair->right->template_mispriming
);
}
if (
(pa->pair_max_template_mispriming >= 0.0) &&
(ppair->template_mispriming > pa->pair_max_template_mispriming)
) {
if (update_stats) { pair_expl->template_mispriming++; }
if (!must_use) { return PAIR_FAILED; }
}
}
} else { /* thermodynamic approach */
if (!_pr_need_pair_template_mispriming_thermod(pa)) {
ppair->template_mispriming = ALIGN_SCORE_UNDEF;
} else {
PR_ASSERT(ppair->left->template_mispriming != ALIGN_SCORE_UNDEF);
PR_ASSERT(ppair->left->template_mispriming_r != ALIGN_SCORE_UNDEF);
PR_ASSERT(ppair->right->template_mispriming != ALIGN_SCORE_UNDEF);
PR_ASSERT(ppair->right->template_mispriming_r != ALIGN_SCORE_UNDEF);
ppair->template_mispriming = (
ppair->left->template_mispriming + ppair->right->template_mispriming_r
);
if (
(ppair->left->template_mispriming_r + ppair->right->template_mispriming) > ppair->template_mispriming
) {
ppair->template_mispriming = (
ppair->left->template_mispriming_r + ppair->right->template_mispriming
);
}
if (
(pa->pair_max_template_mispriming_th) &&
(ppair->template_mispriming > pa->pair_max_template_mispriming_th)
) {
if (update_stats) {
pair_expl->template_mispriming++;
}
if (!must_use) { return PAIR_FAILED; }
}
}
}
/* End of calculating _pair_ mispriming if necessary. */
/* ============================================================= */
return PAIR_OK;
} /* characterize_pair */
/*
*/
void
compute_position_penalty(
const p3_global_settings* pa,
const seq_args_t* sa,
primer_rec* h,
oligo_type o_type
) {
int three_prime_base;
int inside_flag = 0;
int target_begin, target_end;
PR_ASSERT((OT_LEFT == o_type) || (OT_RIGHT == o_type));
PR_ASSERT(1 == sa->tar2.count);
target_begin = sa->tar2.pairs[0][0];
target_end = target_begin + sa->tar2.pairs[0][1] - 1;
three_prime_base = (
OT_LEFT == o_type ?
h->start + h->length - 1 :
h->start - h->length + 1
);
bf_set_infinite_pos_penalty(h, 1);
h->position_penalty = 0.0;
if (OT_LEFT == o_type) {
if (three_prime_base <= target_end) {
bf_set_infinite_pos_penalty(h, 0);
if (three_prime_base < target_begin) {
h->position_penalty = target_begin - three_prime_base - 1;
} else {
h->position_penalty = three_prime_base - target_begin + 1;
inside_flag = 1;
}
}
} else { /* OT_RIGHT == o_type */
if (three_prime_base >= target_begin) {
bf_set_infinite_pos_penalty(h, 0);
if (three_prime_base > target_end) {
h->position_penalty = three_prime_base - target_end - 1;
} else {
h->position_penalty = target_end - three_prime_base + 1;
inside_flag = 1;
}
}
}
if (!inside_flag) {
h->position_penalty *= pa->outside_penalty;
} else {
h->position_penalty *= pa->inside_penalty;
}
}
/*
* Return 1 if 'pair' spans any target (in sa->tar); otherwise return 0; An
* oligo pair spans a target, t, if the last base of the left primer is to
* left of the last base of t and the first base of the right primer is to
* the right of the first base of t. Of course the primers must
* still be in a legal position with respect to each other.
*/
static int
pair_spans_target(
const primer_pair* pair,
const seq_args_t* sa
) {
int i;
int last_of_left = pair->left->start + pair->left->length - 1;
int first_of_right = pair->right->start - pair->right->length + 1;
int target_first, target_last;
for (i = 0; i < sa->tar2.count; i++) {
target_first = sa->tar2.pairs[i][0];
target_last = target_first + sa->tar2.pairs[i][1] - 1;
if (
(last_of_left <= target_last) &&
(first_of_right >= target_first) &&
(last_of_left < first_of_right)
) {
return 1;
}
}
return 0;
}
/*
* Return the value of the objective function value for given primer pair.
* We must know that the pair is acceptable before calling obj_fn.
*/
static double
obj_fn(
const p3_global_settings* pa,
primer_pair* h
) {
double sum;
double lower_tm;
sum = 0.0;
lower_tm = h->right->temp;
if (h->left->temp < h->right->temp) {
lower_tm = h->left->temp;
}
if (pa->pr_pair_weights.primer_quality) { /* HERE 1 */
sum += (
pa->pr_pair_weights.primer_quality * (h->left->quality + h->right->quality)
);
}
if (
(pa->pr_pair_weights.io_quality) &&
(pa->pick_right_primer) &&
(pa->pick_left_primer) &&
(pa->pick_internal_oligo)
) {
sum += pa->pr_pair_weights.io_quality * h->intl->quality;
}
if (pa->pr_pair_weights.diff_tm) {
sum += pa->pr_pair_weights.diff_tm * h->diff_tm;
}
if (pa->thermodynamic_oligo_alignment == 0) {
if (pa->pr_pair_weights.compl_any) {
sum += pa->pr_pair_weights.compl_any * h->compl_any;
}
if (pa->pr_pair_weights.compl_end) {
sum += pa->pr_pair_weights.compl_end * h->compl_end;
}
} else if (pa->thermodynamic_oligo_alignment == 1) {
if (
(pa->pr_pair_weights.compl_any_th) &&
((lower_tm - pa->pr_pair_weights.temp_cutoff) <= h->compl_any)
) {
sum += (
pa->pr_pair_weights.compl_any_th * (h->compl_any - (lower_tm - pa->pr_pair_weights.temp_cutoff - 1.0))
);
}
if (
(pa->pr_pair_weights.compl_any_th) &&
((lower_tm - pa->pr_pair_weights.temp_cutoff) > h->compl_any)
) {
sum +=(
pa->pr_pair_weights.compl_any_th * (1 / (lower_tm - pa->pr_pair_weights.temp_cutoff + 1.0 - h->compl_any))
);
}
if (
(pa->pr_pair_weights.compl_end_th) &&
((lower_tm - pa->pr_pair_weights.temp_cutoff) <= h->compl_end)
) {
sum += (
pa->pr_pair_weights.compl_end_th * (h->compl_end - (lower_tm - pa->pr_pair_weights.temp_cutoff - 1.0))
);
}
if (
(pa->pr_pair_weights.compl_end_th) &&
((lower_tm - pa->pr_pair_weights.temp_cutoff) > h->compl_end)
) {
sum += (
pa->pr_pair_weights.compl_end_th * (1 / (lower_tm - pa->pr_pair_weights.temp_cutoff + 1.0 - h->compl_end))
);
}
} else {
PR_ASSERT(0);
/* Programming error */
}
if (pa->pr_pair_weights.product_tm_lt && h->product_tm < pa->product_opt_tm) {
sum += pa->pr_pair_weights.product_tm_lt *
(pa->product_opt_tm - h->product_tm);
}
if (pa->pr_pair_weights.product_tm_gt && h->product_tm > pa->product_opt_tm) {
sum += pa->pr_pair_weights.product_tm_gt *
(h->product_tm - pa->product_opt_tm);
}
if (pa->pr_pair_weights.product_size_lt &&
h->product_size < pa->product_opt_size) {
sum += pa->pr_pair_weights.product_size_lt *
(pa->product_opt_size - h->product_size);
}
if (pa->pr_pair_weights.product_size_gt &&
h->product_size > pa->product_opt_size) {
sum += pa->pr_pair_weights.product_size_gt *
(h->product_size - pa->product_opt_size);
}
if (pa->pr_pair_weights.repeat_sim) {
sum += pa->pr_pair_weights.repeat_sim * h->repeat_sim;
}
if (pa->pr_pair_weights.template_mispriming && pa->thermodynamic_template_alignment==0) {
PR_ASSERT(pa->pr_pair_weights.template_mispriming >= 0.0);
PR_ASSERT(h->template_mispriming >= 0.0);
sum += pa->pr_pair_weights.template_mispriming * h->template_mispriming;
}
if (pa->pr_pair_weights.template_mispriming_th && pa->thermodynamic_template_alignment==1) {
PR_ASSERT(pa->pr_pair_weights.template_mispriming_th >= 0.0);
PR_ASSERT(h->template_mispriming >= 0.0);
if ((lower_tm - pa->pr_pair_weights.temp_cutoff) <= h->template_mispriming) {
sum += pa->pr_pair_weights.template_mispriming_th *
(h->template_mispriming - (lower_tm - pa->pr_pair_weights.temp_cutoff - 1.0));
}
if ((lower_tm - pa->pr_pair_weights.temp_cutoff) > h->template_mispriming) {
sum += pa->pr_pair_weights.template_mispriming_th *
(1/(lower_tm - pa->pr_pair_weights.temp_cutoff + 1.0 - h->template_mispriming));
}
}
PR_ASSERT(sum >= 0.0);
return sum;
}
static double
align(
const char* s1,
const char* s2,
const dpal_args* a
) {
dpal_results r;
if (a->flag == DPAL_LOCAL || a->flag == DPAL_LOCAL_END) {
if ((int)strlen(s2) < 3) {
/* For extremely short alignments we simply
max out the score, because the dpal subroutines
for these cannot handle this case.
TO DO: this can probably be corrected in dpal. */
return (int)strlen(s2);
}
}
dpal((const unsigned char*) s1, (const unsigned char*) s2, a, DPM_FAST, &r);
PR_ASSERT(r.score <= SHRT_MAX);
if (r.score == DPAL_ERROR_SCORE) {
/* There was an error. */
if (errno == ENOMEM) {
longjmp(_jmp_buf, 1);
} else {
/* This branch is taken only if there is a programming error, in
that s1 or s2 were NULL or contained an illegal character. We
try to print some debugging information before aborting. */
fprintf(stderr, "%s", r.msg);
/* Always false, causes an abort: */
PR_ASSERT(r.score != DPAL_ERROR_SCORE);
}
}
return ((r.score < 0.0) ? 0.0 : r.score / PR_ALIGN_SCORE_PRECISION);
}
/* Helper function */
static int
_set_string(
char** loc,
const char* new_string
) {
if (*loc) {
free(*loc);
*loc = NULL;
}
if (!(*loc = (char*) malloc(
(int) strlen(new_string) + 1)
)
) {
return 1; /* ENOMEM */
}
strcpy(*loc, new_string);
return 0;
}
static double
align_thermod(
const char* s1,
const char* s2,
const thal_args* a,
thal_arg_holder* thal_arg_to_use
) {
int thal_trace=0;
thal_results r;
thal(
(const unsigned char*) s1,
(const unsigned char*) s2,
a,
THL_FAST,
&r,
DO_PRINTOUT
);
if (thal_trace) {
fprintf(
stdout,
"thal, thal_args, type=%d maxLoop=%d mv=%f dv=%f "
"dntp=%f dna_conc=%f, temp=%f, mode=%d dimer=%d\n",
a->type, a->maxLoop, a->mv, a->dv, a->dntp, a->dna_conc,
a->temp, DPM_FAST, a->dimer
);
fprintf(
stdout,
"thal: s1=%s s2=%s temp=%f msg=%s end1=%d end2=%d\n",
s1, s2, r.temp, r.msg, r.align_end_1, r.align_end_2
);
}
PR_ASSERT(r.temp <= DBL_MAX);
if (r.temp == THAL_ERROR_SCORE) {
/* There was an error. */
if (errno == ENOMEM) {
longjmp(_jmp_buf, 1);
} else {
/* This branch is taken if there is an error other than
ENOMEM, in which case we treat it as a per sequence error.
*/
/* Save the error string */
if (
!_set_string(
&(thal_arg_to_use->thermodynamic_alignment_length_error_msg),
r.msg
)
) {
thal_arg_to_use->thermodynamic_alignment_length_error = 1;
}
longjmp(_jmp_buf, 1);
}
}
return ((r.temp < 0.0) ? 0.0 : (double) (r.temp));
}
/* Free the secondary structure strings for selected primers */
void
destroy_secundary_structures(
const p3_global_settings* pa,
p3retval* retval
) {
/* Pointers for the primer set just printing */
int num_print;
if ((pa == NULL) || (retval == NULL)) {
return;
}
/* Do we have a list of primers or pairs? */
if (retval->output_type == primer_list) {
/* For Primer Lists: Figure out how many primers are in
* the array that can be printed. If more than needed,
* set it to the number requested. */
/* Get how may primers should be max. printed */
num_print = pa->num_return;
if (num_print > retval->fwd.num_elem) {
num_print = retval->fwd.num_elem;
}
for (int i = 0 ; i < num_print ; i++) {
destroy_primer_sec_struct(
&retval->fwd.oligo[i]
);
}
num_print = pa->num_return;
if (num_print > retval->rev.num_elem) {
num_print = retval->rev.num_elem;
}
for (int i = 0 ; i < num_print ; i++) {
destroy_primer_sec_struct(
&retval->rev.oligo[i]
);
}
num_print = pa->num_return;
if (num_print > retval->intl.num_elem) {
num_print = retval->intl.num_elem;
}
for (int i = 0 ; i < num_print ; i++) {
destroy_primer_sec_struct(
&retval->intl.oligo[i]
);
}
} else {
/* Get how may primers should be max. printed */
num_print = retval->best_pairs.num_pairs;
for (int i = 0 ; i < num_print ; i++) {
destroy_primer_sec_struct(
retval->best_pairs.pairs[i].left
);
destroy_primer_sec_struct(
retval->best_pairs.pairs[i].right
);
destroy_pair_sec_struct(
&retval->best_pairs.pairs[i]
);
if (retval->intl.num_elem > 0) {
destroy_primer_sec_struct(
retval->best_pairs.pairs[i].intl
);
}
}
}
}
void
destroy_primer_sec_struct(
primer_rec* p_rec
) {
if (NULL == p_rec) { return; }
if (p_rec->self_any_struct != NULL) {
free(p_rec->self_any_struct);
p_rec->self_any_struct = NULL;
}
if (p_rec->self_end_struct != NULL) {
free(p_rec->self_end_struct);
p_rec->self_end_struct = NULL;
}
if (p_rec->hairpin_struct != NULL) {
free(p_rec->hairpin_struct);
p_rec->hairpin_struct = NULL;
}
}
void
destroy_pair_sec_struct(
primer_pair* ppair
) {
if (NULL == ppair) { return; }
if (ppair->compl_any_struct != NULL) {
free(ppair->compl_any_struct);
ppair->compl_any_struct = NULL;
}
if (ppair->compl_end_struct != NULL) {
free(ppair->compl_end_struct);
ppair->compl_end_struct = NULL;
}
}
void
save_overwrite_sec_struct(
char** base,
char* inp
) {
if (*base != NULL) {
free(*base);
}
*base = inp;
}
/* Calculate the secondary structures for selected primers */
void
recalc_secundary_structures(
const p3_global_settings* pa,
const seq_args_t* sa,
const dpal_arg_holder* dpal_arg_to_use,
const thal_arg_holder* thal_arg_to_use,
const thal_arg_holder* thal_oligo_arg_to_use,
p3retval* retval
) {
/* Pointers for the primer set just printing */
int num_print;
/* Do we have a list of primers or pairs? */
if (retval->output_type == primer_list) {
/* For Primer Lists: Figure out how many primers are in
* the array that can be printed. If more than needed,
* set it to the number requested. */
/* Get how may primers should be max. printed */
num_print = pa->num_return;
if (num_print > retval->fwd.num_elem) {
num_print = retval->fwd.num_elem;
}
for (int i = 0 ; i < num_print ; i++) {
recalc_primer_sec_struct(
&retval->fwd.oligo[i],
0,
pa,
sa,
dpal_arg_to_use,
thal_arg_to_use
);
}
num_print = pa->num_return;
if (num_print > retval->rev.num_elem) {
num_print = retval->rev.num_elem;
}
for (int i = 0 ; i < num_print ; i++) {
recalc_primer_sec_struct(
&retval->rev.oligo[i],
1,
pa,
sa,
dpal_arg_to_use,
thal_arg_to_use
);
}
num_print = pa->num_return;
if (num_print > retval->intl.num_elem) {
num_print = retval->intl.num_elem;
}
for (int i = 0 ; i < num_print ; i++) {
recalc_primer_sec_struct(
&retval->intl.oligo[i],
2,
pa,
sa,
dpal_arg_to_use,
thal_oligo_arg_to_use
);
}
} else {
/* Get how may primers should be max. printed */
num_print = retval->best_pairs.num_pairs;
for (int i = 0 ; i < num_print ; i++) {
recalc_primer_sec_struct(
retval->best_pairs.pairs[i].left,
0,
pa,
sa,
dpal_arg_to_use,
thal_arg_to_use
);
recalc_primer_sec_struct(
retval->best_pairs.pairs[i].right,
1,
pa,
sa,
dpal_arg_to_use,
thal_arg_to_use
);
recalc_pair_sec_struct(
&retval->best_pairs.pairs[i],
pa,
sa,
dpal_arg_to_use,
thal_arg_to_use
);
if (retval->intl.num_elem > 0) {
recalc_primer_sec_struct(
retval->best_pairs.pairs[i].intl,
2,
pa,
sa,
dpal_arg_to_use,
thal_oligo_arg_to_use
);
}
}
}
}
/* This functions overwrite the any/end values to report discrepancies for debugging.*/
void
recalc_primer_sec_struct(
primer_rec* p_rec,
const int primer_type, /* left 0, right 1, intl 2 */
const p3_global_settings* pa,
const seq_args_t* sa,
const dpal_arg_holder* dpal_arg_to_use,
const thal_arg_holder* thal_arg_to_use
) {
char s1[THAL_MAX_ALIGN+1], s1_rev[THAL_MAX_ALIGN+1];
int overhang_len;
/* s1 is the forward oligo. */
if (primer_type == 0) { /* left */
if (NULL != sa->overhang_left) {
overhang_len = strlen(sa->overhang_left);
strcpy(s1, sa->overhang_left);
_pr_shift_substr(
sa->trimmed_seq,
p_rec->start,
p_rec->length,
overhang_len,
s1
);
} else {
_pr_substr(
sa->trimmed_seq,
p_rec->start,
p_rec->length,
s1
);
}
p3_reverse_complement(s1, s1_rev);
} else if (primer_type == 2) { /* intl */
_pr_substr(
sa->trimmed_seq,
p_rec->start,
p_rec->length,
s1
);
p3_reverse_complement(s1, s1_rev);
} else { /* right */
_pr_substr(
sa->trimmed_seq,
p_rec->start - p_rec->length + 1,
p_rec->length,
s1_rev
);
if (NULL != sa->overhang_right) {
overhang_len = strlen(sa->overhang_right);
_pr_shift_substr(
sa->overhang_right_rv,
0,
overhang_len,
p_rec->length,
s1_rev
);
} else {
_pr_substr(
sa->trimmed_seq,
p_rec->start - p_rec->length + 1,
p_rec->length,
s1_rev
);
}
p3_reverse_complement(s1_rev, s1);
}
if (pa->thermodynamic_oligo_alignment==0) {
dpal_results any, end;
/* NOTE: important to set these values to NULL to prevent segfaults */
any.sec_struct = NULL;
end.sec_struct = NULL;
if (p_rec->self_any > 0.0) {
dpal(
(const unsigned char*) s1,
(const unsigned char*) s1_rev,
dpal_arg_to_use->local,
DPM_STRUCT,
&any
);
p_rec->self_any = any.score / PR_ALIGN_SCORE_PRECISION;
save_overwrite_sec_struct(
&p_rec->self_any_struct,
any.sec_struct
);
}
if (p_rec->self_end > 0.0) {
dpal(
(const unsigned char*) s1,
(const unsigned char*) s1_rev,
dpal_arg_to_use->end,
DPM_STRUCT,
&end
);
p_rec->self_end = end.score / PR_ALIGN_SCORE_PRECISION;
save_overwrite_sec_struct(
&p_rec->self_end_struct,
end.sec_struct
);
}
}
/* Thermodynamic approach, fwd-primer */
if (pa->thermodynamic_oligo_alignment==1) {
thal_results any, end, hair;
/* NOTE: important to set these values to NULL to prevent segfaults */
any.sec_struct = NULL;
end.sec_struct = NULL;
hair.sec_struct = NULL;
if (p_rec->self_any > 0.0 ) {
thal(
(const unsigned char*) s1,
(const unsigned char*) s1,
thal_arg_to_use->any,
THL_STRUCT,
&any,
DO_PRINTOUT
);
p_rec->self_any = any.temp;
save_overwrite_sec_struct(
&p_rec->self_any_struct,
any.sec_struct
);
}
if (p_rec->self_end > 0.0) {
thal(
(const unsigned char*) s1,
(const unsigned char*) s1,
thal_arg_to_use->end1,
THL_STRUCT,
&end,
DO_PRINTOUT
);
p_rec->self_end = end.temp;
save_overwrite_sec_struct(
&p_rec->self_end_struct,
end.sec_struct
);
}
if (p_rec->hairpin_th > 0.0 ) {
thal(
(const unsigned char*) s1,
(const unsigned char*) s1,
thal_arg_to_use->hairpin_th,
THL_STRUCT,
&hair,
DO_PRINTOUT
);
p_rec->hairpin_th = hair.temp;
save_overwrite_sec_struct(
&p_rec->hairpin_struct,
hair.sec_struct
);
}
}
}
void
recalc_pair_sec_struct(
primer_pair* ppair,
const p3_global_settings* pa,
const seq_args_t* sa,
const dpal_arg_holder* dpal_arg_to_use,
const thal_arg_holder* thal_arg_to_use
) {
char s1[THAL_MAX_ALIGN+1], s1_rev[THAL_MAX_ALIGN+1];
char s2[THAL_MAX_ALIGN+1], s2_rev[THAL_MAX_ALIGN+1];
int overhang_len;
/* s1 is the forward oligo. */
if (sa->overhang_left != NULL) {
overhang_len = strlen(sa->overhang_left);
strcpy(
s1,
sa->overhang_left
);
_pr_shift_substr(
sa->trimmed_seq,
ppair->left->start,
ppair->left->length,
overhang_len,
s1
);
} else {
_pr_substr(
sa->trimmed_seq,
ppair->left->start,
ppair->left->length,
s1
);
}
/* s2 is the reverse oligo. */
_pr_substr(
sa->trimmed_seq,
ppair->right->start - ppair->right->length + 1,
ppair->right->length,
s2
);
if (sa->overhang_right != NULL) {
overhang_len = strlen(sa->overhang_right);
_pr_shift_substr(
sa->overhang_right_rv,
0,
overhang_len,
ppair->right->length,
s2
);
}
p3_reverse_complement(s1, s1_rev);
p3_reverse_complement(s2, s2_rev);
if (pa->thermodynamic_oligo_alignment==0) {
dpal_results any, end, end2;
end2.sec_struct = NULL;
if (ppair->compl_any > 0.0) {
dpal(
(const unsigned char*) s1,
(const unsigned char*) s2,
dpal_arg_to_use->local,
DPM_STRUCT,
&any
);
ppair->compl_any = any.score / PR_ALIGN_SCORE_PRECISION;
save_overwrite_sec_struct(
&ppair->compl_any_struct,
any.sec_struct
);
}
if (ppair->compl_end > 0.0) {
dpal(
(const unsigned char*) s1,
(const unsigned char*) s2,
dpal_arg_to_use->end,
DPM_STRUCT,
&end
);
ppair->compl_end = end.score / PR_ALIGN_SCORE_PRECISION;
save_overwrite_sec_struct(
&ppair->compl_end_struct,
end.sec_struct
);
dpal(
(const unsigned char*) s2_rev,
(const unsigned char*) s1_rev,
dpal_arg_to_use->end,
DPM_STRUCT,
&end2
);
if (end2.score / PR_ALIGN_SCORE_PRECISION > ppair->compl_end){
ppair->compl_end = end2.score / PR_ALIGN_SCORE_PRECISION;
save_overwrite_sec_struct(
&ppair->compl_end_struct,
end2.sec_struct
);
} else {
if (end2.sec_struct != NULL) {
free(end2.sec_struct);
end2.sec_struct = NULL;
}
}
}
} else {
/* thermodynamical approach */
thal_results any, end1, end2, end3, end4;
any.sec_struct = NULL;
end1.sec_struct = NULL;
end2.sec_struct = NULL;
end3.sec_struct = NULL;
end4.sec_struct = NULL;
if (ppair->compl_any > 0.0) {
thal(
(const unsigned char*) s1,
(const unsigned char*) s2_rev,
thal_arg_to_use->any,
THL_STRUCT,
&any,
DO_PRINTOUT
);
ppair->compl_any = any.temp;
save_overwrite_sec_struct(
&ppair->compl_any_struct,
any.sec_struct
);
}
if (ppair->compl_end > 0.0) {
thal(
(const unsigned char*) s1,
(const unsigned char*) s2_rev,
thal_arg_to_use->end1,
THL_STRUCT,
&end1,
DO_PRINTOUT
);
ppair->compl_end = end1.temp;
save_overwrite_sec_struct(
&ppair->compl_end_struct,
end1.sec_struct
);
thal(
(const unsigned char*) s1,
(const unsigned char*) s2_rev,
thal_arg_to_use->end2,
THL_STRUCT,
&end2,
DO_PRINTOUT
); /* Triinu Please check */
if (ppair->compl_end < end2.temp) {
ppair->compl_end = end2.temp;
save_overwrite_sec_struct(
&ppair->compl_end_struct,
end2.sec_struct
);
} else {
if (end2.sec_struct != NULL) {
free(end2.sec_struct);
end2.sec_struct = NULL;
}
}
thal(
(const unsigned char*) s2,
(const unsigned char*) s1_rev,
thal_arg_to_use->end1,
THL_STRUCT,
&end3,
DO_PRINTOUT
);
if (ppair->compl_end < end3.temp) {
ppair->compl_end = end3.temp;
save_overwrite_sec_struct(
&ppair->compl_end_struct,
end3.sec_struct
);
} else {
if (end3.sec_struct != NULL) {
free(end3.sec_struct);
end3.sec_struct = NULL;
}
}
thal(
(const unsigned char*) s2,
(const unsigned char*) s1_rev,
thal_arg_to_use->end2,
THL_STRUCT,
&end4,
DO_PRINTOUT
); /* Triinu Please check */
if (ppair->compl_end < end4.temp) {
ppair->compl_end = end4.temp;
save_overwrite_sec_struct(
&ppair->compl_end_struct,
end4.sec_struct
);
} else {
if (end4.sec_struct != NULL) {
free(end4.sec_struct);
end4.sec_struct = NULL;
}
}
}
}
}
/* Return the sequence of oligo in
a ****static***** buffer. The
sequence returned is changed at the
next call to pr_oligo_sequence. */
char*
pr_oligo_overhang_sequence(
const seq_args_t* sa,
const primer_rec* oligo
) {
static char s[THAL_MAX_ALIGN+1];
int seq_len, overhang_len;
PR_ASSERT(NULL != sa);
PR_ASSERT(NULL != oligo);
seq_len = strlen(sa->sequence);
if (NULL != sa->overhang_left) {
overhang_len = strlen(sa->overhang_left);
_pr_substr(
sa->overhang_left,
0,
overhang_len,
s
);
} else {
overhang_len = 0;
}
PR_ASSERT(oligo->start + sa->incl_s >= 0);
PR_ASSERT(oligo->start + sa->incl_s + oligo->length <= seq_len);
_pr_shift_substr(
sa->sequence,
sa->incl_s + oligo->start,
oligo->length,
overhang_len,
s
);
return &s[0];
}
char*
pr_oligo_sequence(
const seq_args_t* sa,
const primer_rec* oligo
) {
static char s[THAL_MAX_ALIGN+1];
int seq_len;
PR_ASSERT(NULL != sa);
PR_ASSERT(NULL != oligo);
seq_len = (int)strlen(sa->sequence);
PR_ASSERT(oligo->start + sa->incl_s >= 0);
PR_ASSERT(oligo->start + sa->incl_s + oligo->length <= seq_len);
_pr_substr(
sa->sequence,
sa->incl_s + oligo->start,
oligo->length,
s
);
return &s[0];
}
char*
pr_oligo_rev_c_overhang_sequence(
const seq_args_t* sa,
const primer_rec* o
) {
static char s[THAL_MAX_ALIGN+1], s1[THAL_MAX_ALIGN+1];
int seq_len, start, overhang_len;
PR_ASSERT(NULL != sa);
PR_ASSERT(NULL != o);
seq_len = strlen(sa->sequence);
start = sa->incl_s + o->start - o->length + 1;
PR_ASSERT(start >= 0);
PR_ASSERT(start + o->length <= seq_len);
_pr_substr(
sa->sequence,
start,
o->length,
s
);
p3_reverse_complement(s, s1);
if (NULL != sa->overhang_right) {
overhang_len = strlen(sa->overhang_right);
_pr_substr(
sa->overhang_right,
0,
overhang_len,
s
);
} else {
overhang_len = 0;
}
_pr_shift_substr(
s1,
0,
o->length,
overhang_len,
s
);
return &s[0];
}
char*
pr_oligo_rev_c_sequence(
const seq_args_t* sa,
const primer_rec* o
) {
static char s[THAL_MAX_ALIGN+1], s1[THAL_MAX_ALIGN+1];
int seq_len, start;
PR_ASSERT(NULL != sa);
PR_ASSERT(NULL != o);
seq_len = (int)strlen(sa->sequence);
start = sa->incl_s + o->start - o->length + 1;
PR_ASSERT(start >= 0);
PR_ASSERT(start + o->length <= seq_len);
_pr_substr(sa->sequence, start, o->length, s);
p3_reverse_complement(s,s1);
return &s1[0];
}
/* Calculate self complementarity (both h->self_any and h->self_end)
which we use as an approximation for both secondary structure and
self primer-dimer. */
static void
oligo_compl(
primer_rec* h,
const args_for_one_oligo_or_primer* po_args,
oligo_stats* ostats,
const dpal_arg_holder* dpal_arg_to_use,
const char* oligo_seq,
const char* revc_oligo_seq
) {
PR_ASSERT(h != NULL);
h->self_any = align(
oligo_seq,
revc_oligo_seq,
dpal_arg_to_use->local
);
if (h->self_any > po_args->max_self_any) {
op_set_high_self_any(h);
ostats->compl_any++;
ostats->ok--;
if (!h->must_use) { return; }
}
h->self_end = align(
oligo_seq,
revc_oligo_seq,
dpal_arg_to_use->end
);
if (h->self_end > po_args->max_self_end) {
op_set_high_self_end(h);
ostats->compl_end++;
ostats->ok--;
if (!h->must_use) { return; }
}
}
static void
oligo_compl_thermod(
primer_rec* h,
const args_for_one_oligo_or_primer* po_args,
oligo_stats* ostats,
const thal_arg_holder* thal_arg_to_use,
const char* oligo_seq,
const char* revc_oligo_seq
) {
PR_ASSERT(h != NULL);
h->self_any = align_thermod(
oligo_seq,
revc_oligo_seq,
thal_arg_to_use->any,
(thal_arg_holder*) thal_arg_to_use
);
if (h->self_any > po_args->max_self_any_th) {
op_set_high_self_any(h);
ostats->compl_any++;
ostats->ok--;
if (!h->must_use) { return; }
}
h->self_end = align_thermod(
oligo_seq,
revc_oligo_seq,
thal_arg_to_use->end1,
(thal_arg_holder*) thal_arg_to_use
);
if (h->self_end > po_args->max_self_end_th) {
op_set_high_self_end(h);
ostats->compl_end++;
ostats->ok--;
if (!h->must_use) { return; }
}
}
static void
oligo_hairpin(
primer_rec* h,
const args_for_one_oligo_or_primer* po_args,
oligo_stats* ostats,
const thal_arg_holder* thal_arg_to_use,
const char* oligo_seq
) {
PR_ASSERT(h != NULL);
h->hairpin_th = align_thermod(
oligo_seq,
oligo_seq,
thal_arg_to_use->hairpin_th,
(thal_arg_holder*) thal_arg_to_use
);
if (h->hairpin_th > po_args->max_hairpin_th) {
op_set_high_hairpin_th(h);
ostats->hairpin_th++;
ostats->ok--;
return;
}
}
static void
primer_mispriming_to_template(
primer_rec* h,
const p3_global_settings* pa,
const seq_args_t* sa,
oligo_type l,
oligo_stats* ostats,
int first,
int last,
/* The oligo sequence: */
const char* s,
/* s reverse complemented: */
const char* s_r,
const dpal_args* align_args
) {
const char* oseq;
char*target, *target_r;
int tmp, seqlen;
int debug = 0;
int first_untrimmed, last_untrimmed;
/* Indexes of first and last bases of the oligo in sa->seq,
that is, WITHIN THE TOTAL SEQUENCE INPUT. */
/* first, last are indexes of first and last bases of the oligo in
sa->trimmed_seq, that is, WITHIN THE INCLUDED REGION. */
char tmp_char;
double tmp_score;
seqlen = (int) strlen(sa->upcased_seq);
first_untrimmed = sa->incl_s + first;
last_untrimmed = sa->incl_s + last;
if (l == OT_LEFT) {
oseq = &s[0];
target = &sa->upcased_seq[0];
target_r = &sa->upcased_seq_r[0];
} else { /* l == OT_RIGHT */
if (debug) {
fprintf(
stderr,
"first_untrimmed = %d, last_untrimmed = %d\n",
first_untrimmed, last_untrimmed
);
}
oseq = &s_r[0];
target = &sa->upcased_seq_r[0];
target_r = &sa->upcased_seq[0];
/* We need to adjust first_untrimmed and last_untrimmed so that
they are correct in the reverse-complemented
sequence.
*/
tmp = (seqlen - last_untrimmed) - 1;
last_untrimmed = (seqlen - first_untrimmed) - 1;
first_untrimmed = tmp;
}
/* 1. Align to the template 5' of the oligo. */
tmp_char = target[first_untrimmed];
target[first_untrimmed] = '\0';
tmp_score = align(oseq, target, align_args);
if (debug) {
if (l == OT_LEFT) {
fprintf(
stderr,
"\n************ OLIGO = LEFT\n"
);
} else {
fprintf(
stderr,
"\n************ OLIGO = RIGHT\n");
}
fprintf(
stderr,
"first_untrimmed = %d, last_untrimmed = %d,first = %d, last = %d\n",
first_untrimmed, last_untrimmed, first, last
);
fprintf(
stderr,
"5' of oligo: Score %f aligning %s against %s\n\n",
tmp_score, oseq, target
);
}
target[first_untrimmed] = tmp_char;
/* 2. Align to the template 3' of the oligo. */
h->template_mispriming = align(
oseq,
&target[0] + last_untrimmed + 1,
align_args
);
if (debug) {
fprintf(
stderr,
"3' of oligo Score %f aligning %s against %s\n\n",
h->template_mispriming, oseq, &target[0] + last_untrimmed + 1
);
}
/* 3. Take the max of 1. and 2. */
if (tmp_score > h->template_mispriming) {
h->template_mispriming = tmp_score;
}
/* 4. Align to the reverse strand of the template. */
h->template_mispriming_r
= align(oseq, target_r, align_args);
if (debug) {
fprintf(
stderr,
"other strand Score %f aligning %s against %s\n\n",
h->template_mispriming_r, oseq, target_r
);
}
if (pa->p_args.max_template_mispriming >= 0) {
if (
oligo_max_template_mispriming(h) > pa->p_args.max_template_mispriming
) {
op_set_high_similarity_to_multiple_template_sites(h);
if ((OT_LEFT == l) || (OT_RIGHT == l)) {
ostats->template_mispriming++;
ostats->ok--;
} else PR_ASSERT(0); /* Should not get here. */
} else {
/* This oligo is ok, mark it so we do not do this check again. */
h->template_mispriming_ok = 1;
}
}
}
static void
primer_mispriming_to_template_thermod(
primer_rec* h,
const p3_global_settings* pa,
const seq_args_t* sa,
oligo_type l,
oligo_stats* ostats,
int first,
int last,
/* The oligo sequence: */
const char* s,
/* s reverse complemented: */
const char* s_r,
const thal_args* align_args,
thal_arg_holder* thal_arg_to_use
) {
const char* oseq;
char*target, *target_r;
int tmp, seqlen;
int debug = 0;
int first_untrimmed, last_untrimmed;
/* Indexes of first and last bases of the oligo in sa->seq,
* that is, WITHIN THE TOTAL SEQUENCE INPUT. */
/* first, last are indexes of first and last bases of the oligo in
* sa->trimmed_seq, that is, WITHIN THE INCLUDED REGION. */
char tmp_char;
double tmp_score;
seqlen = (int) strlen(sa->upcased_seq);
first_untrimmed = sa->incl_s + first;
last_untrimmed = sa->incl_s + last;
if (l == OT_RIGHT) {
oseq = &s_r[0];
target = &sa->upcased_seq[0];
target_r = &sa->upcased_seq_r[0];
} else { /* l == OT_RIGHT */
if (debug) {
fprintf(
stdout,
"first_untrimmed = %d, last_untrimmed = %d\n",
first_untrimmed, last_untrimmed
);
}
oseq = &s[0];
target = &sa->upcased_seq_r[0];
target_r = &sa->upcased_seq[0];
/* We need to adjust first_untrimmed and last_untrimmed so that
* they are correct in the reverse-complemented
* sequence.
* */
tmp = (seqlen - last_untrimmed) - 1;
last_untrimmed = (seqlen - first_untrimmed) - 1;
first_untrimmed = tmp;
}
/* 1. Align to the template 5' of the oligo. */
/* tmp_char = target_r[first_untrimmed]; Corrected 2012-05-30 */
tmp_char = target[first_untrimmed];
target[first_untrimmed] = '\0';
tmp_score = align_thermod(
oseq,
target,
align_args,
(thal_arg_holder*) thal_arg_to_use
);
if (debug) {
if (l == OT_LEFT) {
fprintf(
stdout,
"\n************ OLIGO = LEFT\n"
);
} else {
fprintf(
stdout,
"\n************ OLIGO = RIGHT\n"
);
}
fprintf(
stdout,
"first_untrimmed = %d, last_untrimmed = %d, first = %d, last = %d\n",
first_untrimmed, last_untrimmed, first, last
);
fprintf(
stdout,
"5' of oligo: Score %f aligning %s against %s\n\n",
tmp_score, oseq, target
);
}
target[first_untrimmed] = tmp_char;
/* 2. Align to the template 3' of the oligo. */
h->template_mispriming = align_thermod(
oseq,
&target[0] + last_untrimmed + 1,
align_args,
(thal_arg_holder*) thal_arg_to_use
);
if (debug) {
fprintf(
stdout,
"3' of oligo Score %f aligning %s against %s\n\n",
h->template_mispriming, oseq, &target[0] + last_untrimmed + 1
);
}
/* 3. Take the max of 1. and 2. */
if (tmp_score > h->template_mispriming) {
h->template_mispriming = tmp_score;
}
/* 4. Align to the reverse strand of the template. */
h->template_mispriming_r = align_thermod(
oseq,
target_r,
align_args,
(thal_arg_holder*) thal_arg_to_use
);
if (debug) {
fprintf(
stdout,
"In primer_mispriming_to_template_thermod\n"
" other strand Score %f aligning %s against %s\n\n",
h->template_mispriming_r, oseq, target_r
);
}
if (pa->p_args.max_template_mispriming_th >= 0) {
if (
oligo_max_template_mispriming_thermod(h) > pa->p_args.max_template_mispriming_th
) {
op_set_high_similarity_to_multiple_template_sites(h);
if ((OT_LEFT == l) || (OT_RIGHT == l) ) {
ostats->template_mispriming++;
ostats->ok--;
} else { PR_ASSERT(0); } /* Should not get here. */
} else {
/* This oligo is ok, mark it so we do not do this check again. */
h->template_mispriming_ok = 1;
}
}
}
static void
oligo_compute_sequence_and_reverse(
primer_rec* h,
const seq_args_t* sa,
oligo_type l,
int* first,
int* last,
char* s,
char* s_r
) {
*first = (OT_LEFT == l || OT_INTL == l)
? h->start
: h->start - h->length + 1;
*last = (OT_LEFT == l || OT_INTL == l)
? h->start + h->length - 1
: h->start;
_pr_substr(
sa->trimmed_seq,
*first,
h->length,
s
);
p3_reverse_complement(s, s_r);
}
/* Possible improvement -- pass in the oligo sequences */
static void
oligo_repeat_library_mispriming(
primer_rec* h,
const p3_global_settings* pa,
const seq_args_t* sa,
oligo_type l,
oligo_stats* ostats,
const dpal_arg_holder* dpal_arg_to_use,
pr_append_str* error
) {
char s[MAX_PRIMER_LENGTH+1]; /* Will contain the oligo sequence. */
char s_r[MAX_PRIMER_LENGTH+1]; /* Will contain s reverse complemented. */
double w;
const seq_lib *lib;
int i;
int first, last; /* Indexes of first and last bases of the oligo in
sa->trimmed_seq, that is, WITHIN THE INCLUDED
REGION. */
int min, max;
short max_lib_compl;
/* First, check the oligo against the repeat library. */
if (OT_INTL == l) {
lib = pa->o_args.repeat_lib;
max_lib_compl = (short) pa->o_args.max_repeat_compl;
} else {
lib = pa->p_args.repeat_lib;
max_lib_compl = (short) pa->p_args.max_repeat_compl;
}
oligo_compute_sequence_and_reverse(
h,
sa,
l,
&first,
&last,
s,
s_r
);
/*
* Calculate maximum similarity to sequences from user defined repeat
* library. Compare it with maximum allowed repeat similarity.
*/
if (seq_lib_num_seq(lib) > 0) {
/* Library exists and is non-empty. */
h->repeat_sim.score = (double *) pr_safe_malloc(
lib->seq_num * sizeof(double)
);
h->repeat_sim.max = h->repeat_sim.min = 0;
max = min = 0;
h->repeat_sim.name = lib->names[0];
for (i = 0; i < lib->seq_num; i++) {
if (OT_LEFT == l) {
w = (
lib->weight[i] *
align(
s,
lib->seqs[i],
(
pa->lib_ambiguity_codes_consensus ?
dpal_arg_to_use->local_end_ambig :
dpal_arg_to_use->local_end
)
)
);
} else if (OT_INTL == l) {
w = (
lib->weight[i] *
align(
s,
lib->seqs[i],
(
pa->lib_ambiguity_codes_consensus ?
dpal_arg_to_use->local_ambig :
dpal_arg_to_use->local
)
)
);
} else {
w = (
lib->weight[i] *
align(
s_r,
lib->rev_compl_seqs[i],
(
pa->lib_ambiguity_codes_consensus ?
dpal_arg_to_use->local_end_ambig :
dpal_arg_to_use->local
)
)
);
}
if ((w > SHRT_MAX) || (w < SHRT_MIN)) {
/* This check is necessary for the next 9 lines */
pr_append_new_chunk(
error,
"Out of range error occured calculating match to repeat library"
);
return;
}
h->repeat_sim.score[i] = w;
if (w > max) {
max = (int) w;
h->repeat_sim.max = i;
h->repeat_sim.name = lib->names[i];
}
if (w < min) {
min = (int) w;
h->repeat_sim.min = i;
}
if (w > max_lib_compl) {
op_set_high_similarity_to_non_template_seq(h);
ostats->repeat_score++;
ostats->ok--;
if (!h->must_use) { return; }
} /* if w > max_lib_compl */
} /* for */
} /* if library exists and is non-empty */
/* End of checking against the repeat library */
}
/* This function carries out either the old "dpal" alignment or the
thermodynamic alignment, depending on the value of
pa->thermodynamic_template_alignment. */
static void
oligo_template_mispriming(
primer_rec* h,
const p3_global_settings* pa,
const seq_args_t* sa,
oligo_type l,
oligo_stats* ostats,
const dpal_args* d_align_args,
const thal_args* t_align_args,
thal_arg_holder* thal_arg_to_use
) {
char s[MAX_PRIMER_LENGTH+1]; /* Will contain the oligo sequence. */
char s_r[MAX_PRIMER_LENGTH+1]; /* Will contain s reverse complemented. */
int first, last; /* Indexes of first and last bases of the oligo in
sa->trimmed_seq, that is, WITHIN THE INCLUDED
REGION. */
/* Check if we already did this and the oligo was ok. */
if (h->template_mispriming_ok) {
return;
}
oligo_compute_sequence_and_reverse(
h,
sa,
l,
&first,
&last,
s,
s_r
);
/* Calculate maximum similarity to ectopic sites in the template. */
if ((l == OT_RIGHT) || (l == OT_LEFT)) {
if (
(pa->thermodynamic_template_alignment == 0) &&
(_pr_need_template_mispriming(pa))
) {
primer_mispriming_to_template(
h,
pa,
sa,
l,
ostats,
first,
last,
s,
s_r,
d_align_args
);
}
if (
(pa->thermodynamic_template_alignment == 1) &&
(_pr_need_template_mispriming_thermod(pa))
) {
primer_mispriming_to_template_thermod(
h,
pa,
sa,
l,
ostats,
first,
last,
s,
s_r,
t_align_args,
thal_arg_to_use
);
}
}
}
static int
pair_repeat_sim(
primer_pair* h,
const p3_global_settings* pa
) {
int i, n, max, w;
primer_rec* fw, *rev;
fw = h->left;
rev = h->right;
max = 0;
n = seq_lib_num_seq(pa->p_args.repeat_lib);
if (n == 0) { return 0; }
h->rep_name = pa->p_args.repeat_lib->names[0] ;
for (i = 0; i < n; i++) {
if (
(w = (int) (fw->repeat_sim.score[i] + rev->repeat_sim.score[i])) > max
) {
max = w;
h->rep_name = pa->p_args.repeat_lib->names[i] ;
}
}
return max;
}
static void
set_retval_both_stop_codons(
const seq_args_t* sa,
p3retval* retval
) {
/* The position of the intial base of the rightmost stop codon that
* is to the left of sa->start_codon_pos; valid only if
* sa->start_codon_pos is "not null". We will not want to include
* a stop codon to the right of the the start codon in the
* amplicon. */
retval->upstream_stop_codon = find_stop_codon(
sa->trimmed_seq,
sa->start_codon_pos,
-1
);
retval->upstream_stop_codon += sa->incl_s;
retval->stop_codon_pos = find_stop_codon(
sa->trimmed_seq,
sa->start_codon_pos,
1
);
retval->stop_codon_pos += sa->incl_s;
}
/*
* 's' is the sequence in which to find the stop codon.
* 'start' is the position of a start codon.
*
* There are two modes depending on 'direction'.
*
* If direction is 1:
*
* Return the index of the first stop codon to the right of
* 'start' in 's' (in same frame).
* If there is no such stop codon return -1.
*
* If direction is -1:
*
* If 'start' is negative then return -1.
* Otherwise return the index the first stop codon to left of 'start'.
* If there is no such stop codon return -1.
*
* Note: we don't insist that the start codon be ATG, since in some
* cases the caller will not have the full sequence in 's', nor even
* know the postion of the start codon relative to s.
*/
static int
find_stop_codon(
const char* s,
int start,
int direction
) {
const char* p, *q;
int increment = 3 * direction;
int len = (int)strlen(s);
PR_ASSERT(s != NULL);
PR_ASSERT(direction == 1 || direction == -1);
PR_ASSERT(len >= 3);
PR_ASSERT(start <= (len - 3));
if (start < 0) {
if (direction == 1) {
while (start < 0) { start += increment; }
} else {
return -1;
}
}
for (
p = &s[start];
(p >= &s[0]
&& *p
&& *(p + 1)
&& *(p + 2)
);
p += increment
) {
if (('T' != *p) && ('t' != *p)) { continue; }
q = p + 1;
if (('A' == *q) || ('a' == *q)) {
q++;
if (('G' == *q) || ('g' == *q) || ('A' == *q) || ('a' == *q)) {
return (int)(p - &s[0]);
}
} else if (('G' == *q )|| ('g' == *q)) {
q++;
if (('A' == *q) || ('a' == *q)) {
return (int)(p - &s[0]);
}
}
}
return -1;
}
int
strcmp_nocase(
const char* s1,
const char* s2
) {
static char M[UCHAR_MAX];
static int f = 0;
int i;
const char* p, *q;
if (f != 1){
for(i = 0; i < UCHAR_MAX; i++) M[i] = i;
i = 'a'; M[i] = 'A'; i = 'b'; M[i] = 'B'; i = 'c'; M[i] = 'C';
i = 'A'; M[i] = 'a'; i = 'B'; M[i] = 'b'; i = 'C'; M[i] = 'c';
i = 'd'; M[i] = 'D'; i = 'e'; M[i] = 'E'; i = 'f'; M[i] = 'F';
i = 'D'; M[i] = 'd'; i = 'E'; M[i] = 'e'; i = 'F'; M[i] = 'f';
i = 'g'; M[i] = 'G'; i = 'h'; M[i] = 'H'; i = 'i'; M[i] = 'I';
i = 'G'; M[i] = 'g'; i = 'H'; M[i] = 'h'; i = 'I'; M[i] = 'i';
i = 'k'; M[i] = 'K'; i = 'l'; M[i] = 'L'; i = 'm'; M[i] = 'M';
i = 'K'; M[i] = 'k'; i = 'L'; M[i] = 'l'; i = 'M'; M[i] = 'm';
i = 'n'; M[i] = 'N'; i = 'o'; M[i] = 'O'; i = 'p'; M[i] = 'P';
i = 'N'; M[i] = 'n'; i = 'O'; M[i] = 'o'; i = 'P'; M[i] = 'p';
i = 'q'; M[i] = 'Q'; i = 'r'; M[i] = 'R'; i = 's'; M[i] = 'S';
i = 'Q'; M[i] = 'q'; i = 'R'; M[i] = 'r'; i = 'S'; M[i] = 's';
i = 't'; M[i] = 'T'; i = 'u'; M[i] = 'U'; i = 'v'; M[i] = 'V';
i = 'T'; M[i] = 't'; i = 'U'; M[i] = 'u'; i = 'V'; M[i] = 'v';
i = 'w'; M[i] = 'W'; i = 'x'; M[i] = 'X'; i = 'y'; M[i] = 'Y';
i = 'W'; M[i] = 'w'; i = 'X'; M[i] = 'x'; i = 'Y'; M[i] = 'y';
i = 'z'; M[i] = 'Z'; i = 'Z'; M[i] = 'z'; i = 'j'; M[i] = 'J';
i = 'J'; M[i] = 'j';
f = 1;
}
if (s1 == NULL || s2 == NULL) { return 1; }
if ((int) strlen(s1) != (int) strlen(s2)) { return 1; }
p = s1; q = s2;
while(*p != '\0' && *p != '\n' && *q != '\0' && *q != '\n') {
i = *p;
if (*p == *q || M[i] == *q ) {p++; q++; continue;}
return 1;
}
return 0;
}
static void
free_repeat_sim_score(
p3retval* state
) {
int i;
for (i = 0; i < state->fwd.num_elem; i++) {
if (state->fwd.oligo[i].repeat_sim.score != NULL) {
free(state->fwd.oligo[i].repeat_sim.score);
state->fwd.oligo[i].repeat_sim.score = NULL;
}
}
for (i = 0; i < state->rev.num_elem; i++) {
if (state->rev.oligo[i].repeat_sim.score != NULL) {
free(state->rev.oligo[i].repeat_sim.score);
state->rev.oligo[i].repeat_sim.score = NULL;
}
}
for (i = 0; i < state->intl.num_elem; i++) {
if (state->intl.oligo[i].repeat_sim.score != NULL) {
free(state->intl.oligo[i].repeat_sim.score);
state->intl.oligo[i].repeat_sim.score = NULL;
}
}
}
static void
free_primer_repeat_sim_score(
primer_rec* h
) {
if (h->repeat_sim.score != NULL) {
free(h->repeat_sim.score);
h->repeat_sim.score = NULL;
}
}
/*
Edited by T. Koressaar for lowercase masking. This function checks
if the 3' end of the primer has been masked by lowercase letter.
Function created/Added by Eric Reppo, July 9, 2002
*/
static int
is_lowercase_masked(
int position,
const char* sequence,
primer_rec* h,
oligo_stats* global_oligo_stats
) {
const char* p = &sequence[position];
if (
('a' == *p) ||
('c' == *p) ||
('g' == *p) ||
('t' == *p)
) {
op_set_overlaps_masked_sequence(h);
global_oligo_stats->gmasked++;
return 1;
}
return 0;
}
/*
Edited by A. Untergasser
*/
static int
primer_must_match(
const p3_global_settings* pa,
primer_rec* h,
oligo_stats* global_oligo_stats,
const char* input_oligo_seq, /* This is 5'->3' on the template sequence: */
char* match_three_prime,
char* match_five_prime
) {
const char* seq;
char*test;
int length = h->length - 5;
if (match_five_prime != NULL) {
int i;
seq = input_oligo_seq;
test = match_five_prime;
for (i = 0; i < 5; i++) {
if (!compare_nucleotides(*seq, *test)) {
global_oligo_stats->must_match_fail++;
return 1;
}
seq++;
test++;
}
}
if (match_three_prime != NULL) {
int i;
seq = input_oligo_seq;
test = match_three_prime;
seq = seq + length;
for (i = 0; i < 5; i++) {
if (!compare_nucleotides(*seq, *test)) {
global_oligo_stats->must_match_fail++;
return 1;
}
seq++;
test++;
}
}
return 0;
}
/* For a [NACTG] is allowed, for b [NACTGRYWSMKBHDV].*/
static int
compare_nucleotides(
const char a,
const char b
) {
char x = a;
char y = b;
/* Convert to uppercase */
if (a >= 'a' && a <= 'z') {
x = ('A' + a - 'a');
}
if (b >= 'a' && b <= 'z') {
y = ('A' + b - 'a');
}
if ( x == y ) {
return 1;
}
if (( x == 'N') || (y == 'N')) {
return 1;
}
if (x == 'A') {
if ((y == 'R') || (y == 'W') || (y == 'M') ||
(y == 'H') || (y == 'D') || (y == 'V')) {
return 1;
}
}
if (x == 'G') {
if ((y == 'R') || (y == 'S') || (y == 'K') ||
(y == 'B') || (y == 'D') || (y == 'V')){
return 1;
}
}
if (x == 'C') {
if ((y == 'Y') || (y == 'S') || (y == 'M') ||
(y == 'B') || (y == 'H') || (y == 'V')) {
return 1;
}
}
if (x == 'T') {
if ((y == 'Y') || (y == 'W') || (y == 'K') ||
(y == 'B') || (y == 'H') || (y == 'D')) {
return 1;
}
}
return 0;
}
static int
test_must_match_parameters(
char* test
) {
int i = 0;
char x;
while (*test != '\0') {
/* First to UPPER letters */
if ((*test >= 'a') && (*test <= 'z')) {
x = ('A' + (*test) - 'a');
} else {
x = *test;
}
/* Second check that it is in Range A-Z */
if ((x < 'A') || (x > 'Z')){
return 1;
}
/* Check it is NACTGRYWSMKBHDV */
if ((x == 'N') ||
(x == 'A') || (x == 'C') ||
(x == 'T') || (x == 'G') ||
(x == 'R') || (x == 'Y') ||
(x == 'W') || (x == 'S') ||
(x == 'M') || (x == 'K') ||
(x == 'B') || (x == 'H') ||
(x == 'D') || (x == 'V'))
{
test++;
i++;
} else {
return 1;
}
}
/* Check it is 5 letters */
if (i != 5) {
return 1;
}
return 0;
}
/* Put substring of seq starting at n with length m into s. */
void
_pr_substr(
const char* seq,
int n,
int m,
char* s
) {
int i;
for(i = n;i < n + m; i++) { s[i - n]=seq[i]; }
s[m] = '\0';
}
/* Put substring of seq starting at n with length m into s from p on. */
void
_pr_shift_substr(
const char* seq,
int n,
int m,
int p,
char* s
) {
int i;
for(i=n; i< n+m; i++) {s[p + i - n] = seq[i]; }
s[p + m] = '\0';
}
/* Reverse and complement the sequence seq and put the result in s.
WARNING: It is up the caller to ensure that s points to enough
space. */
void
p3_reverse_complement(
const char* seq,
char* s
) {
const char* p = seq;
char*q = s;
while (*p != '\0') { p++; }
p--;
while (p >= seq) {
switch (*p)
{
case 'A': *q = 'T'; break;
case 'C': *q = 'G'; break;
case 'G': *q = 'C'; break;
case 'T': *q = 'A'; break;
case 'U': *q = 'A'; break;
case 'B': *q = 'V'; break;
case 'D': *q = 'H'; break;
case 'H': *q = 'D'; break;
case 'V': *q = 'B'; break;
case 'R': *q = 'Y'; break;
case 'Y': *q = 'R'; break;
case 'K': *q = 'M'; break;
case 'M': *q = 'K'; break;
case 'S': *q = 'S'; break;
case 'W': *q = 'W'; break;
case 'N': *q = 'N'; break;
case 'a': *q = 't'; break;
case 'c': *q = 'g'; break;
case 'g': *q = 'c'; break;
case 't': *q = 'a'; break;
case 'u': *q = 'a'; break;
case 'b': *q = 'v'; break;
case 'd': *q = 'h'; break;
case 'h': *q = 'd'; break;
case 'v': *q = 'b'; break;
case 'r': *q = 'y'; break;
case 'y': *q = 'r'; break;
case 'k': *q = 'm'; break;
case 'm': *q = 'k'; break;
case 's': *q = 's'; break;
case 'w': *q = 'w'; break;
case 'n': *q = 'n'; break;
}
p--; q++;
}
*q = '\0';
}
int
_pr_need_template_mispriming(
const p3_global_settings* pa
) {
return (
(pa->p_args.max_template_mispriming >= 0) ||
(pa->p_args.weights.template_mispriming > 0.0) ||
(_pr_need_pair_template_mispriming(pa))
);
}
int
_pr_need_template_mispriming_thermod(
const p3_global_settings* pa
) {
return (
(pa->p_args.max_template_mispriming_th >= 0) ||
(pa->p_args.weights.template_mispriming_th > 0.0) ||
(_pr_need_pair_template_mispriming_thermod(pa))
);
}
int
_pr_need_pair_template_mispriming(
const p3_global_settings* pa
) {
return
(pa->pair_max_template_mispriming >= 0) ||
(pa->pr_pair_weights.template_mispriming > 0.0);
}
int
_pr_need_pair_template_mispriming_thermod(
const p3_global_settings* pa
) {
return
(pa->pair_max_template_mispriming_th >= 0) ||
(pa->pr_pair_weights.template_mispriming_th > 0.0);
}
/* Upcase a DNA string, s, in place. If amibiguity_code_ok is false,
then the characters acgtnACGTN are 'recognized' and upcased. If
ambiguity_code_ok is true, then the IUB/IUPAC ambiguity codes are
also 'recognized' and upcased.
Change any unrecognized letters in *s to 'N"
Return the first unrecognized letter, if
any, that is seen. Otherwise return '\0'. */
static char
dna_to_upper(
char* s,
int ambiguity_code_ok
) {
char*p = s;
int unrecognized_base = '\0';
while (*p) {
switch (*p) {
case 'a': case 'A': *p='A'; break;
case 'c': case 'C': *p='C'; break;
case 'g': case 'G': *p='G'; break;
case 't': case 'T': *p='T'; break;
case 'n': case 'N': *p='N'; break;
default:
if (ambiguity_code_ok) {
switch (*p) {
case 'r': case 'R': *p = 'R'; break;
case 'y': case 'Y': *p = 'Y'; break;
case 'm': case 'M': *p = 'M'; break;
case 'w': case 'W': *p = 'W'; break;
case 's': case 'S': *p = 'S'; break;
case 'k': case 'K': *p = 'K'; break;
case 'd': case 'D': *p = 'D'; break;
case 'h': case 'H': *p = 'H'; break;
case 'v': case 'V': *p = 'V'; break;
case 'b': case 'B': *p = 'B'; break;
}
} else {
if (!unrecognized_base) { unrecognized_base = *p; }
*p = 'N';
}
break;
}
p++;
}
return unrecognized_base;
}
static char*
strstr_nocase(
char* s1,
char* s2
) {
int n1, n2;
char*p, q, *tmp;
if (s1 == NULL || s2 == NULL) { return NULL; }
n1 = (int)strlen(s1);
n2 = (int)strlen(s2);
if (n1 < n2) { return NULL; }
tmp = (char*) pr_safe_malloc(n1 + 1);
strcpy(tmp, s1);
q = *tmp; p = tmp;
while(q != '\0' && q != '\n') {
q = *(p + n2);
*(p + n2) = '\0';
if (strcmp_nocase(p, s2)) {
*(p + n2) = q;
p++;
continue;
} else {
if (tmp != NULL) free(tmp);
return p;
}
}
if (tmp != NULL) free(tmp);
return NULL;
}
#define CHECK if (r > bsize || r < 0) return "Internal error, not enough space for \"explain\" string"; bufp += r; bsize -= r
#define SP_AND_CHECK(FMT, VAL) { r = sprintf(bufp, FMT, VAL); CHECK; }
#define IF_SP_AND_CHECK(FMT, VAL) { if (VAL) { SP_AND_CHECK(FMT, VAL) } }
const char*
p3_pair_explain_string(
const pair_stats* pair_expl
) {
/* WARNING WARNING WARNING
Static, fixed-size buffer. If you add more calls to SP_AND_CHECK or
IF_SP_AND_CHECK, you need to make sure the buffer cannot overflow.
*/
static char buf[10000];
char* bufp = buf;
size_t bsize = 10000;
size_t r;
SP_AND_CHECK("considered %d", pair_expl->considered)
IF_SP_AND_CHECK(", no target %d", pair_expl->target)
IF_SP_AND_CHECK(", unacceptable product size %d", pair_expl->product)
IF_SP_AND_CHECK(", low product Tm %d", pair_expl->low_tm)
IF_SP_AND_CHECK(", high product Tm %d", pair_expl->high_tm)
IF_SP_AND_CHECK(", tm diff too large %d",pair_expl->temp_diff)
IF_SP_AND_CHECK(", high any compl %d", pair_expl->compl_any)
IF_SP_AND_CHECK(", high end compl %d", pair_expl->compl_end)
IF_SP_AND_CHECK(", no internal oligo %d", pair_expl->internal)
IF_SP_AND_CHECK(", high mispriming library similarity %d",
pair_expl->repeat_sim)
IF_SP_AND_CHECK(", no overlap of required point %d",
pair_expl->does_not_overlap_a_required_point)
IF_SP_AND_CHECK(", primer in pair overlaps a primer in a better pair %d",
pair_expl->overlaps_oligo_in_better_pair)
IF_SP_AND_CHECK(", high template mispriming score %d",
pair_expl->template_mispriming)
IF_SP_AND_CHECK(", not in any ok region %d",
pair_expl->not_in_any_ok_region);
IF_SP_AND_CHECK(", left primer to right of right primer %d",
pair_expl->reversed);
SP_AND_CHECK(", ok %d", pair_expl->ok)
return buf;
}
const char*
p3_oligo_explain_string(
const oligo_stats* stat
) {
/* WARNING WARNING WARNING
Static, fixed-size buffer. If you add more calls to SP_AND_CHECK or
IF_SP_AND_CHECK, you need to make sure the buffer cannot overflow.
*/
static char buf[10000];
char*bufp = buf;
size_t bsize = 10000;
size_t r;
IF_SP_AND_CHECK("sequencing locations %d, ", stat->sequencing_location)
SP_AND_CHECK("considered %d", stat->considered)
IF_SP_AND_CHECK(", would not amplify any of the ORF %d", stat->no_orf)
IF_SP_AND_CHECK(", too many Ns %d", stat->ns)
IF_SP_AND_CHECK(", overlap target %d", stat->target)
IF_SP_AND_CHECK(", overlap excluded region %d", stat->excluded)
IF_SP_AND_CHECK(", GC content failed %d", stat->gc)
IF_SP_AND_CHECK(", GC clamp failed %d", stat->gc_clamp)
IF_SP_AND_CHECK(", low tm %d", stat->temp_min)
IF_SP_AND_CHECK(", high tm %d", stat->temp_max)
IF_SP_AND_CHECK(", low faction bound %d", stat->bound_min)
IF_SP_AND_CHECK(", high fraction bound %d", stat->bound_max)
IF_SP_AND_CHECK(", high any compl %d", stat->compl_any)
IF_SP_AND_CHECK(", high end compl %d", stat->compl_end)
IF_SP_AND_CHECK(", high hairpin stability %d", stat->hairpin_th)
IF_SP_AND_CHECK(", high repeat similarity %d", stat->repeat_score)
IF_SP_AND_CHECK(", long poly-x seq %d", stat->poly_x)
IF_SP_AND_CHECK(", low sequence quality %d", stat->seq_quality)
IF_SP_AND_CHECK(", high 3' stability %d", stat->stability)
IF_SP_AND_CHECK(", high template mispriming score %d",
stat->template_mispriming)
IF_SP_AND_CHECK(", lowercase masking of 3' end %d",stat->gmasked)
IF_SP_AND_CHECK(", failed must_match requirements %d",stat->must_match_fail)
IF_SP_AND_CHECK(", not in any ok left region %d",
stat->not_in_any_left_ok_region)
IF_SP_AND_CHECK(", not in any ok right region %d",
stat->not_in_any_right_ok_region)
IF_SP_AND_CHECK(", no overlap of required point %d",
stat->does_not_overlap_a_required_point)
SP_AND_CHECK(", ok %d", stat->ok)
return buf;
}
#undef CHECK
#undef SP_AND_CHECK
#undef IF_SP_AND_CHEC
const char*
p3_get_oligo_array_explain_string(
const oligo_array* oligo_array
) {
return p3_oligo_explain_string(&oligo_array->expl);
}
const char*
p3_get_pair_array_explain_string(
const pair_array_t* pair_array
) {
return p3_pair_explain_string(&pair_array->expl);
}
const char*
libprimer3_release(
void
) {
return "libprimer3 release 2.6.1";
}
const char*
primer3_copyright(
void
) {
return primer3_copyright_char_star;
}
/* ============================================================ */
/* BEGIN Internal and external functions for pr_append_str */
/* ============================================================ */
void
init_pr_append_str(
pr_append_str* s
) {
s->data = NULL;
s->storage_size = 0;
}
const char*
pr_append_str_chars(
const pr_append_str* x
) {
return x->data;
}
pr_append_str*
create_pr_append_str()
{
/* We cannot use pr_safe_malloc here
because this function will be called outside
of the setjmp(....) */
pr_append_str* ret = NULL;
ret = (pr_append_str* ) malloc(
sizeof(pr_append_str)
);
if (NULL == ret) { return NULL; }
init_pr_append_str(ret);
return ret;
}
void
destroy_pr_append_str_data(
pr_append_str* str
) {
if (NULL == str) { return; }
if (str->data != NULL) {
free(str->data);
str->data = NULL;
}
}
void
destroy_pr_append_str(
pr_append_str* str
) {
if (str == NULL) { return; }
destroy_pr_append_str_data(str);
free(str);
str = NULL;
}
int
pr_append_external(
pr_append_str* x,
const char* s
) {
int xlen, slen;
PR_ASSERT(NULL != s);
PR_ASSERT(NULL != x);
if (NULL == x->data) {
x->storage_size = 24;
x->data = (char*) malloc(x->storage_size);
if (NULL == x->data) { return 1; } /* out of memory */
*x->data = '\0';
}
xlen = (int)strlen(x->data);
slen = (int)strlen(s);
if (xlen + slen + 1 > x->storage_size) {
x->storage_size += 2 * (slen + 1);
x->data = (char*) realloc(x->data, x->storage_size);
if (NULL == x->data) { return 1; } /* out of memory */
}
strcpy(x->data + xlen, s);
return 0;
}
static void
pr_append_new_chunk(
pr_append_str* x,
const char* s
) {
PR_ASSERT(NULL != x)
if (NULL == s) { return; }
pr_append_w_sep(x, "; ", s);
}
int
pr_append_new_chunk_external(
pr_append_str* x,
const char* s
) {
PR_ASSERT(NULL != x)
if (NULL == s) { return 0; }
return(pr_append_w_sep_external(x, "; ", s));
}
int
pr_append_w_sep_external(
pr_append_str* x,
const char* sep,
const char* s
) {
PR_ASSERT(NULL != x)
PR_ASSERT(NULL != s)
PR_ASSERT(NULL != sep)
if (pr_is_empty(x)) {
return(pr_append_external(x, s));
} else {
return (pr_append_external(x, sep) || pr_append_external(x, s));
}
}
void
pr_set_empty(
pr_append_str* x
) {
PR_ASSERT(NULL != x);
if (NULL != x->data) { *x->data = '\0'; }
}
int
pr_is_empty(
const pr_append_str* x
) {
PR_ASSERT(NULL != x);
return NULL == x->data || '\0' == *x->data;
}
static void
pr_append_w_sep(
pr_append_str* x,
const char* sep,
const char* s
) {
if (pr_append_w_sep_external(x, sep, s)) { longjmp(_jmp_buf, 1); }
}
static void
pr_append(
pr_append_str* x,
const char* s
) {
if (pr_append_external(x, s)) { longjmp(_jmp_buf, 1); }
}
/* ============================================================ */
/* END internal and external functions for pr_append_str */
/* ============================================================ */
/* =========================================================== */
/* Malloc and realloc wrappers that longjmp() on failure */
/* =========================================================== */
static void *
pr_safe_malloc(
size_t x
) {
void *r = malloc(x);
if (NULL == r) { longjmp(_jmp_buf, 1); }
return r;
}
static void *
pr_safe_realloc(
void *p,
size_t x
) {
void *r = realloc(p, x);
if (NULL == r) { longjmp(_jmp_buf, 1); }
return r;
}
/* =========================================================== */
/* End of malloc/realloc wrappers. */
/* =========================================================== */
/* ============================================================ */
/* START functions which check and modify the input */
/* ============================================================ */
/* Fuction to set the included region and fix the start positions */
static void
_adjust_seq_args(
const p3_global_settings* pa,
seq_args_t* sa,
pr_append_str* nonfatal_err,
pr_append_str* warning
) {
int seq_len, inc_len, overhang_len;
/* Subtract the overhang from PRIMER_PRODUCT_SIZE_RANGE */
/* Create a seq for check primers if needed */
if (pa->primer_task == check_primers) {
if (NULL == sa->sequence) {
fake_a_sequence(sa, pa);
}
}
if (
(pa->primer_task == pick_sequencing_primers) &&
(sa->incl_l != -1)
) {
pr_append_new_chunk(
nonfatal_err,
"Task pick_sequencing_primers cannot be combined with included region"
);
return;
}
/*
Complain if there is no sequence; We need to check this
error here, because this function cannot do its work if
sa->sequence == NULL
*/
if (NULL == sa->sequence) {
if (pa->primer_task == check_primers) {
pr_append_new_chunk(
nonfatal_err,
"No primers provided"
);
} else {
pr_append_new_chunk(
nonfatal_err,
"Missing SEQUENCE tag"
);
}
return;
}
/* Calculate once for all the reverse complement of the overhang_right */
if (NULL != sa->overhang_right) {
overhang_len = strlen(sa->overhang_right);
sa->overhang_right_rv = (char*) pr_safe_malloc(
overhang_len + 1
);
memset(
sa->overhang_right_rv,
'\0',
overhang_len + 1
);
p3_reverse_complement(
sa->overhang_right,
sa->overhang_right_rv
);
}
seq_len = (int)strlen(sa->sequence);
/* For pick_cloning_primers set the forced positions */
if (pa->primer_task == pick_cloning_primers) {
if (sa->incl_l == -1) {
sa->force_left_start = pa->first_base_index;
sa->force_right_start = seq_len + pa->first_base_index - 1;
} else {
sa->force_left_start = sa->incl_s;
sa->force_right_start = sa->incl_s + sa->incl_l - 1;
}
}
/* For pick_discriminative_primers set the forced positions */
if (pa->primer_task == pick_discriminative_primers) {
/* Changed here from incl_s and incl_l to sa->tar2->pairs[0][0/1] */
if (sa->tar2.count != 1) {
pr_append_new_chunk(
nonfatal_err,
"Task pick_discriminative_primers requires exactly one SEQUENCE_TARGET"
);
}
sa->force_left_end = sa->tar2.pairs[0][0] - 1;
sa->force_right_end = sa->tar2.pairs[0][0] + sa->tar2.pairs[0][1];
}
/* If no included region is specified,
* use the whole sequence as included region */
if (sa->incl_l == -1) {
sa->incl_l = seq_len;
sa->incl_s = pa->first_base_index;
}
/* Generate at least one target */
if (
(pa->primer_task == pick_sequencing_primers) &&
(sa->tar2.count == 0)
) {
sa->tar2.pairs[0][0] = pa->first_base_index;
sa->tar2.pairs[0][1] = seq_len;
sa->tar2.count = 1;
}
/* Fix the start of the included region and start codon */
sa->incl_s -= pa->first_base_index;
sa->start_codon_pos -= pa->first_base_index;
/* Fix the start */
sa->force_left_start -= pa->first_base_index;
sa->force_left_end -= pa->first_base_index;
sa->force_right_start -= pa->first_base_index;
sa->force_right_end -= pa->first_base_index;
/* Make it relative to included region */
sa->force_left_start -= sa->incl_s;
sa->force_left_end -= sa->incl_s;
sa->force_right_start -= sa->incl_s;
sa->force_right_end -= sa->incl_s;
inc_len = sa->incl_s + sa->incl_l - 1;
if (
(sa->incl_l < INT_MAX) &&
(sa->incl_s > -1) &&
(sa->incl_l > -1) &&
(inc_len < seq_len)
) {
/* Copies inluded region into trimmed_seq */
sa->trimmed_seq = (char*) pr_safe_malloc(
sa->incl_l + 1
);
_pr_substr(
sa->sequence,
sa->incl_s,
sa->incl_l,
sa->trimmed_seq
);
/* Copies inluded region into trimmed_orig_seq */
/* edited by T. Koressaar for lowercase masking */
sa->trimmed_orig_seq = (char*) pr_safe_malloc(
sa->incl_l + 1
);
_pr_substr(
sa->sequence,
sa->incl_s,
sa->incl_l,
sa->trimmed_orig_seq
);
#if !defined(OS_WIN)
/* Masks original trimmed sequence */
/* edited by M. Lepamets */
if (
(pa->mask_template) &&
((pa->pick_left_primer == 1) && (pa->pick_right_primer == 1))
) {
input_sequence *input_seq;
output_sequence *output_seq;
input_seq = create_input_sequence_from_string(
sa->trimmed_orig_seq,
nonfatal_err
);
output_seq = create_output_sequence(
(unsigned long long) sa->incl_l,
pa->mp.mdir,
nonfatal_err
);
read_and_mask_sequence(
input_seq,
output_seq,
&pa->mp,
nonfatal_err,
0
);
if (output_seq->sequence) {
if (pa->mp.mdir == fwd) {
sa->trimmed_masked_seq = (char*) pr_safe_malloc(
sa->incl_l + 1
);
strcpy(
sa->trimmed_masked_seq,
output_seq->sequence
);
} else if (pa->mp.mdir == rev) {
sa->trimmed_masked_seq_r = (char*) pr_safe_malloc(
sa->incl_l + 1
);
strcpy(
sa->trimmed_masked_seq_r,
output_seq->sequence
);
}
} else {
sa->trimmed_masked_seq = (char*) pr_safe_malloc(
sa->incl_l + 1
);
strcpy(
sa->trimmed_masked_seq,
output_seq->sequence_fwd
);
sa->trimmed_masked_seq_r = (char*) pr_safe_malloc(
sa->incl_l + 1
);
strcpy(
sa->trimmed_masked_seq_r,
output_seq->sequence_rev
);
}
delete_input_sequence (input_seq);
delete_output_sequence (output_seq);
}
#endif
/* Copies the whole sequence into upcased_seq */
sa->upcased_seq = (char*) pr_safe_malloc(
(int) strlen(sa->sequence) + 1
);
strcpy(
sa->upcased_seq,
sa->sequence
);
dna_to_upper(sa->upcased_seq, 1);
/* We do not need to check for illegal characters in the return
from dna_to_upper(), because errors are checked in
_pr_data_control sa->trimmed_seq. */
/* Copies the reverse complement of the whole sequence into upcased_seq_r */
sa->upcased_seq_r = (char*) pr_safe_malloc(
(int) strlen(sa->sequence) + 1
);
p3_reverse_complement(
sa->upcased_seq,
sa->upcased_seq_r
);
}
if (
_check_and_adjust_intervals(
sa,
seq_len,
pa->first_base_index,
nonfatal_err, warning
)
) {
return;
}
if (
_check_and_adjust_overlap_pos(
sa,
sa->primer_overlap_junctions,
&sa->primer_overlap_junctions_count,
"SEQUENCE_OVERLAP_JUNCTION_LIST",
seq_len,
pa->first_base_index,
nonfatal_err,
warning
)
) {
return;
}
if (
_check_and_adjust_overlap_pos(
sa,
sa->intl_overlap_junctions,
&sa->intl_overlap_junctions_count,
"SEQUENCE_INTERNAL_OVERLAP_JUNCTION_LIST",
seq_len,
pa->first_base_index,
nonfatal_err,
warning
)
) {
return;
}
/* Update ok regions, if non empty */
if (sa->ok_regions.count > 0) {
_optimize_ok_regions_list(pa, sa);
}
}
/*
* This function uses the max/min product size info and the max/min
* oligo length in order to reduce the ranges of the ok regions. On
* some imputs this improves speed dramatically.
*/
static void
_optimize_ok_regions_list(
const p3_global_settings* pa,
seq_args_t* sa
) {
int pmin = INT_MAX;
int pmax = 0;
int omin = pa->p_args.min_size;
int omax = pa->p_args.max_size;
int i;
/* We do this only if we enabled the optimization and
* the primers were NOT specified. */
if (!OPTIMIZE_OK_REGIONS || (sa->left_input) || (sa->right_input)) {
return;
}
/* If any pair is allowed, no point in doing this */
if (sa->ok_regions.any_pair) {
return;
}
/* Determine min/max product size */
for (i=0; i < pa->num_intervals; i++) {
if (pa->pr_min[i] < pmin) { pmin = pa->pr_min[i]; }
if (pa->pr_max[i] > pmax) { pmax = pa->pr_max[i]; }
}
/* Update each region */
for (i=0; iok_regions.count; i++) {
int ls = -1, le = -1, rs = -1, re = -1;
int new_ls = -1, new_le = -1, new_rs = -1, new_re = -1;
if (sa->ok_regions.left_pairs[i][0] != -1) {
ls = sa->ok_regions.left_pairs[i][0];
le = sa->ok_regions.left_pairs[i][0]
+ sa->ok_regions.left_pairs[i][1] - 1;
}
if (sa->ok_regions.right_pairs[i][0] != -1) {
rs = sa->ok_regions.right_pairs[i][0];
re = sa->ok_regions.right_pairs[i][0]
+ sa->ok_regions.right_pairs[i][1] - 1;
}
/* Compute new right region based on left range and min/max values
of product size and oligo length */
if (ls != -1) {
new_rs = ls + pmin - omax - 1; /* -1 just to be safe */
new_re = le - omin + pmax + 1; /* +1 just to be safe */
/* Adjust the ranges */
if ((rs == -1) || (new_rs > rs)) { rs = new_rs; }
if ((re == -1) || (new_re < re)) { re = new_re; }
if (rs < 0) { rs = 0; }
if (re > (signed) (int)strlen(sa->sequence)) { re = (int) strlen(sa->sequence); }
}
/* Compute new left region based on right range and min/max values
of product size and oligo length */
if (rs != -1) {
new_ls = rs + omin - pmax - 1; /* -1 just to be safe */
new_le = re - pmin + omax + 1; /* +1 just to be safe */
/* Adjust the ranges */
if ((ls == -1) || (new_ls > ls)) { ls = new_ls; }
if ((le == -1) || (new_le < le)) { le = new_le; }
if (ls < 0) { ls = 0; }
if (le > (signed) (int)strlen(sa->sequence)) { le = (int) strlen(sa->sequence); }
}
/* Temporary testing fprintf: */
/* fprintf(stderr, "Adjusted range [%d,%d,%d,%d] to [%d,%d,%d,%d],
pmin is %d, pmax is %d, omin is %d, omax is %d\n",
sa->ok_regions.left_pairs[i][0],
sa->ok_regions.left_pairs[i][0] +
sa->ok_regions.left_pairs[i][1] - 1,
sa->ok_regions.right_pairs[i][0],
sa->ok_regions.right_pairs[i][0] +
sa->ok_regions.right_pairs[i][1] - 1, ls, le, rs, re,
pmin, pmax, omin, omax);
*/
sa->ok_regions.left_pairs[i][0] = ls;
sa->ok_regions.left_pairs[i][1] = le - ls + 1;
sa->ok_regions.right_pairs[i][0] = rs;
sa->ok_regions.right_pairs[i][1] = re - rs + 1;
}
/* any_left and any_right not true anymore */
sa->ok_regions.any_left = 0;
sa->ok_regions.any_right = 0;
}
/*
* Return 1 on error, 0 on success. fake_a_sequence creates a sequence
* out of the provided primers and puts them in sa.
*/
static int
fake_a_sequence(
seq_args_t* sa,
const p3_global_settings* pa
) {
int i, product_size, space, ns_to_fill;
char*rev = NULL;
int ns_to_fill_first, ns_to_fill_second;
/* Determine the product size */
if (
(pa->product_opt_size < 1) ||
(pa->product_opt_size == PR_UNDEFINED_INT_OPT)
) {
product_size = pa->pr_max[0] - pa->pr_min[0];
} else {
product_size = pa->product_opt_size;
}
space = product_size + 1;
ns_to_fill = product_size;
/* Calculate how many Ns have to be added */
if (sa->left_input) {
ns_to_fill = ns_to_fill - (int) strlen(sa->left_input);
}
if (sa->right_input) {
ns_to_fill = ns_to_fill - (int) strlen(sa->right_input);
rev = (char*) pr_safe_malloc((int) strlen(sa->right_input) + 1);
p3_reverse_complement(
sa->right_input,
rev
);
}
if (sa->internal_input) {
ns_to_fill = ns_to_fill - (int) strlen(sa->internal_input);
}
/* Return if there are no primers provided */
if (ns_to_fill == product_size + 1){
return 0;
}
ns_to_fill_first = ns_to_fill / 2;
ns_to_fill_second = ns_to_fill - ns_to_fill_first;
/* Allocate the space for the sequence */
sa->sequence = (char*) pr_safe_malloc(space);
*sa->sequence = '\0';
/* Copy over the primers */
if (sa->left_input){
strcat(
sa->sequence,
sa->left_input
);
}
/* Add the Ns*/
for (i = 0; i < ns_to_fill_first; i++ ) {
strcat(
sa->sequence,
"N\0"
);
}
if (sa->internal_input){
strcat(
sa->sequence,
sa->internal_input
);
}
for (i = 0; i < ns_to_fill_second; i++ ) {
strcat(
sa->sequence,
"N\0"
);
}
if (sa->right_input){
strcat(
sa->sequence,
rev
);
}
if (rev != NULL) {
free(rev);
rev = NULL;
}
return 0;
}
/*
* Return 1 on error, 0 on success. Set sa->trimmed_seq and possibly modify
* sa->tar. Upcase and check all bases in sa->trimmed_seq.
* TO DO -- this would probably be cleaner if it only
* checked, rather than updated, sa.
*/
/* Check if the input in sa and pa makes sense */
int
_pr_data_control(
const p3_global_settings* pa,
const seq_args_t* sa,
pr_append_str* glob_err,
pr_append_str* nonfatal_err,
pr_append_str* warning
) {
static char s1[MAX_PRIMER_LENGTH+1];
int i, pr_min, seq_len, overhang_left_len, overhang_right_len;
char offending_char = '\0';
overhang_left_len = 0;
overhang_right_len = 0;
seq_len = (int) strlen(sa->sequence);
/* The overhang from PRIMER_PRODUCT_SIZE_RANGE is subtracted
in adjust_seq_args() */
/* If sequence quality is provided, is it as long as the sequence? */
if (
(sa->n_quality != 0) &&
(sa->n_quality != seq_len)
) {
pr_append_new_chunk(
nonfatal_err,
"Error in sequence quality data"
);
}
if (
(pa->min_left_three_prime_distance < -1) ||
(pa->min_internal_three_prime_distance < -1) ||
(pa->min_right_three_prime_distance < -1)
) {
pr_append_new_chunk(
nonfatal_err,
"Minimum 3' distance must be >= -1 "
"(min_*_three_prime_distance)"
);
}
if (
((pa->p_args.min_quality != 0) || (pa->o_args.min_quality != 0)) &&
(sa->n_quality == 0)
) {
pr_append_new_chunk(
nonfatal_err,
"Sequence quality data missing"
);
}
if (pa->first_base_index < PR_NULL_FORCE_POSITION) {
pr_append_new_chunk(
glob_err,
"Value too small at tag PRIMER_FIRST_BASE_INDEX"
);
return 1;
}
if (
(pa->p_args.max_template_mispriming > SHRT_MAX) &&
(pa->thermodynamic_template_alignment == 0)
) {
pr_append_new_chunk(
glob_err,
"Value too large at tag PRIMER_MAX_TEMPLATE_MISPRIMING"
);
return 1;
}
if (
(pa->pair_max_template_mispriming > SHRT_MAX) &&
(pa->thermodynamic_template_alignment == 0)
) {
pr_append_new_chunk(
glob_err,
"Value too large at tag PRIMER_PAIR_MAX_TEMPLATE_MISPRIMING"
);
return 1;
}
if (
(pa->p_args.max_repeat_compl > SHRT_MAX) &&
(pa->thermodynamic_oligo_alignment == 0)
) {
pr_append_new_chunk(
glob_err,
"Value too large at tag PRIMER_MAX_LIBRARY_MISPRIMING"
);
return 1;
}
if (
(pa->o_args.max_repeat_compl > SHRT_MAX) &&
(pa->thermodynamic_oligo_alignment == 0)
) {
pr_append_new_chunk(
glob_err,
"Value too large at tag PRIMER_INTERNAL_MAX_LIBRARY_MISHYB"
);
return 1;
}
if (
(pa->pair_repeat_compl > SHRT_MAX) &&
(pa->thermodynamic_oligo_alignment == 0)
) {
pr_append_new_chunk(
glob_err,
"Value too large at tag PRIMER_PAIR_MAX_LIBRARY_MISPRIMING"
);
return 1;
}
if (
(pa->o_args.max_template_mispriming >= 0) &&
(pa->thermodynamic_template_alignment == 0)
) {
pr_append_new_chunk(
glob_err,
"PRIMER_INTERNAL_MAX_TEMPLATE_MISHYB is not supported"
);
}
if (
(pa->o_args.max_template_mispriming_th >= 0) &&
(pa->thermodynamic_template_alignment == 1)
) {
pr_append_new_chunk(
glob_err,
"PRIMER_INTERNAL_MAX_TEMPLATE_MISHYB_TH is not supported"
);
}
if (pa->p_args.min_size < 1) {
pr_append_new_chunk(
glob_err,
"PRIMER_MIN_SIZE must be >= 1"
);
}
if (pa->p_args.max_size > MAX_PRIMER_LENGTH) {
pr_append_new_chunk(
glob_err,
"PRIMER_MAX_SIZE exceeds built-in maximum of "
);
pr_append(
glob_err,
MACRO_VALUE_AS_STRING(MAX_PRIMER_LENGTH)
);
return 1;
}
if (pa->p_args.opt_size > pa->p_args.max_size) {
pr_append_new_chunk(
glob_err,
"PRIMER_{OPT,DEFAULT}_SIZE > PRIMER_MAX_SIZE"
);
return 1;
}
if (pa->p_args.opt_size < pa->p_args.min_size) {
pr_append_new_chunk(
glob_err,
"PRIMER_{OPT,DEFAULT}_SIZE < PRIMER_MIN_SIZE"
);
return 1;
}
if (pa->o_args.max_size > MAX_PRIMER_LENGTH) {
pr_append_new_chunk(
glob_err,
"PRIMER_INTERNAL_MAX_SIZE exceeds built-in maximum"
);
return 1;
}
if (pa->o_args.opt_size > pa->o_args.max_size) {
pr_append_new_chunk(
glob_err,
"PRIMER_INTERNAL_{OPT,DEFAULT}_SIZE > MAX_SIZE"
);
return 1;
}
if (pa->o_args.opt_size < pa->o_args.min_size) {
pr_append_new_chunk(
glob_err,
"PRIMER_INTERNAL_{OPT,DEFAULT}_SIZE < MIN_SIZE"
);
return 1;
}
/* A GC clamp can not be bigger then the primer */
if (pa->gc_clamp > pa->p_args.min_size) {
pr_append_new_chunk(
glob_err,
"PRIMER_GC_CLAMP > PRIMER_MIN_SIZE"
);
return 1;
}
/* Must be >= 0 and <= 5 */
if (
(pa->max_end_gc < 0) ||
(pa->max_end_gc > 5)
) {
pr_append_new_chunk(
glob_err,
"PRIMER_MAX_END_GC must be between 0 to 5"
);
return 1;
}
/* Product size must be provided */
if (pa->num_intervals == 0) {
pr_append_new_chunk(
glob_err,
"Empty value for PRIMER_PRODUCT_SIZE_RANGE"
);
return 1;
}
for (i = 0; i < pa->num_intervals; i++) {
if (pa->pr_min[i] > pa->pr_max[i] || pa->pr_min[i] < 0) {
pr_append_new_chunk(
glob_err,
"Illegal element in PRIMER_PRODUCT_SIZE_RANGE"
);
return 1;
}
}
pr_min = INT_MAX;
/* Check if the primer is bigger then the product */
for(i=0; i < pa->num_intervals; i++) {
if (pa->pr_min[i] < pr_min) {
pr_min=pa->pr_min[i];
}
}
if (pa->p_args.max_size > pr_min) {
pr_append_new_chunk(
glob_err,
"PRIMER_MAX_SIZE > min PRIMER_PRODUCT_SIZE_RANGE"
);
return 1;
}
if (
(pa->pick_internal_oligo == 1) &&
(pa->o_args.max_size > pr_min)
) {
pr_append_new_chunk(
glob_err,
"PRIMER_INTERNAL_MAX_SIZE > min PRIMER_PRODUCT_SIZE_RANGE"
);
return 1;
}
/* There must be at least one primer returned */
if (pa->num_return < 1) {
pr_append_new_chunk(
glob_err,
"PRIMER_NUM_RETURN < 1"
);
return 1;
}
if (
(pa->p_args.must_match_five_prime != NULL) &&
((int) strlen(pa->p_args.must_match_five_prime) != 5)
) {
pr_append_new_chunk(
glob_err,
"PRIMER_MUST_MATCH_FIVE_PRIME must have 5 characters"
);
return 1;
}
if (
(pa->p_args.must_match_three_prime != NULL) &&
((int) strlen(pa->p_args.must_match_three_prime) != 5)
) {
pr_append_new_chunk(
glob_err,
"PRIMER_MUST_MATCH_THREE_PRIME must have 5 characters"
);
return 1;
}
if (
(pa->o_args.must_match_five_prime != NULL) &&
((int) strlen(pa->o_args.must_match_five_prime) != 5)
) {
pr_append_new_chunk(
glob_err,
"PRIMER_INTERNAL_MUST_MATCH_FIVE_PRIME must have 5 characters"
);
return 1;
}
if (
(pa->o_args.must_match_three_prime != NULL) &&
((int)strlen(pa->o_args.must_match_three_prime) != 5)
) {
pr_append_new_chunk(
glob_err,
"PRIMER_INTERNAL_MUST_MATCH_THREE_PRIME must have 5 characters"
);
return 1;
}
if (sa->incl_l >= INT_MAX) {
pr_append_new_chunk(
nonfatal_err,
"Value for SEQUENCE_INCLUDED_REGION too large"
);
return 1;
}
if (
(sa->incl_s < 0) ||
(sa->incl_l < 0) ||
(sa->incl_s + sa->incl_l > seq_len)
) {
pr_append_new_chunk(
nonfatal_err,
"Illegal value for SEQUENCE_INCLUDED_REGION"
);
return 1;
}
/* The product must fit in the included region */
if (
(sa->incl_l < pr_min) &&
(pa->pick_left_primer == 1) &&
(pa->pick_right_primer == 1)
) {
if (pa->primer_task == check_primers) {
pr_append_new_chunk(
warning,
"SEQUENCE_INCLUDED_REGION length < min PRIMER_PRODUCT_SIZE_RANGE"
);
} else if (pa->primer_task != pick_primer_list) {
pr_append_new_chunk(
nonfatal_err,
"SEQUENCE_INCLUDED_REGION length < min PRIMER_PRODUCT_SIZE_RANGE"
);
}
if (pa->primer_task == generic_p3) {
return 1;
}
}
if (pa->max_end_stability < 0) {
pr_append_new_chunk(
nonfatal_err,
"PRIMER_MAX_END_STABILITY must be non-negative"
);
return 1;
}
/* Is the startodon ATG and in the incl. region */
if (!PR_START_CODON_POS_IS_NULL(sa)) {
if (!PR_POSITION_PENALTY_IS_NULL(pa)) {
pr_append_new_chunk(
nonfatal_err,
"Cannot accept both SEQUENCE_START_CODON_POSITION and non-default "
);
pr_append(
nonfatal_err,
"arguments for PRIMER_INSIDE_PENALTY or PRIMER_OUTSIDE_PENALTY"
);
}
if (sa->start_codon_pos > (sa->incl_s + sa->incl_l - 3)) {
pr_append_new_chunk(
nonfatal_err,
"Start codon position not contained in SEQUENCE_INCLUDED_REGION"
);
return 1;
} else {
if (sa->start_codon_seq[0] == 'X') {
pr_append_new_chunk(
nonfatal_err,
"No codon provided in SEQUENCE_START_CODON_SEQUENCE"
);
return 1;
}
if (
(sa->start_codon_pos >= 0) &&
(
(toupper(sa->sequence[sa->start_codon_pos]) != sa->start_codon_seq[0]) ||
(toupper(sa->sequence[sa->start_codon_pos + 1]) != sa->start_codon_seq[1]) ||
(toupper(sa->sequence[sa->start_codon_pos + 2]) != sa->start_codon_seq[2])
)
) {
pr_append_new_chunk(
nonfatal_err,
"No start codon at SEQUENCE_START_CODON_POSITION"
);
return 1;
}
}
}
if (sa->quality != NULL) {
if (
(pa->p_args.min_quality != 0) &&
(pa->p_args.min_quality < pa->quality_range_min)
) {
pr_append_new_chunk(
glob_err,
"PRIMER_MIN_QUALITY < PRIMER_QUALITY_RANGE_MIN"
);
return 1;
}
if (
(pa->p_args.min_quality != 0) &&
(pa->p_args.min_quality > pa->quality_range_max)
) {
pr_append_new_chunk(
glob_err,
"PRIMER_MIN_QUALITY > PRIMER_QUALITY_RANGE_MAX"
);
return 1;
}
if (
(pa->o_args.min_quality != 0) &&
(pa->o_args.min_quality < pa->quality_range_min)
) {
pr_append_new_chunk(
glob_err,
"PRIMER_INTERNAL_MIN_QUALITY < PRIMER_QUALITY_RANGE_MIN"
);
return 1;
}
if (
(pa->o_args.min_quality != 0) &&
(pa->o_args.min_quality > pa->quality_range_max)
) {
pr_append_new_chunk(
glob_err,
"PRIMER_INTERNAL_MIN_QUALITY > PRIMER_QUALITY_RANGE_MAX"
);
return 1;
}
for(i=0; i < sa->n_quality; i++) {
if (
(sa->quality[i] < pa->quality_range_min) ||
(sa->quality[i] > pa->quality_range_max)
) {
pr_append_new_chunk(
nonfatal_err,
"Sequence quality score out of range"
);
return 1;
}
} /* end for */
} else if (
(pa->p_args.weights.seq_quality) ||
(pa->o_args.weights.seq_quality)
) {
pr_append_new_chunk(
nonfatal_err,
"Sequence quality is part of objective function but sequence quality is not defined"
);
return 1;
}
if ((offending_char = dna_to_upper(sa->trimmed_seq, 0))) {
char err_msg[64];
snprintf(
err_msg,
64,
"Rejecting invalid sequence character (only ACGTN allowed): %c",
offending_char
);
if (pa->liberal_base) {
pr_append_new_chunk(warning, err_msg);
} else {
pr_append_new_chunk(nonfatal_err, err_msg);
return 1;
}
}
if (sa->overhang_left != NULL) {
overhang_left_len = strlen(sa->overhang_left);
if (
((unsigned) pa->p_args.max_size + overhang_left_len) > THAL_MAX_ALIGN
) {
pr_append_new_chunk(
glob_err,
"PRIMER_MAX_SIZE + SEQUENCE_OVERHANG_LEFT exceeds built-in maximum of "
);
pr_append(
glob_err,
MACRO_VALUE_AS_STRING(THAL_MAX_ALIGN)
);
return 1;
}
if ((offending_char = dna_to_upper(sa->overhang_left, 0))) {
pr_append_new_chunk(
nonfatal_err,
"Unrecognized base in left overhang"
);
return 1;
}
}
if (sa->overhang_right != NULL) {
overhang_right_len = strlen(sa->overhang_right);
if (
((unsigned) pa->p_args.max_size + overhang_right_len) > THAL_MAX_ALIGN
) {
pr_append_new_chunk(
glob_err,
"PRIMER_MAX_SIZE + SEQUENCE_OVERHANG_RIGHT exceeds built-in maximum of "
);
pr_append(
glob_err,
MACRO_VALUE_AS_STRING(THAL_MAX_ALIGN)
);
return 1;
}
if ((offending_char = dna_to_upper(sa->overhang_right, 0))) {
pr_append_new_chunk(
nonfatal_err,
"Unrecognized base in right overhang"
);
return 1;
}
}
if (
(pa->p_args.opt_tm < pa->p_args.min_tm) ||
(pa->p_args.opt_tm > pa->p_args.max_tm)
) {
pr_append_new_chunk(
glob_err,
"Optimum primer Tm lower than minimum or higher than maximum"
);
return 1;
}
if (
(pa->o_args.opt_tm < pa->o_args.min_tm) ||
(pa->o_args.opt_tm > pa->o_args.max_tm)
) {
pr_append_new_chunk(
glob_err,
"Optimum internal oligo Tm lower than minimum or higher than maximum"
);
return 1;
}
if (
(pa->p_args.opt_bound < pa->p_args.min_bound) ||
(pa->p_args.opt_bound > pa->p_args.max_bound)
) {
pr_append_new_chunk(
glob_err,
"Optimum primer fraction binding lower than minimum or higher than maximum"
);
return 1;
}
if (
(pa->o_args.opt_bound < pa->o_args.min_bound) ||
(pa->o_args.opt_bound > pa->o_args.max_bound)
) {
pr_append_new_chunk(
glob_err,
"Optimum internal oligo fraction binding lower than minimum or higher than maximum"
);
return 1;
}
if (pa->annealing_temp > 0.0) {
if (pa->annealing_temp > 100.0) {
pr_append_new_chunk(
glob_err,
"Annealing temperature higher than 100 C"
);
return 1;
}
if (pa->salt_corrections == 2) {
pr_append_new_chunk(
glob_err,
"Primer binding does not work with Owczarzy salt correction (PRIMER_SALT_CORRECTIONS=2)"
);
return 1;
}
}
if (
(pa->p_args.min_gc > pa->p_args.max_gc) ||
(pa->p_args.min_gc > 100) ||
(pa->p_args.max_gc < 0)
){
pr_append_new_chunk(
glob_err,
"Illegal value for PRIMER_MAX_GC and PRIMER_MIN_GC"
);
return 1;
}
if (
(pa->o_args.min_gc > pa->o_args.max_gc) ||
(pa->o_args.min_gc > 100) ||
(pa->o_args.max_gc < 0)
) {
pr_append_new_chunk(
glob_err,
"Illegal value for PRIMER_INTERNAL_OLIGO_GC"
);
return 1;
}
if (pa->p_args.num_ns_accepted < 0) {
pr_append_new_chunk(
glob_err,
"Illegal value for PRIMER_MAX_NS_ACCEPTED"
);
return 1;
}
if (pa->o_args.num_ns_accepted < 0){
pr_append_new_chunk(
glob_err,
"Illegal value for PRIMER_INTERNAL_MAX_NS_ACCEPTED"
);
return 1;
}
if (
(pa->p_args.max_self_any < 0) ||
(pa->p_args.max_self_any > SHRT_MAX) ||
(pa->p_args.max_self_end < 0) ||
(pa->p_args.max_self_end > SHRT_MAX) ||
(pa->pair_compl_any < 0) ||
(pa->pair_compl_any > SHRT_MAX) ||
(pa->pair_compl_end < 0) ||
(pa->pair_compl_end > SHRT_MAX)
) {
pr_append_new_chunk(
glob_err,
"Illegal value for primer complementarity restrictions"
);
return 1;
}
if (
(pa->p_args.max_self_any_th < 0) ||
(pa->p_args.max_self_end_th < 0) ||
(pa->p_args.max_hairpin_th < 0) ||
(pa->pair_compl_any_th < 0) ||
(pa->pair_compl_end_th < 0)
) {
pr_append_new_chunk(
glob_err,
"Illegal value for primer complementarity restrictions (thermod. approach)"
);
return 1;
}
if (
(pa->o_args.max_self_any < 0) ||
(pa->o_args.max_self_any > SHRT_MAX) ||
(pa->o_args.max_self_end < 0) ||
(pa->o_args.max_self_end > SHRT_MAX)
) {
pr_append_new_chunk(
glob_err,
"Illegal value for internal oligo complementarity restrictions"
);
return 1;
}
if (
(pa->o_args.max_self_any_th < 0) ||
(pa->o_args.max_self_end_th < 0) ||
(pa->o_args.max_hairpin_th < 0)
) {
pr_append_new_chunk(
glob_err,
"Illegal value for internal oligo complementarity restrictions"
);
return 1;
}
if ((pa->p_args.salt_conc <= 0) || (pa->p_args.dna_conc <= 0)) {
pr_append_new_chunk(
glob_err,
"Illegal value for primer salt or dna concentration"
);
return 1;
}
if (
((pa->p_args.dntp_conc < 0) && (pa->p_args.divalent_conc != 0) ) ||
(pa->p_args.divalent_conc < 0)
) { /* added by T.Koressaar */
pr_append_new_chunk(
glob_err,
"Illegal value for primer divalent salt or dNTP concentration"
);
return 1;
}
if (
(pa->o_args.salt_conc <= 0) || (pa->o_args.dna_conc <= 0)
){
pr_append_new_chunk(
glob_err,
"Illegal value for internal oligo salt or dna concentration"
);
return 1;
}
if (
((pa->o_args.dntp_conc < 0) && (pa->o_args.divalent_conc != 0)) ||
(pa->o_args.divalent_conc < 0)
) { /* added by T.Koressaar */
pr_append_new_chunk(
glob_err,
"Illegal value for internal oligo divalent salt or dNTP concentration"
);
return 1;
}
if (!_PR_DEFAULT_POSITION_PENALTIES(pa) && (sa->tar2.count > 1)) {
pr_append_new_chunk(
nonfatal_err,
"Non-default inside penalty or outside penalty "
);
pr_append(
nonfatal_err,
"is valid only when number of targets <= 1"
);
}
if (!_PR_DEFAULT_POSITION_PENALTIES(pa) && (0 == sa->tar2.count)) {
pr_append_new_chunk(
warning,
"Non-default inside penalty or outside penalty "
);
pr_append(
warning,
"has no effect when number of targets is 0"
);
}
if ((pa->pick_internal_oligo != 1) && sa->internal_input) {
pr_append_new_chunk(
nonfatal_err,
"Not specified to pick internal oligos"
);
pr_append(
nonfatal_err,
" but a specific internal oligo is provided"
);
}
if (sa->internal_input) {
if ((int) strlen(sa->internal_input) > MAX_PRIMER_LENGTH) {
pr_append_new_chunk(
glob_err,
"Specified internal oligo exceeds built-in maximum of "
);
pr_append(
glob_err,
MACRO_VALUE_AS_STRING(MAX_PRIMER_LENGTH)
);
return 1;
}
if ((int)strlen(sa->internal_input) > (int)pa->o_args.max_size) {
pr_append_new_chunk(
warning,
"Specified internal oligo > PRIMER_INTERNAL_MAX_SIZE"
);
}
if ((int)strlen(sa->internal_input) < (int)pa->o_args.min_size) {
pr_append_new_chunk(
warning,
"Specified internal oligo < PRIMER_INTERNAL_MIN_SIZE"
);
}
if (!strstr_nocase(sa->sequence, sa->internal_input)) {
pr_append_new_chunk(
nonfatal_err,
"Specified internal oligo not in sequence"
);
} else if (!strstr_nocase(sa->trimmed_seq, sa->internal_input)) {
pr_append_new_chunk(
nonfatal_err,
"Specified internal oligo not in Included Region"
);
}
}
if (sa->left_input) {
if ((int) strlen(sa->left_input) > MAX_PRIMER_LENGTH) {
pr_append_new_chunk(
glob_err,
"Specified left primer exceeds built-in maximum of "
);
pr_append(
glob_err,
MACRO_VALUE_AS_STRING(MAX_PRIMER_LENGTH)
);
return 1;
}
if ((strlen(sa->left_input) + overhang_left_len) > THAL_MAX_ALIGN) {
pr_append_new_chunk(
glob_err,
"Specified left primer + overhang exceeds built-in maximum of "
);
pr_append(
glob_err,
MACRO_VALUE_AS_STRING(THAL_MAX_ALIGN)
);
return 1;
}
if ((int)strlen(sa->left_input) > (int)pa->p_args.max_size) {
pr_append_new_chunk(
warning,
"Specified left primer > PRIMER_MAX_SIZE"
);
}
if ((int)strlen(sa->left_input) < (int)pa->p_args.min_size) {
pr_append_new_chunk(
warning,
"Specified left primer < PRIMER_MIN_SIZE"
);
}
if (!strstr_nocase(sa->sequence, sa->left_input)) {
pr_append_new_chunk(
nonfatal_err,
"Specified left primer not in sequence"
);
} else if (!strstr_nocase(sa->trimmed_seq, sa->left_input)) {
pr_append_new_chunk(
nonfatal_err,
"Specified left primer not in Included Region"
);
}
}
if (sa->right_input) {
if ((int)strlen(sa->right_input) > MAX_PRIMER_LENGTH) {
pr_append_new_chunk(
glob_err,
"Specified right primer exceeds built-in maximum of "
);
pr_append(glob_err, MACRO_VALUE_AS_STRING(MAX_PRIMER_LENGTH));
return 1;
}
if ((strlen(sa->right_input) + overhang_right_len) > THAL_MAX_ALIGN) {
pr_append_new_chunk(
glob_err,
"Specified right primer + overhang exceeds built-in maximum of "
);
pr_append(glob_err, MACRO_VALUE_AS_STRING(THAL_MAX_ALIGN));
return 1;
}
if ((int)strlen(sa->right_input) < (int)pa->p_args.min_size) {
pr_append_new_chunk(
warning,
"Specified right primer < PRIMER_MIN_SIZE"
);
}
if ((int)strlen(sa->right_input) > (int)pa->p_args.max_size) {
pr_append_new_chunk(
warning,
"Specified right primer > PRIMER_MAX_SIZE"
);
} else { /* We do not want to overflow s1. */
p3_reverse_complement(sa->right_input,s1);
if (!strstr_nocase(sa->sequence, s1)) {
pr_append_new_chunk(
nonfatal_err,
"Specified right primer not in sequence"
);
} else if (!strstr_nocase(sa->trimmed_seq, s1)) {
pr_append_new_chunk(
nonfatal_err,
"Specified right primer not in Included Region"
);
} else if (sa->left_input) {
if (strcmp(sa->left_input, s1) == 0) {
pr_append_new_chunk(
nonfatal_err,
"Specified left and right primer are reverse complementary"
);
}
if (strcmp(sa->left_input, sa->right_input) == 0) {
pr_append_new_chunk(
nonfatal_err,
"Specified left and right primer are identical"
);
}
}
}
}
if (
(pa->pr_pair_weights.product_tm_lt || pa->pr_pair_weights.product_tm_gt) &&
(pa->product_opt_tm == PR_UNDEFINED_DBL_OPT)
) {
pr_append_new_chunk(
glob_err,
"Product temperature is part of objective function while optimum temperature is not defined"
);
return 1;
}
if (
(pa->pr_pair_weights.product_size_lt || pa->pr_pair_weights.product_size_gt) &&
(pa->product_opt_size == PR_UNDEFINED_INT_OPT)
) {
pr_append_new_chunk(
glob_err,
"Product size is part of objective function while optimum size is not defined"
);
return 1;
}
if (
(pa->p_args.weights.gc_content_lt || pa->p_args.weights.gc_content_gt) &&
(pa->p_args.opt_gc_content == DEFAULT_OPT_GC_PERCENT)
) {
pr_append_new_chunk(
glob_err,
"Primer GC content is part of objective function while optimum gc_content is not defined"
);
return 1;
}
if (
(pa->o_args.weights.gc_content_lt || pa->o_args.weights.gc_content_gt) &&
(pa->o_args.opt_gc_content == DEFAULT_OPT_GC_PERCENT)
) {
pr_append_new_chunk(
glob_err,
"Hyb probe GC content is part of objective function "
"while optimum gc_content is not defined"
);
return 1;
}
if (
(pa->pick_internal_oligo != 1) &&
(pa->pr_pair_weights.io_quality)
) {
pr_append_new_chunk(
glob_err,
"Internal oligo quality is part of objective function "
"while internal oligo choice is not required"
);
return 1;
}
if (
(pa->p_args.weights.repeat_sim) &&
(!seq_lib_num_seq(pa->p_args.repeat_lib))
) {
pr_append_new_chunk(
glob_err,
"Mispriming score is part of objective function, but mispriming library is not defined"
);
return 1;
}
if (
(pa->o_args.weights.repeat_sim) &&
(!seq_lib_num_seq(pa->o_args.repeat_lib))
) {
pr_append_new_chunk(
glob_err,
"Internal oligo mispriming score is part of objective function while mishyb library is not defined"
);
return 1;
}
if (
(pa->pr_pair_weights.repeat_sim) &&
(!(seq_lib_num_seq(pa->p_args.repeat_lib)))
) {
pr_append_new_chunk(
glob_err,
"Mispriming score is part of objective function, "
"but mispriming library is not defined"
);
return 1;
}
if (pa->pr_pair_weights.io_quality
&& pa->pick_internal_oligo == 0 ) {
pr_append_new_chunk(
glob_err,
"Internal oligo quality is part of objective function"
" while internal oligo choice is not required"
);
return 1;
}
if (pa->sequencing.lead < 0) {
pr_append_new_chunk(
glob_err,
"Illegal value for PRIMER_SEQUENCING_LEAD"
);
return 1;
}
if (pa->sequencing.interval < 0) {
pr_append_new_chunk(
glob_err,
"Illegal value for PRIMER_SEQUENCING_INTERVAL"
);
return 1;
}
if (pa->sequencing.accuracy < 0) {
pr_append_new_chunk(
glob_err,
"Illegal value for PRIMER_SEQUENCING_ACCURACY"
);
return 1;
}
if (pa->sequencing.spacing < 0) {
pr_append_new_chunk(
glob_err,
"Illegal value for PRIMER_SEQUENCING_SPACING"
);
return 1;
}
if (pa->sequencing.interval > pa->sequencing.spacing) {
pr_append_new_chunk(
glob_err,
"PRIMER_SEQUENCING_INTERVAL > PRIMER_SEQUENCING_SPACING"
);
return 1;
}
if (pa->sequencing.accuracy > pa->sequencing.spacing) {
pr_append_new_chunk(
glob_err,
"PRIMER_SEQUENCING_ACCURACY > PRIMER_SEQUENCING_SPACING"
);
return 1;
}
if (pa->sequencing.lead > pa->sequencing.spacing) {
pr_append_new_chunk(
glob_err,
"PRIMER_SEQUENCING_LEAD > PRIMER_SEQUENCING_SPACING"
);
return 1;
}
if ((sa->force_left_start > -1) && (sa->force_left_end > -1)
&& (sa->force_left_start > sa->force_left_end)) {
pr_append_new_chunk(
glob_err,
"SEQUENCE_FORCE_LEFT_START > SEQUENCE_FORCE_LEFT_END"
);
return 1;
}
if ((sa->force_right_end > -1) && (sa->force_right_start > -1)
&& (sa->force_right_end > sa->force_right_start)) {
pr_append_new_chunk(
glob_err,
"SEQUENCE_FORCE_RIGHT_END > SEQUENCE_FORCE_RIGHT_START"
);
return 1;
}
if (pa->p_args.min_5_prime_overlap_of_junction < 1) {
pr_append_new_chunk(
glob_err,
"Illegal value for PRIMER_MIN_5_PRIME_OVERLAP_OF_JUNCTION"
);
return 1;
}
if (pa->p_args.min_3_prime_overlap_of_junction < 1) {
pr_append_new_chunk(
glob_err,
"Illegal value for PRIMER_MIN_3_PRIME_OVERLAP_OF_JUNCTION"
);
return 1;
}
if (
(sa->primer_overlap_junctions_count > 0) &&
(pa->p_args.min_5_prime_overlap_of_junction > (pa->p_args.max_size / 2))
) {
pr_append_new_chunk(
glob_err,
"PRIMER_MIN_5_PRIME_OVERLAP_OF_JUNCTION > PRIMER_MAX_SIZE / 2"
);
return 1;
}
if (
(sa->primer_overlap_junctions_count > 0) &&
(pa->p_args.min_3_prime_overlap_of_junction > (pa->p_args.max_size / 2))
) {
pr_append_new_chunk(
glob_err,
"PRIMER_MIN_3_PRIME_OVERLAP_OF_JUNCTION > PRIMER_MAX_SIZE / 2"
);
return 1;
}
if (pa->o_args.min_5_prime_overlap_of_junction < 1) {
pr_append_new_chunk(
glob_err,
"Illegal value for PRIMER_INTERNAL_MIN_5_PRIME_OVERLAP_OF_JUNCTION"
);
return 1;
}
if (pa->o_args.min_3_prime_overlap_of_junction < 1) {
pr_append_new_chunk(
glob_err,
"Illegal value for PRIMER_INTERNAL_MIN_3_PRIME_OVERLAP_OF_JUNCTION"
);
return 1;
}
if (
(sa->primer_overlap_junctions_count > 0) &&
(pa->o_args.min_5_prime_overlap_of_junction > (pa->p_args.max_size / 2))
) {
pr_append_new_chunk(
glob_err,
"PRIMER_INTERNAL_MIN_5_PRIME_OVERLAP_OF_JUNCTION > PRIMER_MAX_SIZE / 2"
);
return 1;
}
if (
(sa->primer_overlap_junctions_count > 0) &&
(pa->o_args.min_3_prime_overlap_of_junction > (pa->p_args.max_size / 2))
) {
pr_append_new_chunk(
glob_err,
"PRIMER_INTERNAL_MIN_3_PRIME_OVERLAP_OF_JUNCTION > PRIMER_MAX_SIZE / 2"
);
return 1;
}
if (
(pa->p_args.divalent_conc > 0.0) &&
(pa->p_args.dntp_conc <= 0.0)
) {
pr_append_new_chunk(warning,
"PRIMER_SALT_DIVALENT > 0.0 "
"but PRIMER_DNTP_CONC <= 0.0; "
"use reasonable value for PRIMER_DNTP_CONC");
}
if (
(pa->p_args.must_match_five_prime != NULL) &&
(test_must_match_parameters(pa->p_args.must_match_five_prime))
) {
pr_append_new_chunk(
glob_err,
"Illegal values for PRIMER_MUST_MATCH_FIVE_PRIME"
);
return 1;
}
if (
(pa->p_args.must_match_three_prime != NULL) &&
(test_must_match_parameters(pa->p_args.must_match_three_prime))
) {
pr_append_new_chunk(
glob_err,
"Illegal values for PRIMER_MUST_MATCH_THREE_PRIME"
);
return 1;
}
if (
(pa->o_args.must_match_five_prime != NULL) &&
(test_must_match_parameters(pa->o_args.must_match_five_prime))
) {
pr_append_new_chunk(
glob_err,
"Illegal values for PRIMER_INTERNAL_MUST_MATCH_FIVE_PRIME"
);
return 1;
}
if (
(pa->o_args.must_match_three_prime != NULL) &&
(test_must_match_parameters(pa->o_args.must_match_three_prime))
) {
pr_append_new_chunk(
glob_err,
"Illegal values for PRIMER_INTERNAL_MUST_MATCH_THREE_PRIME"
);
return 1;
}
return (NULL == nonfatal_err->data && NULL == glob_err->data) ? 0 : 1;
} /* _pr_data_control */
static int
_check_and_adjust_overlap_pos(
seq_args_t* sa,
int* list,
int* count,
const char* tag,
int seq_len,
int first_index,
pr_append_str* nonfatal_err,
pr_append_str* warning
) {
int i;
int outside_warning_issued = 0;
char buffer[255];
if (*count == 0) {
return 0;
}
for (i = 0; i < *count; i++) {
/* Subtract first_index from the "must overlap" positions */
list[i] -= first_index;
if (list[i] >= seq_len) {
sprintf(buffer, "%s beyond end of sequence", tag);
pr_append_new_chunk(nonfatal_err, buffer);
return 1;
}
if (list[i] < 0) {
sprintf(buffer, "Negative %s length", tag);
pr_append_new_chunk(nonfatal_err, buffer);
return 1;
}
/* Cause the intron positions to be relative to the included region. */
list[i] -= sa->incl_s;
/* Check that intron positions are within the included region. */
if (list[i] < 0
|| list[i] > sa->incl_l) {
if (!outside_warning_issued) {
sprintf(buffer, "%s outside of INCLUDED_REGION", tag);
pr_append_new_chunk(warning, buffer);
outside_warning_issued = 1;
}
}
}
return 0;
}
/*
* Takes an upper case oligo sequence and a maximum allows number of
* identical consecutive base pairs. Returns 0 if a run of more than
* max_poly_x base pairs is not possible for seq and 1 otherwise.
*
* N can be any base and poly_x should be the worst case possible
* corner cases:
* NNG poly_x=3
* ANA poly_x=3
* CNN poly_x=3
* TNNG poly_x=3
* GNGNG poly_x=5
* ANGNG poly_x=4
*
* Algorithm - scan though seq from 0 to end considering all N bp to be
* the last seen non-N base pair. Then scan in the reverse direction
* and consider all N bp to the the last seen non-N base pair. The
* reverse scan can be skipped if seq does not contain any Ns.
*/
static int
_pr_violates_poly_x(
const char* seq,
int max_poly_x
) {
if (max_poly_x < 1) return 0;
const int len = strlen(seq);
if (len <= max_poly_x) return 0;
int i, poly_x;
int has_N = 0;
char last_non_N = seq[0];
poly_x = 1;
if (last_non_N == 'N') {
for (i=1; i max_poly_x) return 1;
} else if (seq[i] == last_non_N) {
poly_x++;
if (poly_x > max_poly_x) return 1;
} else {
poly_x = 1;
last_non_N = seq[i];
}
}
if (has_N == 0) return 0;
last_non_N = seq[len-1];
poly_x = 1;
if (last_non_N == 'N') {
for (i=len-2; i>=0; i--){
if (seq[i] != 'N') {
last_non_N = seq[i];
break;
}
}
}
for (i=len-2; i>=0; i--){
if (seq[i] == 'N' || seq[i] == last_non_N) {
poly_x++;
if (poly_x > max_poly_x) return 1;
} else {
poly_x = 1;
last_non_N = seq[i];
}
}
return 0;
}
static int
_check_and_adjust_intervals(
seq_args_t* sa,
int seq_len,
int first_index,
pr_append_str* nonfatal_err,
pr_append_str* warning
) {
if (
_check_and_adjust_1_interval(
"TARGET",
sa->tar2.count,
sa->tar2.pairs,
seq_len,
first_index,
nonfatal_err,
sa,
warning,
0
) == 1
) {
return 1;
}
sa->start_codon_pos -= sa->incl_s;
if (
_check_and_adjust_1_interval(
"EXCLUDED_REGION",
sa->excl2.count, sa->excl2.pairs,
seq_len, first_index,
nonfatal_err,
sa,
warning,
0
) == 1
) {
return 1;
}
if (
_check_and_adjust_1_interval(
"PRIMER_INTERNAL_OLIGO_EXCLUDED_REGION",
sa->excl_internal2.count,
sa->excl_internal2.pairs,
seq_len,
first_index,
nonfatal_err,
sa,
warning,
0
) == 1
) {
return 1;
}
if (
_check_and_adjust_1_interval(
"PRIMER_PAIR_OK_REGION_LIST",
sa->ok_regions.count,
sa->ok_regions.left_pairs,
seq_len,
first_index,
nonfatal_err,
sa,
warning,
1
) == 1
) {
return 1;
}
if (
_check_and_adjust_1_interval(
"PRIMER_PAIR_OK_REGION_LIST",
sa->ok_regions.count,
sa->ok_regions.right_pairs,
seq_len,
first_index,
nonfatal_err,
sa,
warning,
1
) == 1
) {
return 1;
}
return 0;
}
/*
* Check intervals, and add any errors to err.
* Update the start of each interval to
* be relative to the start of the included region.
*/
static int
_check_and_adjust_1_interval(
const char* tag_name,
int num_intervals,
interval_array_t intervals,
int seq_len,
int first_index,
pr_append_str* err,
seq_args_t* sa,
pr_append_str* warning,
int empty_allowed
) {
int i;
int outside_warning_issued = 0;
/* Subtract the first_index from the start positions in the interval
array */
for (i = 0; i < num_intervals; i++) {
if (empty_allowed && (intervals[i][0] == -1) && (intervals[i][1] == -1)) {
continue;
}
if (empty_allowed && (((intervals[i][0] == -1) && (intervals[i][1] != -1))
|| ((intervals[i][0] != -1) && (intervals[i][1] == -1)))) {
pr_append_new_chunk(err, tag_name);
pr_append(err, " illegal interval");
return 1;
}
intervals[i][0] -= first_index;
}
for (i=0; i < num_intervals; i++) {
if (empty_allowed && (intervals[i][0] == -1) && (intervals[i][1] == -1)) {
continue;
}
if (intervals[i][0] + intervals[i][1] > seq_len) {
pr_append_new_chunk(err, tag_name);
pr_append(err, " beyond end of sequence");
return 1;
}
/* Cause the interval start to be relative to the included region. */
intervals[i][0] -= sa->incl_s;
/* Check that intervals are within the included region. */
if (intervals[i][0] < 0
|| intervals[i][0] + intervals[i][1] > sa->incl_l) {
if (!outside_warning_issued) {
pr_append_new_chunk(warning, tag_name);
pr_append(warning,
" outside of INCLUDED_REGION");
outside_warning_issued = 1;
}
}
if (intervals[i][1] < 0) {
pr_append_new_chunk(err, "Negative ");
pr_append(err, tag_name);
pr_append(err, " length");
return 1;
}
}
return 0;
} /* _check_and_adjust_intervals */
/* ============================================================ */
/* END functions that check and modify the input */
/* ============================================================ */
/* ============================================================ */
/* BEGIN create primer files functions */
/* ============================================================ */
/* START OF WHAT SHOULD GO TO IO_PRIMER_FILES.C */
/*
Creates up to three files, the names of which are based on the
argument 'file_name'. One file is a table of forward primers, one
a table of reverse primers, and one a table of internal
hybridization oligos, depending on what the caller to
choose_primers() requested (in the 'pa' argument). Returns 0 on
success, 1 on error. On error, check errno for ENOMEM. Used to
implement P3_FILE_FLAG=1.
*/
int
p3_print_oligo_lists(
const p3retval* retval,
const seq_args_t* sa,
const p3_global_settings* pa,
pr_append_str* err,
const char* file_name
) {
/* Figure out if the sequence starts at position 1 or 0 */
int first_base_index = pa->first_base_index;
int ret;
/* Start building up a filename */
char* file = NULL;
FILE* fh;
if (setjmp(_jmp_buf) != 0) {
return 1; /* If we get here, that means we returned via a longjmp.
In this case errno should be ENOMEM. */
}
file = (char*) malloc((int) strlen(sa->sequence_name) + 5);
if (NULL == file) { return 1; } /* ENOMEM */
/* Check if the left primers have to be printed */
if ( pa->pick_left_primer ) {
/* Create the file name and open file*/
strcpy(file, sa->sequence_name);
strcat(file, ".for");
if (!(fh = fopen(file,"w"))) {
if (pr_append_new_chunk_external(err, "Unable to open file ")) {
return 1;
}
if (pr_append_external(err, file)) { return 1; }
if (pr_append_external(err, " for writing")) { return 1; }
free(file);
file = NULL;
return 1;
}
/* Print the content to the file */
ret = p3_print_one_oligo_list(
sa,
retval->fwd.num_elem,
retval->fwd.oligo,
OT_LEFT,
first_base_index,
NULL != pa->p_args.repeat_lib,
fh,
pa->thermodynamic_oligo_alignment
);
fclose(fh);
if (ret) { return 1; }
}
/* Check if the right primers have to be printed */
if (pa->pick_right_primer) {
strcpy(file, sa->sequence_name);
strcat(file, ".rev");
if (!(fh = fopen(file,"w"))) {
pr_append_new_chunk(err, "Unable to open file ");
pr_append(err, file);
pr_append(err, " for writing");
free(file);
file = NULL;
return 1;
}
/* Print the content to the file */
ret = p3_print_one_oligo_list(
sa,
retval->rev.num_elem,
retval->rev.oligo,
OT_RIGHT,
first_base_index,
NULL != pa->p_args.repeat_lib,
fh,
pa->thermodynamic_oligo_alignment
);
fclose(fh);
if (ret) { return 1; }
}
/* Check if the internal oligos have to be printed */
if (pa->pick_internal_oligo) {
/* Create the file name and open file*/
strcpy(file, sa->sequence_name);
strcat(file, ".int");
if (!(fh = fopen(file,"w"))) {
if (pr_append_new_chunk_external(err, "Unable to open file ")) {
return 1;
}
if (pr_append_external(err, file)) { return 1; }
if (pr_append_external(err, " for writing")) { return 1; }
free(file);
file = NULL;
return 1;
}
/* Print the content to the file */
ret = p3_print_one_oligo_list(
sa,
retval->intl.num_elem,
retval->intl.oligo,
OT_INTL,
first_base_index,
NULL != pa->o_args.repeat_lib,
fh,
pa->thermodynamic_oligo_alignment
);
fclose(fh);
if (ret) { return 1; }
}
free(file);
file = NULL;
return 0;
}
/* Print out the content of one primer array */
/* Return 1 on error, otherwise 0. */
int
p3_print_one_oligo_list(
const seq_args_t* sa,
int n,
const primer_rec* oligo_arr,
const oligo_type o_type,
const int first_base_index,
const int print_lib_sim,
FILE* fh,
const int thermodynamic_oligo_alignment
) {
int i;
/* Print out the header for the table */
if (print_list_header(fh, o_type, first_base_index, print_lib_sim, thermodynamic_oligo_alignment)) {
return 1; /* error */
}
/* Iterate over the array */
for (i = 0; i < n; i++) {
/* Print each single oligo */
if (print_oligo(fh, sa, i, &oligo_arr[i], o_type,
first_base_index, print_lib_sim, thermodynamic_oligo_alignment)) {
return 1; /* error */
}
}
return 0; /* success */
}
static int
print_list_header(
FILE* fh,
oligo_type type,
int first_base_index,
int print_lib_sim,
int thermodynamic_oligo_alignment
) {
int ret;
ret = fprintf(fh, "ACCEPTABLE %s\n",
OT_LEFT == type ? "LEFT PRIMERS"
: OT_RIGHT == type ? "RIGHT PRIMERS" : "INTERNAL OLIGOS");
if (ret < 0) { return 1; }
ret = fprintf(fh, " %4d-based ",
first_base_index);
if (ret < 0) { return 1; }
if (thermodynamic_oligo_alignment) {
ret = fprintf(fh, "# self self hair-");
} else {
ret = fprintf(fh, "# self self");
}
if (ret < 0) { return 1; }
if (print_lib_sim) {
/* ret = fprintf(fh, "# self self lib qual-\n"); */
ret = fprintf(fh, " lib");
}
if (ret < 0) { return 1; }
ret = fprintf(fh, " qual-\n");
if (ret < 0) { return 1; }
ret = fprintf(fh, " # sequence start ln ");
if (ret < 0) { return 1; }
ret = fprintf(fh, "N GC%% Tm");
if (ret < 0) { return 1; }
if (thermodynamic_oligo_alignment) {
ret = fprintf(fh, " any_th end_th pin");
} else {
ret = fprintf(fh, " any end");
}
if (ret < 0) { return 1; }
if (print_lib_sim) {
ret = fprintf(fh, " sim lity\n");
} else {
ret = fprintf(fh, " lity\n");
}
if (ret < 0) { return 1; }
return 0;
}
static int
print_oligo(
FILE* fh,
const seq_args_t* sa,
int index,
const primer_rec* h,
oligo_type type,
int first_base_index,
int print_lib_sim,
int thermodynamical_approach
) {
int ret;
/* WARNING, *p points to static storage that is overwritten on next
call to pr_oligo_sequence or pr_oligo_rev_c_sequence. */
char*p =
(OT_RIGHT != type)
? pr_oligo_sequence(sa, h)
: pr_oligo_rev_c_sequence(sa, h);
ret = fprintf(fh,
"%4d %-30s %5d %2d %2d %5.2f %5.3f %5.2f %5.2f",
index, p, h->start+sa->incl_s + first_base_index,
h->length,
h->num_ns, h->gc_content, h->temp,
h->self_any,
h->self_end);
if (ret < 0) { return 1; }
if (1==thermodynamical_approach) {
ret = fprintf(fh, " %5.2f", h->hairpin_th);
if (ret < 0) { return 1; }
}
if (ret < 0) { return 1; }
if (print_lib_sim) {
PR_ASSERT(h->repeat_sim.score != NULL);
ret = fprintf(fh, " %5.2f",
h->repeat_sim.score[h->repeat_sim.max]);
if (ret < 0) { return 1; }
}
ret = fprintf(fh, " %6.3f\n", h->quality);
if (ret < 0) { return 1; }
else return 0;
}
/* END OF WHAT SHOULD GO TO IO_PRIMER_FILES.C */
/* ============================================================ */
/* END create primer files functions */
/* ============================================================ */
/* ============================================================
* BEGIN p3_read_line, a utility used
* both for reading boulder input and for reading sequence
* libraries.
* ============================================================ */
/* Read a line of any length from file. Return NULL on end of file,
* otherwise return a pointer to static storage containing the line. Any
* trailing newline is stripped off. Be careful -- there is only
* one static buffer, so subsequent calls will replace the string
* pointed to by the return value.
* Used in seq_lib functions and also exported
* used in p3_read_line and seq_lib functions
* */
#define INIT_BUF_SIZE 1024
char*
p3_read_line(
FILE* file
) {
static size_t ssz;
static char*s = NULL;
size_t remaining_size;
char*p, *n;
if (NULL == s) {
ssz = INIT_BUF_SIZE;
s = (char*) pr_safe_malloc(ssz);
}
p = s;
remaining_size = ssz;
while (1) {
if (fgets(p, remaining_size, file) == NULL) { /* End of file. */
if (p == s) {
ssz = 0;
if (s != NULL) {
free(s);
}
s = NULL;
return NULL;
} else {
return s;
}
}
if ((n = strchr(p, '\n')) != NULL) {
*n = '\0';
n--;
if ((n >= p) && (*n == '\r')) {
*n = '\0';
}
return s;
}
/* We did not get the whole line. */
/*
* The following assertion is a bit of hack, a at least for 32-bit
* machines, because we will usually run out of address space first.
* Really we should treat an over-long line as an input error, but
* since an over-long line is unlikely and we do want to provide some
* protection....
*/
PR_ASSERT(ssz <= INT_MAX);
if (ssz >= INT_MAX / 2) {
ssz = INT_MAX;
} else {
ssz *= 2;
}
s = (char*) pr_safe_realloc(s, ssz);
p = strchr(s, '\0');
remaining_size = ssz - (p - s);
}
}
/* ============================================================ */
/* END p3_read_line */
/* ============================================================ */
/* ============================================================ */
/* BEGIN 'get' functions for seq_args_t */
/* ============================================================ */
const interval_array_t2*
p3_get_sa_tar2(
const seq_args_t* sargs
) {
return &sargs->tar2 ;
}
const interval_array_t2*
p3_get_sa_excl2(
const seq_args_t* sargs
) {
return &sargs->excl2 ;
}
const interval_array_t2*
p3_get_sa_excl_internal2(
const seq_args_t* sargs
) {
return &sargs->excl_internal2 ;
}
const interval_array_t4*
p3_get_sa_ok_regions(
const seq_args_t* sargs
) {
return &sargs->ok_regions;
}
const int*
p3_get_sa_overlap_junctions(
const seq_args_t* sargs
) {
return sargs->primer_overlap_junctions;
}
const int*
p3_get_sa_intl_overlap_junctions(
const seq_args_t* sargs
) {
return sargs->intl_overlap_junctions;
}
/* ============================================================ */
/* END 'get' functions for seq_args_t */
/* ============================================================ */
int
p3_get_sa_n_quality(
seq_args_t* sargs
) {
return sargs->n_quality ;
}
/* ============================================================ */
/* BEGIN 'set' functions for seq_args_t */
/* ============================================================ */
int
p3_set_sa_sequence(
seq_args_t* sargs,
const char* sequence
) {
return _set_string(&sargs->sequence, sequence) ;
}
void
p3_set_sa_primer_sequence_quality(
seq_args_t* sargs,
int quality
) {
sargs->quality[sargs->n_quality++] = quality ;
}
int
p3_set_sa_sequence_name(
seq_args_t* sargs,
const char* sequence_name
) {
return _set_string(&sargs->sequence_name, sequence_name);
}
int
p3_set_sa_left_input(
seq_args_t* sargs,
const char* s
) {
return _set_string(&sargs->left_input, s);
}
int
p3_set_sa_right_input(
seq_args_t* sargs,
const char* s
) {
return _set_string(&sargs->right_input, s);
}
int
p3_set_sa_internal_input(
seq_args_t* sargs,
const char* s
) {
return _set_string(&sargs->internal_input, s);
}
void
p3_set_sa_incl_s(
seq_args_t* sargs,
int incl_s
) {
sargs->incl_s = incl_s;
}
void
p3_set_sa_incl_l(
seq_args_t* sargs,
int incl_l
) {
sargs->incl_l = incl_l;
}
void
p3_set_sa_empty_quality(
seq_args_t* sargs
) {
sargs->n_quality = 0;
}
void
p3_sa_add_to_quality_array(
seq_args_t* sargs,
int quality
) {
int n = sargs->n_quality;
if (sargs->quality_storage_size == 0) {
sargs->quality_storage_size = 3000;
sargs->quality = (int* ) pr_safe_malloc(
sizeof(int) * sargs->quality_storage_size
);
}
if (n > sargs->quality_storage_size) {
sargs->quality_storage_size *= 2;
sargs->quality = (int* ) pr_safe_realloc(
sargs->quality,
sizeof(int) * sargs->quality_storage_size
);
}
sargs->quality[n] = quality;
sargs->n_quality++;
}
int
p3_sa_add_to_overlap_junctions_array(
seq_args_t* sargs,
int overlap
) {
int c = sargs->primer_overlap_junctions_count;
if (c >= PR_MAX_INTERVAL_ARRAY) { return 1; }
sargs->primer_overlap_junctions[sargs->primer_overlap_junctions_count++] = overlap;
return 0;
}
int
p3_sa_add_to_intl_overlap_junctions_array(
seq_args_t* sargs,
int overlap
) {
int c = sargs->intl_overlap_junctions_count;
if (c >= PR_MAX_INTERVAL_ARRAY) return 1;
sargs->intl_overlap_junctions[sargs->intl_overlap_junctions_count++] = overlap;
return 0;
}
void
p3_set_sa_start_codon_pos(
seq_args_t* sargs,
int start_codon_pos
) {
sargs->start_codon_pos = start_codon_pos;
}
int
p3_add_to_sa_tar2(
seq_args_t* sargs,
int n1,
int n2
) {
return p3_add_to_interval_array(&sargs->tar2, n1, n2);
}
int
p3_add_to_sa_excl2(
seq_args_t* sargs,
int n1,
int n2
) {
return p3_add_to_interval_array(&sargs->excl2, n1, n2);
}
int
p3_add_to_sa_excl_internal2(
seq_args_t* sargs,
int n1,
int n2
) {
return p3_add_to_interval_array(&sargs->excl_internal2, n1, n2);
}
int
p3_add_to_sa_ok_regions(
seq_args_t* sargs,
int l1,
int l2,
int r1,
int r2
) {
return p3_add_to_2_interval_array(&sargs->ok_regions, l1, l2, r1, r2);
}
/* ============================================================ */
/* END 'set' functions for seq_args_t */
/* ============================================================ */
/* ============================================================ */
/* BEGIN 'get' functions for p3_global_settings */
/* ============================================================ */
args_for_one_oligo_or_primer*
p3_get_gs_p_args(
p3_global_settings* p
) {
return &p->p_args;
}
args_for_one_oligo_or_primer*
p3_get_gs_o_args(
p3_global_settings* p
) {
return &p->o_args;
}
/* ============================================================ */
/* END 'get' functions for p3_global_settings */
/* ============================================================ */
/* ============================================================ */
/* BEGIN 'set' functions for p3_global_settings */
/* ============================================================ */
void
p3_set_gs_primer_task(p3_global_settings* pa , char* task_tmp)
{
if (!strcmp_nocase(task_tmp, "pick_pcr_primers")) {
pa->primer_task = generic_p3;
pa->pick_left_primer = 1;
pa->pick_right_primer = 1;
pa->pick_internal_oligo = 0;
} else if (!strcmp_nocase(task_tmp, "pick_pcr_primers_and_hyb_probe")) {
pa->primer_task = generic_p3;
pa->pick_left_primer = 1;
pa->pick_right_primer = 1;
pa->pick_internal_oligo = 1;
} else if (!strcmp_nocase(task_tmp, "pick_left_only")) {
pa->primer_task = generic_p3;
pa->pick_left_primer = 1;
pa->pick_right_primer = 0;
pa->pick_internal_oligo = 0;
} else if (!strcmp_nocase(task_tmp, "pick_right_only")) {
pa->primer_task = generic_p3;
pa->pick_left_primer = 0;
pa->pick_right_primer = 1;
pa->pick_internal_oligo = 0;
} else if (!strcmp_nocase(task_tmp, "pick_hyb_probe_only")) {
pa->primer_task = generic_p3;
pa->pick_left_primer = 0;
pa->pick_right_primer = 0;
pa->pick_internal_oligo = 1;
} else if (!strcmp_nocase(task_tmp, "generic")) {
pa->primer_task = generic_p3;
} else if (!strcmp_nocase(task_tmp, "pick_detection_primers")) {
pa->primer_task = generic_p3; /* Deliberate duplication for
backward compatibility. */
} else if (!strcmp_nocase(task_tmp, "pick_cloning_primers")) {
pa->primer_task = pick_cloning_primers;
} else if (!strcmp_nocase(task_tmp, "pick_discriminative_primers")) {
pa->primer_task = pick_discriminative_primers;
} else if (!strcmp_nocase(task_tmp, "pick_sequencing_primers")) {
pa->primer_task = pick_sequencing_primers;
} else if (!strcmp_nocase(task_tmp, "pick_primer_list")) {
pa->primer_task = pick_primer_list;
} else if (!strcmp_nocase(task_tmp, "check_primers")) {
pa->primer_task = check_primers;
}
}
int
p3_add_to_gs_product_size_range(
p3_global_settings* pgs,
int n1,
int n2
) {
if (pgs->num_intervals >= PR_MAX_INTERVAL_ARRAY) {
return 1;
}
pgs->pr_min[pgs->num_intervals] = n1;
pgs->pr_max[pgs->num_intervals] = n2;
pgs->num_intervals++;
return 0;
}
/* ============================================================ */
/* END 'set' functions for p3_global_settings */
/* ============================================================ */
/* ============================================================ */
/* START functions for setting and getting oligo problems */
/* ============================================================ */
static void
initialize_op(
primer_rec* oligo
) {
oligo->problems.prob = 0UL; /* 0UL is the unsigned long zero */
}
/* We use bitfields to store all primer data. The idea is that
* a primer is uninitialized if all bits are 0. It was evaluated
* if OP_PARTIALLY_WRITTEN is true. If OP_COMPLETELY_WRITTEN is
* also true the primer was evaluated till the end - meaning if
* all OP_... are false, the primer is OK, if some are true
* primer3 was forced to use it (must_use). */
#define OP_PARTIALLY_WRITTEN (1UL << 0)
#define OP_COMPLETELY_WRITTEN (1UL << 1)
#define BF_OVERLAPS_TARGET (1UL << 2)
#define BF_OVERLAPS_EXCL_REGION (1UL << 3)
#define BF_INFINITE_POSITION_PENALTY (1UL << 4)
/* Space for more bitfields */
#define OP_HIGH_BOUND (1UL << 5)
#define OP_LOW_BOUND (1UL << 6)
#define OP_NOT_IN_ANY_OK_REGION (1UL << 7)
#define OP_TOO_MANY_NS (1UL << 8) /* 3prime problem*/
#define OP_OVERLAPS_TARGET (1UL << 9) /* 3prime problem*/
#define OP_HIGH_GC_CONTENT (1UL << 10)
#define OP_LOW_GC_CONTENT (1UL << 11)
#define OP_HIGH_TM (1UL << 12)
#define OP_LOW_TM (1UL << 13)
#define OP_OVERLAPS_EXCL_REGION (1UL << 14) /* 3prime problem*/
#define OP_HIGH_SELF_ANY (1UL << 15) /* 3prime problem*/
#define OP_HIGH_SELF_END (1UL << 16)
#define OP_NO_GC_CLAMP (1UL << 17) /* 3prime problem*/
#define OP_HIGH_END_STABILITY (1UL << 18) /* 3prime problem*/
#define OP_HIGH_POLY_X (1UL << 19) /* 3prime problem*/
#define OP_LOW_SEQUENCE_QUALITY (1UL << 20) /* 3prime problem*/
#define OP_LOW_END_SEQUENCE_QUALITY (1UL << 21) /* 3prime problem*/
#define OP_HIGH_SIM_TO_NON_TEMPLATE_SEQ (1UL << 22) /* 3prime problem*/
#define OP_HIGH_SIM_TO_MULTI_TEMPLATE_SITES (1UL << 23)
#define OP_OVERLAPS_MASKED_SEQ (1UL << 24)
#define OP_TOO_LONG (1UL << 25) /* 3prime problem*/
#define OP_TOO_SHORT (1UL << 26)
#define OP_DOES_NOT_AMPLIFY_ORF (1UL << 27)
#define OP_TOO_MANY_GC_AT_END (1UL << 28) /* 3prime problem*/
#define OP_HIGH_HAIRPIN (1UL << 29) /* 3prime problem*/
#define OP_MUST_MATCH_ERR (1UL << 30)
/* Space for more Errors */
/* Tip: the calculator of windows (in scientific mode) can easily convert
between decimal and binary numbers */
/* all bits 1 except bits 0 to 6 */
/* (~0UL) ^ 31UL = 1111 1111 1111 1111 1111 1111 1110 0000 */
static unsigned long int any_problem = (~0UL) ^ 31UL;
/* 310297344UL = 0001 0010 0111 1110 1100 0011 0000 0000 */
static unsigned long int five_prime_problem = 310297344UL;
int
p3_ol_is_uninitialized(
const primer_rec* oligo
) {
return (oligo->problems.prob == 0UL);
}
int
p3_ol_is_ok(
const primer_rec* oligo
) {
return (oligo->problems.prob & OP_COMPLETELY_WRITTEN) != 0;
}
/*
Return 1 iff the argument 'oligo' has any problems -- i.e.
violations of design constraints.
*/
int
p3_ol_has_any_problem(
const primer_rec* oligo
) {
return (oligo->problems.prob & any_problem) != 0;
}
static int
any_5_prime_ol_extension_has_problem(
const primer_rec* oligo
) {
return (oligo->problems.prob & five_prime_problem) != 0;
}
/*
Return a string details the the problems in 'oligo', i.e. the
constraints that 'oligo' violates. WARNING: Returns a pointer to
static storage, which is over-written on next call.
*/
#define ADD_OP_STR(COND, STR) if (prob & COND) { tmp = STR; strcpy(next, tmp); next += (int)strlen(tmp); }
const char*
p3_get_ol_problem_string(
const primer_rec* oligo
) {
static char output[4096*2]; /* WARNING, make sure all error strings
concatenated will not overflow this
buffer. */
char*next = output;
const char* tmp;
unsigned long int prob = oligo->problems.prob;
output[0] = '\0';
if (
(prob & OP_PARTIALLY_WRITTEN)
&&
!(prob & OP_COMPLETELY_WRITTEN)
) {
tmp = " Not completely checked;";
strcpy(next, tmp);
next += (int)strlen(tmp);
}
{
ADD_OP_STR(OP_TOO_MANY_NS,
" Too many Ns;")
ADD_OP_STR(OP_OVERLAPS_TARGET,
" Overlaps target;")
ADD_OP_STR(OP_HIGH_GC_CONTENT,
" GC content too high;")
ADD_OP_STR(OP_LOW_GC_CONTENT,
" GC content too low;")
ADD_OP_STR(OP_HIGH_TM,
" Temperature too high;")
ADD_OP_STR(OP_LOW_TM,
" Temperature too low;")
ADD_OP_STR(OP_HIGH_BOUND,
" Fraction bound too high;")
ADD_OP_STR(OP_LOW_BOUND,
" Fraction bound too low;")
ADD_OP_STR(OP_OVERLAPS_EXCL_REGION,
" Overlaps an excluded region;")
ADD_OP_STR(OP_NOT_IN_ANY_OK_REGION,
" Not in any ok region;")
ADD_OP_STR(OP_HIGH_SELF_ANY,
" Similarity to self too high;")
ADD_OP_STR(OP_HIGH_SELF_END,
" Similary to 3' end of self too high;")
ADD_OP_STR(OP_HIGH_HAIRPIN,
" Hairpin stability too high;")
ADD_OP_STR(OP_NO_GC_CLAMP,
" No 3' GC clamp;")
ADD_OP_STR(OP_TOO_MANY_GC_AT_END,
" Too many GCs at 3' end;")
ADD_OP_STR(OP_HIGH_END_STABILITY,
" 3' end too stable (delta-G too high);")
ADD_OP_STR(OP_HIGH_POLY_X,
" Contains too-long poly nucleotide tract;")
ADD_OP_STR(OP_LOW_SEQUENCE_QUALITY,
" Template sequence quality too low;")
ADD_OP_STR(OP_LOW_END_SEQUENCE_QUALITY,
" Template sequence quality at 3' end too low;")
ADD_OP_STR(OP_HIGH_SIM_TO_NON_TEMPLATE_SEQ,
" Similarity to non-template sequence too high;")
ADD_OP_STR(OP_HIGH_SIM_TO_MULTI_TEMPLATE_SITES,
" Similarity to multiple sites in template;")
ADD_OP_STR(OP_OVERLAPS_MASKED_SEQ,
" 3' base overlaps masked sequence;")
ADD_OP_STR(OP_TOO_LONG,
" Too long;")
ADD_OP_STR(OP_TOO_SHORT,
" Too short;")
ADD_OP_STR(OP_DOES_NOT_AMPLIFY_ORF,
" Would not amplify an open reading frame;")
ADD_OP_STR(OP_MUST_MATCH_ERR,
" Failed must_match requirements;")
}
return output;
}
#undef ADD_OP_STR
static void
bf_set_overlaps_target(
primer_rec* oligo,
int val
) {
if (val == 0) {
oligo->problems.prob |= BF_OVERLAPS_TARGET;
oligo->problems.prob ^= BF_OVERLAPS_TARGET;
} else {
oligo->problems.prob |= BF_OVERLAPS_TARGET;
}
}
static int
bf_get_overlaps_target(
const primer_rec* oligo
) {
return (oligo->problems.prob & BF_OVERLAPS_TARGET) != 0;
}
static void
bf_set_overlaps_excl_region(
primer_rec* oligo,
int val
) {
if (val == 0) {
oligo->problems.prob |= BF_OVERLAPS_EXCL_REGION;
oligo->problems.prob ^= BF_OVERLAPS_EXCL_REGION;
} else {
oligo->problems.prob |= BF_OVERLAPS_EXCL_REGION;
}
}
static int
bf_get_overlaps_excl_region(
const primer_rec* oligo
) {
return (oligo->problems.prob & BF_OVERLAPS_EXCL_REGION) != 0;
}
static void
bf_set_infinite_pos_penalty(primer_rec* oligo, int val){
if (val == 0) {
oligo->problems.prob |= BF_INFINITE_POSITION_PENALTY;
oligo->problems.prob ^= BF_INFINITE_POSITION_PENALTY;
} else {
oligo->problems.prob |= BF_INFINITE_POSITION_PENALTY;
}
}
static int
bf_get_infinite_pos_penalty(
const primer_rec* oligo
) {
return (oligo->problems.prob & BF_INFINITE_POSITION_PENALTY) != 0;
}
static void
op_set_does_not_amplify_orf(
primer_rec* oligo
) {
oligo->problems.prob |= OP_DOES_NOT_AMPLIFY_ORF;
oligo->problems.prob |= OP_PARTIALLY_WRITTEN;
}
static void
op_set_completely_written(
primer_rec* oligo
) {
oligo->problems.prob |= OP_COMPLETELY_WRITTEN;
}
static void
op_set_must_match_err(
primer_rec* oligo
) {
oligo->problems.prob |= OP_MUST_MATCH_ERR;
oligo->problems.prob |= OP_PARTIALLY_WRITTEN;
}
static void
op_set_too_many_ns(
primer_rec* oligo
) {
oligo->problems.prob |= OP_TOO_MANY_NS;
oligo->problems.prob |= OP_PARTIALLY_WRITTEN;
}
static void
op_set_overlaps_target(
primer_rec* oligo
) {
oligo->problems.prob |= OP_OVERLAPS_TARGET;
oligo->problems.prob |= OP_PARTIALLY_WRITTEN;
}
static void
op_set_high_gc_content(
primer_rec* oligo
) {
oligo->problems.prob |= OP_HIGH_GC_CONTENT;
oligo->problems.prob |= OP_PARTIALLY_WRITTEN;
}
static void
op_set_low_gc_content(
primer_rec* oligo
) {
oligo->problems.prob |= OP_LOW_GC_CONTENT;
oligo->problems.prob |= OP_PARTIALLY_WRITTEN;
}
static void
op_set_high_tm(
primer_rec* oligo
) {
oligo->problems.prob |= OP_HIGH_TM;
oligo->problems.prob |= OP_PARTIALLY_WRITTEN;
}
static void
op_set_low_tm(
primer_rec* oligo
) {
oligo->problems.prob |= OP_LOW_TM;
oligo->problems.prob |= OP_PARTIALLY_WRITTEN;
}
static void
op_set_high_bound(
primer_rec* oligo
) {
oligo->problems.prob |= OP_HIGH_BOUND;
oligo->problems.prob |= OP_PARTIALLY_WRITTEN;
}
static void
op_set_low_bound(
primer_rec* oligo
) {
oligo->problems.prob |= OP_LOW_BOUND;
oligo->problems.prob |= OP_PARTIALLY_WRITTEN;
}
static void
op_set_overlaps_excluded_region(
primer_rec* oligo
) {
oligo->problems.prob |= OP_OVERLAPS_EXCL_REGION;
oligo->problems.prob |= OP_PARTIALLY_WRITTEN;
}
static void
op_set_not_in_any_ok_region(
primer_rec* oligo
) {
oligo->problems.prob |= OP_NOT_IN_ANY_OK_REGION;
oligo->problems.prob |= OP_PARTIALLY_WRITTEN;
}
static void
op_set_high_self_any(
primer_rec* oligo
) {
oligo->problems.prob |= OP_HIGH_SELF_ANY;
oligo->problems.prob |= OP_PARTIALLY_WRITTEN;
}
static void
op_set_high_self_end(
primer_rec* oligo
) {
oligo->problems.prob |= OP_HIGH_SELF_END;
oligo->problems.prob |= OP_PARTIALLY_WRITTEN;
}
static void
op_set_high_hairpin_th(
primer_rec* oligo
) {
oligo->problems.prob |= OP_HIGH_HAIRPIN;
oligo->problems.prob |= OP_PARTIALLY_WRITTEN;
}
static void
op_set_no_gc_glamp(
primer_rec* oligo
) {
oligo->problems.prob |= OP_NO_GC_CLAMP;
oligo->problems.prob |= OP_PARTIALLY_WRITTEN;
}
static void
op_set_too_many_gc_at_end(
primer_rec* oligo
) {
oligo->problems.prob |= OP_TOO_MANY_GC_AT_END;
oligo->problems.prob |= OP_PARTIALLY_WRITTEN;
}
/* Must not be called on a hybridization probe / internal oligo */
static void
op_set_high_end_stability(
primer_rec* oligo
) {
oligo->problems.prob |= OP_HIGH_END_STABILITY;
oligo->problems.prob |= OP_PARTIALLY_WRITTEN;
}
static void
op_set_high_poly_x(
primer_rec* oligo
) {
oligo->problems.prob |= OP_HIGH_POLY_X;
oligo->problems.prob |= OP_PARTIALLY_WRITTEN;
}
static void
op_set_low_sequence_quality(
primer_rec* oligo
) {
oligo->problems.prob |= OP_LOW_SEQUENCE_QUALITY;
oligo->problems.prob |= OP_PARTIALLY_WRITTEN;
}
static void
op_set_low_end_sequence_quality(
primer_rec* oligo
) {
oligo->problems.prob |= OP_LOW_END_SEQUENCE_QUALITY;
oligo->problems.prob |= OP_PARTIALLY_WRITTEN;
}
static void
op_set_high_similarity_to_non_template_seq(
primer_rec* oligo
) {
oligo->problems.prob |= OP_HIGH_SIM_TO_NON_TEMPLATE_SEQ;
oligo->problems.prob |= OP_PARTIALLY_WRITTEN;
}
static void
op_set_high_similarity_to_multiple_template_sites(
primer_rec* oligo
) {
oligo->problems.prob |= OP_HIGH_SIM_TO_MULTI_TEMPLATE_SITES;
oligo->problems.prob |= OP_PARTIALLY_WRITTEN;
}
static void
op_set_overlaps_masked_sequence(
primer_rec* oligo
) {
oligo->problems.prob |= OP_OVERLAPS_MASKED_SEQ;
oligo->problems.prob |= OP_PARTIALLY_WRITTEN;
}
static void
op_set_too_long(
primer_rec* oligo
) {
oligo->problems.prob |= OP_TOO_LONG;
oligo->problems.prob |= OP_PARTIALLY_WRITTEN;
}
static void
op_set_too_short(
primer_rec* oligo
) {
oligo->problems.prob |= OP_TOO_SHORT;
oligo->problems.prob |= OP_PARTIALLY_WRITTEN;
}
/* ============================================================ */
/* END functions for setting and getting oligo problems */
/* ============================================================ */
/* ============================================================ */
/* START functions for getting values from p3retvals */
/* ============================================================ */
char*
p3_get_rv_and_gs_warnings(
const p3retval* retval,
const p3_global_settings* pa
) {
pr_append_str warning;
PR_ASSERT(NULL != pa);
init_pr_append_str(&warning);
if (seq_lib_warning_data(pa->p_args.repeat_lib)) {
pr_append_new_chunk(&warning, seq_lib_warning_data(pa->p_args.repeat_lib));
}
if (seq_lib_warning_data(pa->o_args.repeat_lib)) {
pr_append_new_chunk(&warning, seq_lib_warning_data(pa->o_args.repeat_lib));
pr_append(&warning, " (for internal oligo)");
}
if (!pr_is_empty(&retval->warnings)) {
pr_append_new_chunk(&warning, retval->warnings.data);
}
return pr_is_empty(&warning) ? NULL : warning.data;
}
const char*
p3_get_rv_global_errors(
const p3retval* retval
) {
return retval->glob_err.data;
}
const char*
p3_get_rv_per_sequence_errors(
const p3retval* retval
) {
return retval->per_sequence_err.data;
}
p3_output_type
p3_get_rv_output_type(
const p3retval* r
) {
return r->output_type;
}
const char*
p3_get_rv_warnings(
const p3retval* r
) {
return pr_append_str_chars(&r->warnings);
}
int
p3_get_rv_stop_codon_pos(
p3retval* r
) {
return r->stop_codon_pos;
}
/* ============================================================ */
/* END functions for getting values from p3retvals */
/* ============================================================ */
void
print_masking_parameters(
const masker_parameters* mp,
FILE* fd
) {
if (mp == NULL){
return;
}
// unsigned int i;
fprintf (fd, "Current masker parameters:\n");
fprintf (fd, " masking_direction = %s\n", mp->mdir == both_on_same ? "both" : (mp->mdir == fwd ? "fwd" : "rev"));
fprintf (fd, " failure_rate = %f\n", mp->failure_rate);
fprintf (fd, " abs_cutoff = %u\n", mp->abs_cutoff);
fprintf (fd, " m5p = %u\n", mp->nucl_masked_in_5p_direction);
fprintf (fd, " m3p = %u\n", mp->nucl_masked_in_3p_direction);
fprintf (fd, " print_sequence = %d\n", mp->print_sequence);
fprintf (fd, " do_soft_masking = %d\n", mp->do_soft_masking);
fprintf (fd, " masking_char = %c\n", mp->masking_char);
fprintf (fd, " nlists = %u\n", mp->nlists);
fprintf (fd, " intercept = %f\n", mp->formula_intercept);
// for (i = 0; i < mp->nlists; i++) {
// fprintf (fd, " LIST: %u\n", i);
// formula_parameters *fp = mp->fp[i];
// if (!fp) continue;
// fprintf (fd, " name = %s\n", fp->list_file_name);
// fprintf (fd, " oligo_length = %u\n", fp->oligo_length);
// fprintf (fd, " words_in_list = %llu\n", fp->words_in_list);
// fprintf (fd, " mm0 %f mm1 %f mm2 %f mm0_2 %f mm1_2 %f mm2_2 %f\n", fp->mm0, fp->mm1, fp->mm2, fp->mm0_2, fp->mm1_2, fp->mm2_2);
// }
return;
}
void
p3_print_args(
const p3_global_settings* p,
seq_args_t* s
) {
p3_print_args_fd(p, s, stdout);
}
void
p3_print_args_fd(
const p3_global_settings* p,
seq_args_t* s,
FILE* fd
) {
int i;
if (p != NULL) {
fprintf(fd, "=============\n");
fprintf(fd, "BEGIN GLOBAL ARGS\n") ;
fprintf(fd, " primer_task %i\n", p->primer_task);
fprintf(fd, " pick_left_primer %i\n", p->pick_left_primer);
fprintf(fd, " pick_right_primer %i\n", p->pick_right_primer);
fprintf(fd, " pick_internal_oligo %i\n", p->pick_internal_oligo);
fprintf(fd, " file_flag %i\n", p->file_flag) ;
fprintf(fd, " first_base_index %i\n", p->first_base_index);
fprintf(fd, " liberal_base %i\n", p->liberal_base );
fprintf(fd, " num_return %i\n", p->num_return) ;
fprintf(fd, " pick_anyway %i\n", p->pick_anyway);
fprintf(fd, " lib_ambiguity_codes_consensus %i\n",
p->lib_ambiguity_codes_consensus) ;
fprintf(fd, " quality_range_min %i\n", p->quality_range_min) ;
fprintf(fd, " quality_range_max %i\n", p->quality_range_max) ;
fprintf(fd, " tm_santalucia %i\n", p->tm_santalucia) ;
fprintf(fd, " salt_corrections %i\n", p->salt_corrections) ;
fprintf(fd, " annealing_temp %f\n", p->annealing_temp) ;
fprintf(fd, " max_end_stability %f\n", p->max_end_stability) ;
fprintf(fd, " gc_clamp %i\n", p->gc_clamp) ;
fprintf(fd, " max_end_gc %i\n", p->max_end_gc);
fprintf(fd, " lowercase_masking %i\n", p->lowercase_masking) ;
fprintf(fd, " thermodynamic_oligo_alignment %i\n", p->thermodynamic_oligo_alignment);
fprintf(fd, " thermodynamic_template_alignment %i\n", p->thermodynamic_template_alignment);
fprintf(fd, " outside_penalty %f\n", p->outside_penalty) ;
fprintf(fd, " inside_penalty %f\n", p->inside_penalty) ;
fprintf(fd, " number of product size ranges: %d\n", p->num_intervals);
fprintf(fd, " product size ranges:\n");
for (i = 0; i < p->num_intervals; i++) {
fprintf(fd, " %d - %d \n", p->pr_min[i], p->pr_max[i]);
}
fprintf(fd, " product_opt_size %i\n", p->product_opt_size) ;
fprintf(fd, " product_max_tm %f\n", p->product_max_tm) ;
fprintf(fd, " product_min_tm %f\n", p->product_min_tm) ;
fprintf(fd, " product_opt_tm %f\n", p->product_opt_tm) ;
fprintf(fd, " pair_max_template_mispriming %f\n", p->pair_max_template_mispriming) ;
fprintf(fd, " pair_max_template_mispriming_th %f\n", p->pair_max_template_mispriming_th) ;
fprintf(fd, " pair_repeat_compl %f\n", p->pair_repeat_compl) ;
fprintf(fd, " pair_compl_any %f\n", p->pair_compl_any) ;
fprintf(fd, " pair_compl_end %f\n", p->pair_compl_end) ;
fprintf(fd, " pair_compl_any_th %f\n", p->pair_compl_any_th) ;
fprintf(fd, " pair_compl_end_th %f\n", p->pair_compl_end_th) ;
fprintf(fd, " min_left_three_prime_distance %i\n", p->min_left_three_prime_distance) ;
fprintf(fd, " min_internal_three_prime_distance %i\n", p->min_internal_three_prime_distance) ;
fprintf(fd, " min_right_three_prime_distance %i\n", p->min_right_three_prime_distance) ;
fprintf(fd, " min_5_prime_overlap_of_junction %i\n", p->p_args.min_5_prime_overlap_of_junction);
fprintf(fd, " min_3_prime_overlap_of_junction %i\n", p->p_args.min_3_prime_overlap_of_junction);
fprintf(fd, " min_5_internal_overlap_of_junction %i\n", p->o_args.min_5_prime_overlap_of_junction);
fprintf(fd, " min_3_internal_overlap_of_junction %i\n", p->o_args.min_3_prime_overlap_of_junction);
fprintf(fd, " mask_template %i\n", p->mask_template);
fprintf(fd, " failure_rate %f\n", p->mp.failure_rate);
fprintf(fd, " nucl_masked_in_5p_direction %i\n", p->mp.nucl_masked_in_5p_direction);
fprintf(fd, " nucl_masked_in_3p_direction %i\n", p->mp.nucl_masked_in_3p_direction);
fprintf(fd, " list_prefix %s\n", p->mp.list_prefix);
fprintf(fd, " dump %i\n", p->dump);
fprintf(fd, " begin pr_pair_weights\n") ;
fprintf(fd, " primer_quality %f\n", p->pr_pair_weights.primer_quality) ;
fprintf(fd, " io_quality %f\n", p->pr_pair_weights.io_quality) ;
fprintf(fd, " diff_tm %f\n", p->pr_pair_weights.diff_tm) ;
fprintf(fd, " compl_any %f\n", p->pr_pair_weights.compl_any) ;
fprintf(fd, " compl_end %f\n", p->pr_pair_weights.compl_end) ;
fprintf(fd, " compl_any_th %f\n", p->pr_pair_weights.compl_any_th) ;
fprintf(fd, " compl_end_th %f\n", p->pr_pair_weights.compl_end_th) ;
fprintf(fd, " product_tm_lt %f\n", p->pr_pair_weights.product_tm_lt) ;
fprintf(fd, " product_tm_gt %f\n", p->pr_pair_weights.product_tm_gt) ;
fprintf(fd, " product_size_lt %f\n", p->pr_pair_weights.product_size_lt) ;
fprintf(fd, " product_size_gt %f\n", p->pr_pair_weights.product_size_gt) ;
fprintf(fd, " repeat_sim %f\n", p->pr_pair_weights.repeat_sim) ;
fprintf(fd, " template_mispriming %f\n", p->pr_pair_weights.template_mispriming) ;
fprintf(fd, " template_mispriming_th %f\n", p->pr_pair_weights.template_mispriming_th) ;
fprintf(fd, " end pair_weights\n") ;
fprintf(fd, "\n\n");
fprintf(fd, "=============\n");
fprintf(fd, "BEGIN primer_args\n");
fprintf(fd, "begin oligo_weights\n");
fprintf(fd, "temp_gt %f\n", p->p_args.weights.temp_gt) ;
fprintf(fd, "temp_lt %f\n", p->p_args.weights.temp_lt) ;
fprintf(fd, "bound_gt %f\n", p->p_args.weights.bound_gt) ;
fprintf(fd, "bound_lt %f\n", p->p_args.weights.bound_lt) ;
fprintf(fd, "gc_content_gt %f\n", p->p_args.weights.gc_content_gt) ;
fprintf(fd, "gc_content_lt %f\n", p->p_args.weights.gc_content_lt) ;
fprintf(fd, "compl_any %f\n", p->p_args.weights.compl_any) ;
fprintf(fd, "compl_end %f\n", p->p_args.weights.compl_end) ;
fprintf(fd, "compl_any_th %f\n", p->p_args.weights.compl_any_th) ;
fprintf(fd, "compl_end_th %f\n", p->p_args.weights.compl_end_th) ;
fprintf(fd, "hairpin %f\n", p->p_args.weights.hairpin_th) ;
fprintf(fd, "repeat_sim %f\n", p->p_args.weights.repeat_sim) ;
fprintf(fd, "length_lt %f\n", p->p_args.weights.length_lt) ;
fprintf(fd, "length_gt %f\n", p->p_args.weights.length_gt) ;
fprintf(fd, "seq_quality %f\n", p->p_args.weights.seq_quality) ;
fprintf(fd, "end_quality %f\n", p->p_args.weights.end_quality) ;
fprintf(fd, "pos_penalty %f\n", p->p_args.weights.pos_penalty) ;
fprintf(fd, "end_stability %f\n", p->p_args.weights.end_stability) ;
fprintf(fd, "num_ns %f\n", p->p_args.weights.num_ns) ;
fprintf(fd, "template_mispriming %f\n", p->p_args.weights.template_mispriming) ;
fprintf(fd, "template_mispriming_th %f\n", p->p_args.weights.template_mispriming_th) ;
fprintf(fd, "failure_rate %f\n", p->p_args.weights.failure_rate) ;
fprintf(fd, "end oligo_weights\n") ;
fprintf(fd, "opt_tm %f\n", p->p_args.opt_tm) ;
fprintf(fd, "min_tm %f\n", p->p_args.min_tm) ;
fprintf(fd, "max_tm %f\n", p->p_args.max_tm) ;
fprintf(fd, "opt_bound %f\n", p->p_args.opt_bound) ;
fprintf(fd, "min_bound %f\n", p->p_args.min_bound) ;
fprintf(fd, "max_bound %f\n", p->p_args.max_bound) ;
fprintf(fd, "opt_gc_content %f\n", p->p_args.opt_gc_content) ;
fprintf(fd, "max_gc %f\n", p->p_args.max_gc) ;
fprintf(fd, "min_gc %f\n", p->p_args.min_gc) ;
fprintf(fd, "divalent_conc %f\n", p->p_args.divalent_conc) ;
fprintf(fd, "dntp_conc %f\n", p->p_args.dntp_conc) ;
fprintf(fd, "dna_conc %f\n", p->p_args.dna_conc) ;
fprintf(fd, "dmso_conc %f\n", p->p_args.dmso_conc) ;
fprintf(fd, "dmso_fact %f\n", p->p_args.dmso_fact) ;
fprintf(fd, "formamide_conc %f\n", p->p_args.formamide_conc) ;
fprintf(fd, "num_ns_accepted %i\n", p->p_args.num_ns_accepted) ;
fprintf(fd, "opt_size %i\n", p->p_args.opt_size) ;
fprintf(fd, "min_size %i\n", p->p_args.min_size) ;
fprintf(fd, "max_size %i\n", p->p_args.max_size) ;
fprintf(fd, "max_poly_x %i\n", p->p_args.max_poly_x) ;
fprintf(fd, "min_end_quality %i\n", p->p_args.min_end_quality) ;
fprintf(fd, "min_quality %i\n", p->p_args.min_quality) ;
fprintf(fd, "max_self_any %f\n", p->p_args.max_self_any) ;
fprintf(fd, "max_self_end %f\n", p->p_args.max_self_end) ;
fprintf(fd, "max_self_any_th %f\n", p->p_args.max_self_any_th) ;
fprintf(fd, "max_self_end_th %f\n", p->p_args.max_self_end_th) ;
fprintf(fd, "max_hairpin %f\n", p->p_args.max_hairpin_th) ;
fprintf(fd, "max_repeat_compl %f\n", p->p_args.max_repeat_compl) ;
fprintf(fd, "max_template_mispriming %f\n", p->p_args.max_template_mispriming) ;
fprintf(fd, "max_template_mispriming_th %f\n", p->p_args.max_template_mispriming_th) ;
fprintf(fd, "end primer args\n") ;
fprintf(fd, "begin internal oligo args (p->o_args.)\n") ;
fprintf(fd, " begin internal oligo_weights (p->o_args.weights.)\n") ;
fprintf(fd, " temp_gt %f\n", p->o_args.weights.temp_gt) ;
fprintf(fd, " temp_lt %f\n", p->o_args.weights.temp_lt) ;
fprintf(fd, " bound_gt %f\n", p->o_args.weights.bound_gt) ;
fprintf(fd, " bound_lt %f\n", p->o_args.weights.bound_lt) ;
fprintf(fd, " gc_content_gt %f\n", p->o_args.weights.gc_content_gt) ;
fprintf(fd, " gc_content_lt %f\n", p->o_args.weights.gc_content_lt) ;
fprintf(fd, " compl_any %f\n", p->o_args.weights.compl_any) ;
fprintf(fd, " compl_end %f\n", p->o_args.weights.compl_end) ;
fprintf(fd, " compl_any_th %f\n", p->o_args.weights.compl_any_th) ;
fprintf(fd, " compl_end_th %f\n", p->o_args.weights.compl_end_th) ;
fprintf(fd, " hairpin %f\n", p->o_args.weights.hairpin_th) ;
fprintf(fd, " repeat_sim %f\n", p->o_args.weights.repeat_sim) ;
fprintf(fd, " length_lt %f\n", p->o_args.weights.length_lt) ;
fprintf(fd, " length_gt %f\n", p->o_args.weights.length_gt) ;
fprintf(fd, " seq_quality %f\n", p->o_args.weights.seq_quality) ;
fprintf(fd, " end_quality %f\n", p->o_args.weights.end_quality) ;
fprintf(fd, " pos_penalty %f\n", p->o_args.weights.pos_penalty) ;
fprintf(fd, " end_stability %f\n", p->o_args.weights.end_stability) ;
fprintf(fd, " num_ns %f\n", p->o_args.weights.num_ns) ;
fprintf(fd, " end internal oligo_weights\n") ;
fprintf(fd, " opt_tm %f\n", p->o_args.opt_tm) ;
fprintf(fd, " min_tm %f\n", p->o_args.min_tm) ;
fprintf(fd, " max_tm %f\n", p->o_args.max_tm) ;
fprintf(fd, " opt_bound %f\n", p->o_args.opt_bound) ;
fprintf(fd, " min_bound %f\n", p->o_args.min_bound) ;
fprintf(fd, " max_bound %f\n", p->o_args.max_bound) ;
fprintf(fd, " opt_gc_content %f\n", p->o_args.opt_gc_content) ;
fprintf(fd, " max_gc %f\n", p->o_args.max_gc) ;
fprintf(fd, " min_gc %f\n", p->o_args.min_gc) ;
fprintf(fd, " divalent_conc %f\n", p->o_args.divalent_conc) ;
fprintf(fd, " dntp_conc %f\n", p->o_args.dntp_conc) ;
fprintf(fd, " dna_conc %f\n", p->o_args.dna_conc) ;
fprintf(fd, " dmso_conc %f\n", p->o_args.dmso_conc) ;
fprintf(fd, " dmso_fact %f\n", p->o_args.dmso_fact) ;
fprintf(fd, " formamide_conc %f\n", p->o_args.formamide_conc) ;
fprintf(fd, " num_ns_accepted %i\n", p->o_args.num_ns_accepted) ;
fprintf(fd, " opt_size %i\n", p->o_args.opt_size) ;
fprintf(fd, " min_size %i\n", p->o_args.min_size) ;
fprintf(fd, " max_size %i\n", p->o_args.max_size) ;
fprintf(fd, " max_poly_x %i\n", p->o_args.max_poly_x) ;
fprintf(fd, " min_end_quality %i\n", p->o_args.min_end_quality) ;
fprintf(fd, " min_quality %i\n", p->o_args.min_quality) ;
fprintf(fd, " max_self_any %f\n", p->o_args.max_self_any) ;
fprintf(fd, " max_self_end %f\n", p->o_args.max_self_end) ;
fprintf(fd, " max_repeat_compl %f\n", p->o_args.max_repeat_compl) ;
fprintf(fd, " end internal oligo args\n");
fprintf(fd, "\n");
fprintf(fd, "END GLOBAL ARGS\n");
fprintf(fd, "=============\n");
fprintf(fd, "\n");
}
if (s != NULL) {
fprintf(fd, "=============\n");
fprintf(fd, "BEGIN SEQUENCE ARGS\n") ;
/* TO DO: complete the statments for dumping this data
fprintf(fd, "interval_array_t2 tar2 %i\n",
int pairs[PR_MAX_INTERVAL_ARRAY][2]) ;
int count) ;
fprintf(fd, "interval_array_t2 excl2 %i\n",
int pairs[PR_MAX_INTERVAL_ARRAY][2]) ;
int count) ;
fprintf(fd, "interval_array_t2 excl_internal2 %i\n",
int pairs[PR_MAX_INTERVAL_ARRAY][2]) ;
int count) ;
fprintf(fd, "ok_regions \n");
*/
fprintf(fd, "sequence_primer_pair_ok_regions %i\n",
s->ok_regions.count);
if (s->ok_regions.count) {
fprintf(fd, "sequence_primer_pair_ok_regions_list [\n");
for (i = 0; i < s->ok_regions.count; i++) {
fprintf(fd, " %i\n", s->ok_regions.left_pairs[i][0]);
fprintf(fd, " %i\n", s->ok_regions.left_pairs[i][1]);
fprintf(fd, " %i\n", s->ok_regions.right_pairs[i][0]);
fprintf(fd, " %i\n", s->ok_regions.right_pairs[i][1]);
}
fprintf(fd, "]\n");
}
if (s->primer_overlap_junctions_count > 0) {
fprintf(fd, "primer_overlap_junctions_count %i\n",
s->primer_overlap_junctions_count);
fprintf(fd, "primer_overlap_junctions_list [\n");
for (i = 0; i < s->primer_overlap_junctions_count; i++) {
fprintf(fd, " %i\n", s->primer_overlap_junctions[i]);
}
fprintf(fd, "]\n");
}
if (s->intl_overlap_junctions_count > 0) {
fprintf(fd, "intl_overlap_junctions_count %i\n",
s->intl_overlap_junctions_count);
fprintf(fd, "intl_overlap_junctions_list [\n");
for (i = 0; i < s->intl_overlap_junctions_count; i++) {
fprintf(fd, " %i\n", s->intl_overlap_junctions[i]);
}
fprintf(fd, "]\n");
}
fprintf(fd, "incl_s %i\n", s->incl_s) ;
fprintf(fd, "incl_l %i\n", s->incl_l) ;
fprintf(fd, "start_codon_pos %i\n", s->start_codon_pos) ;
fprintf(fd, "n_quality %i\n", s->n_quality) ;
/* TO DO fprintf(fd, "quality%i\", s->quality) ; */
fprintf(fd, "quality_storage_size %i\n", s->quality_storage_size) ;
fprintf(fd, "*sequence %s\n", s->sequence) ;
fprintf(fd, "*sequence_name %s\n", s->sequence_name) ;
fprintf(fd, "*sequence_file %s\n", s->sequence_file) ;
fprintf(fd, "*trimmed_seq %s\n", s->trimmed_seq) ;
fprintf(fd, "*trimmed_orig_seq %s\n", s->trimmed_orig_seq) ;
fprintf(fd, "*trimmed_masked_seq %s\n", s->trimmed_masked_seq) ;
fprintf(fd, "*trimmed_masked_seq_r %s\n", s->trimmed_masked_seq_r) ;
fprintf(fd, "*upcased_seq %s\n", s->upcased_seq) ;
fprintf(fd, "*upcased_seq_r %s\n", s->upcased_seq_r) ;
fprintf(fd, "*left_input %s\n", s->left_input) ;
fprintf(fd, "*right_input %s\n", s->right_input) ;
fprintf(fd, "*internal_input %s\n", s->internal_input) ;
fprintf(fd, "force_left_start %i\n", s->force_left_start) ;
fprintf(fd, "force_left_end %i\n", s->force_left_end) ;
fprintf(fd, "force_right_start %i\n", s->force_right_start) ;
fprintf(fd, "force_right_end %i\n", s->force_right_end) ;
fprintf(fd, "END SEQUENCE ARGS\n") ;
fprintf(fd, "=============\n");
fprintf(fd, "\n");
}
}
/********************************
* BEGIN DATA SETTING FUNCTIONS *
********************************/
void
p3_set_gs_prmin (
p3_global_settings* p,
int val,
int i
) {
p->pr_min[i] = val ;
}
void
p3_set_gs_prmax (
p3_global_settings* p,
int val,
int i
) {
p->pr_max[i] = val ;
}
void
p3_set_gs_primer_opt_size(
p3_global_settings* p,
int val
) {
p->p_args.opt_size = val ;
}
void
p3_set_gs_primer_min_size(
p3_global_settings* p,
int val
) {
p->p_args.min_size = val ;
}
void
p3_set_gs_primer_max_size(
p3_global_settings* p,
int val
) {
p->p_args.max_size = val ;
}
void
p3_set_gs_primer_max_poly_x(
p3_global_settings* p,
int val
) {
p->p_args.max_poly_x = val;
}
void
p3_set_gs_primer_opt_tm(
p3_global_settings* p,
double d
) {
p->p_args.opt_tm = d ;
}
void
p3_set_gs_primer_opt_gc_percent(
p3_global_settings* p,
double d
) {
p->p_args.opt_gc_content = d ;
}
void
p3_set_gs_primer_min_tm(
p3_global_settings* p,
double d
) {
p->p_args.min_tm = d ;
}
void
p3_set_gs_primer_max_tm(
p3_global_settings* p,
double d
) {
p->p_args.max_tm = d;
}
void
p3_set_gs_primer_opt_bound(
p3_global_settings* p,
double d
) {
p->p_args.opt_bound = d ;
}
void
p3_set_gs_primer_min_bound(
p3_global_settings* p,
double d
) {
p->p_args.min_bound = d ;
}
void
p3_set_gs_primer_max_bound(
p3_global_settings* p,
double d
) {
p->p_args.max_bound = d;
}
void
p3_set_gs_primer_max_diff_tm(
p3_global_settings* p,
double val
) {
p->max_diff_tm = val;
}
void
p3_set_gs_primer_tm_santalucia(
p3_global_settings* p,
tm_method_type val
) {
p->tm_santalucia = val ;
}
void
p3_set_gs_primer_salt_corrections(
p3_global_settings* p,
salt_correction_type val
) {
p->salt_corrections = val;
}
void
p3_set_gs_primer_annealing_temp(
p3_global_settings* p,
double val
) {
p->annealing_temp = val;
}
void
p3_set_gs_primer_min_gc(
p3_global_settings* p,
double val
) {
p->p_args.min_gc = val ;
}
void
p3_set_gs_primer_max_gc(
p3_global_settings* p,
double val
) {
p->p_args.max_gc = val ;
}
void
p3_set_gs_primer_salt_conc(
p3_global_settings* p,
double val
) {
p->p_args.salt_conc = val ;
}
void
p3_set_gs_primer_divalent_conc(
p3_global_settings* p,
double val
) {
p->p_args.divalent_conc = val;
}
void
p3_set_gs_primer_dntp_conc(
p3_global_settings* p,
double val
) {
p->p_args.dntp_conc = val ;
}
void
p3_set_gs_primer_dna_conc(
p3_global_settings* p,
double val
) {
p->p_args.dna_conc = val ;
}
void
p3_set_gs_primer_dmso_conc(
p3_global_settings* p,
double val
) {
p->p_args.dmso_conc = val ;
}
void
p3_set_gs_primer_dmso_fact(
p3_global_settings* p,
double val
) {
p->p_args.dmso_fact = val ;
}
void
p3_set_gs_primer_formamide_conc(
p3_global_settings* p,
double val
) {
p->p_args.formamide_conc = val ;
}
void
p3_set_gs_primer_num_ns_accepted(
p3_global_settings* p,
int val
) {
p->p_args.num_ns_accepted = val ;
}
void
p3_set_gs_primer_product_opt_size(
p3_global_settings* p,
int val
) {
p->product_opt_size = val ;
}
void
p3_set_gs_primer_self_any(
p3_global_settings* p,
double val
) {
p->p_args.max_self_any = val;
}
void
p3_set_gs_primer_self_any_th(
p3_global_settings* p,
double val
) {
p->p_args.max_self_any_th = val;
}
void
p3_set_gs_primer_self_end(
p3_global_settings* p,
double val
) {
p->p_args.max_self_end = val; /* (short) (val * 100); */
}
void
p3_set_gs_primer_self_end_th(
p3_global_settings* p,
double val
) {
p->p_args.max_self_end_th = val;
}
void
p3_set_gs_primer_hairpin_th(
p3_global_settings* p,
double val
) {
p->p_args.max_hairpin_th = val;
}
void /* Called in primer3_boulder_main.c. */
p3_set_gs_primer_file_flag(
p3_global_settings* p,
int file_flag)
{
p->file_flag = file_flag;
}
void
p3_set_gs_pick_anyway(
p3_global_settings* p,
int pick_anyway)
{
p->pick_anyway = pick_anyway ;
}
void
p3_set_gs_gc_clamp(
p3_global_settings* p,
int gc_clamp)
{
p->gc_clamp = gc_clamp;
}
void
p3_set_gs_primer_liberal_base(
p3_global_settings* p,
int val
) {
p->liberal_base = val;
}
void
p3_set_gs_primer_first_base_index(
p3_global_settings* p,
int first_base_index){
p->first_base_index = first_base_index;
}
void
p3_set_gs_primer_num_return(
p3_global_settings* p,
int val
) {
p->num_return = val ;
}
void
p3_set_gs_primer_min_quality(
p3_global_settings* p,
int val
) {
p->p_args.min_quality = val ;
}
void
p3_set_gs_primer_min_end_quality(
p3_global_settings* p,
int val
) {
p->p_args.min_end_quality = val ;
}
void
p3_set_gs_primer_quality_range_min(
p3_global_settings* p,
int val
) {
p->quality_range_min = val ;
}
void
p3_set_gs_primer_quality_range_max(
p3_global_settings* p,
int val
) {
p->quality_range_max = val ;
}
void
p3_set_gs_primer_product_max_tm(
p3_global_settings* p,
double val
) {
p->product_max_tm = val ;
}
void
p3_set_gs_primer_product_min_tm(
p3_global_settings* p,
double val
) {
p->product_min_tm = val ;
}
void
p3_set_gs_primer_product_opt_tm(
p3_global_settings* p,
double val
) {
p->product_opt_tm = val ;
}
void
p3_set_gs_primer_pick_right_primer(
p3_global_settings* p,
int pick_right_primer)
{
p->pick_right_primer = pick_right_primer;
}
void
p3_set_gs_primer_pick_internal_oligo(
p3_global_settings* p,
int pick_internal_oligo)
{
p->pick_internal_oligo = pick_internal_oligo;
}
void
p3_set_gs_primer_pick_left_primer(
p3_global_settings* p,
int pick_left_primer) {
p->pick_left_primer = pick_left_primer;
}
void
p3_set_gs_primer_internal_oligo_opt_size(
p3_global_settings* p,
int val
) {
p->o_args.opt_size = val ;
}
void
p3_set_gs_primer_internal_oligo_max_size(
p3_global_settings* p,
int val
) {
p->o_args.max_size = val ;
}
void
p3_set_gs_primer_internal_oligo_min_size(
p3_global_settings* p,
int val
) {
p->o_args.min_size = val ;
}
void
p3_set_gs_primer_internal_oligo_max_poly_x(
p3_global_settings* p,
int val
) {
p->o_args.max_poly_x = val ;
}
void
p3_set_gs_primer_internal_oligo_opt_tm(
p3_global_settings* p,
double val
) {
p->o_args.opt_tm = val ;
}
void
p3_set_gs_primer_internal_oligo_opt_gc_percent(
p3_global_settings* p,
double val
) {
p->o_args.opt_gc_content = val ;
}
void
p3_set_gs_primer_internal_oligo_max_tm(
p3_global_settings* p,
double val
) {
p->o_args.max_tm = val ;
}
void
p3_set_gs_primer_internal_oligo_min_tm(
p3_global_settings* p,
double val
) {
p->o_args.min_tm = val ;
}
void
p3_set_gs_primer_internal_oligo_opt_bound(
p3_global_settings* p,
double val
) {
p->o_args.opt_bound = val ;
}
void
p3_set_gs_primer_internal_oligo_max_bound(
p3_global_settings* p,
double val
) {
p->o_args.max_bound = val ;
}
void
p3_set_gs_primer_internal_oligo_min_bound(
p3_global_settings* p,
double val
) {
p->o_args.min_bound = val ;
}
void
p3_set_gs_primer_internal_oligo_min_gc(
p3_global_settings* p,
double val
) {
p->o_args.min_gc = val ;
}
void
p3_set_gs_primer_internal_oligo_max_gc(
p3_global_settings* p,
double val
) {
p->o_args.max_gc = val ;
}
void
p3_set_gs_primer_internal_oligo_salt_conc(
p3_global_settings* p,
double val
) {
p->o_args.salt_conc = val ;
}
void
p3_set_gs_primer_internal_oligo_divalent_conc(
p3_global_settings* p,
double val
) {
p->o_args.divalent_conc = val ;
}
void
p3_set_gs_primer_internal_oligo_dntp_conc(
p3_global_settings* p,
double val
) {
p->o_args.dntp_conc = val ;
}
void
p3_set_gs_primer_internal_oligo_dna_conc(
p3_global_settings* p,
double val
) {
p->o_args.dna_conc = val ;
}
void
p3_set_gs_primer_internal_oligo_dmso_conc(
p3_global_settings* p,
double val
) {
p->o_args.dmso_conc = val ;
}
void
p3_set_gs_primer_internal_oligo_dmso_fact(
p3_global_settings* p,
double val
) {
p->o_args.dmso_fact = val ;
}
void
p3_set_gs_primer_internal_oligo_formamide_conc(
p3_global_settings* p,
double val
) {
p->o_args.formamide_conc = val ;
}
void
p3_set_gs_primer_internal_oligo_num_ns(
p3_global_settings* p,
int val
) {
p->o_args.num_ns_accepted = val ;
}
void
p3_set_gs_primer_internal_oligo_min_quality(
p3_global_settings* p,
int val
) {
p->o_args.min_quality = val ;
}
void
p3_set_gs_primer_internal_oligo_self_any(
p3_global_settings* p,
double val
) {
p->o_args.max_self_any = val;
}
void
p3_set_gs_primer_internal_oligo_self_any_th(
p3_global_settings* p,
double val
) {
p->o_args.max_self_any_th = val;
}
void
p3_set_gs_primer_internal_oligo_self_end(
p3_global_settings* p,
double val
) {
p->o_args.max_self_end = val; /* (short) (val * 100); */
}
void
p3_set_gs_primer_internal_oligo_self_end_th(
p3_global_settings* p,
double val
) {
p->o_args.max_self_end_th = val;
}
void
p3_set_gs_primer_internal_oligo_hairpin_th(
p3_global_settings* p,
double val
) {
p->o_args.max_hairpin_th = val;
}
void
p3_set_gs_primer_max_mispriming(
p3_global_settings* p,
double val
) {
p->p_args.max_repeat_compl = val;
}
void
p3_set_gs_primer_internal_oligo_max_mishyb(
p3_global_settings* p,
double val
) {
p->o_args.max_repeat_compl = val;
}
void
p3_set_gs_primer_pair_max_mispriming(
p3_global_settings* p,
double val
) {
p->pair_repeat_compl = val;
}
void
p3_set_gs_primer_max_template_mispriming(
p3_global_settings* p,
double val
) {
p->p_args.max_template_mispriming = val;
}
void
p3_set_gs_primer_max_template_mispriming_th(
p3_global_settings* p,
double val
) {
p->p_args.max_template_mispriming_th = val;
}
void
p3_set_gs_primer_lib_ambiguity_codes_consensus(
p3_global_settings* p,
int val
) {
p->lib_ambiguity_codes_consensus = val ;
}
void
p3_set_gs_primer_inside_penalty(
p3_global_settings* p,
double val
) {
p->inside_penalty = val ;
}
void
p3_set_gs_primer_outside_penalty(
p3_global_settings* p,
double val
) {
p->outside_penalty = val ;
}
void
p3_set_gs_primer_mispriming_library(
p3_global_settings* p,
char* path
) {
/* TO DO: Re-factor this? TO DO: Check for errors */
p->p_args.repeat_lib = read_and_create_seq_lib(path, "mispriming library") ;
}
void
p3_set_gs_primer_internal_oligo_mishyb_library(
p3_global_settings* p,
char* path) {
/* TO DO: Re-factor this? TO DO: Check for errors */
p->o_args.repeat_lib = read_and_create_seq_lib(path, "internal oligio mishyb library") ;
}
void
p3_set_gs_primer_max_end_stability(
p3_global_settings* p,
double val
) {
p->max_end_stability = val ;
}
void
p3_set_gs_primer_lowercase_masking(
p3_global_settings* p,
int val
) {
p->lowercase_masking = val ;
}
void
p3_set_gs_primer_thermodynamic_oligo_alignment(
p3_global_settings* p,
int val
) {
p->thermodynamic_oligo_alignment = val ;
}
void
p3_set_gs_primer_thermodynamic_template_alignment(
p3_global_settings* p,
int val
) {
p->thermodynamic_template_alignment = val ;
}
void
p3_set_gs_primer_wt_tm_gt(
p3_global_settings* p,
double val
) {
p->p_args.weights.temp_gt = val ;
}
void
p3_set_gs_primer_wt_tm_lt(
p3_global_settings* p,
double val
) {
p->p_args.weights.temp_lt = val ;
}
void
p3_set_gs_primer_wt_bound_gt(
p3_global_settings* p,
double val
) {
p->p_args.weights.bound_gt = val ;
}
void
p3_set_gs_primer_wt_bound_lt(
p3_global_settings* p,
double val
) {
p->p_args.weights.bound_lt = val ;
}
void
p3_set_gs_primer_wt_gc_percent_gt(
p3_global_settings* p,
double val
) {
p->p_args.weights.gc_content_gt = val ;
}
void
p3_set_gs_primer_wt_gc_percent_lt(
p3_global_settings* p,
double val
) {
p->p_args.weights.gc_content_lt = val ;
}
void
p3_set_gs_primer_wt_size_lt(
p3_global_settings* p,
double val
) {
p->p_args.weights.length_lt = val ;
}
void
p3_set_gs_primer_wt_size_gt(
p3_global_settings* p,
double val
) {
p->p_args.weights.length_gt = val ;
}
void
p3_set_gs_primer_wt_compl_any(
p3_global_settings* p,
double val
) {
p->p_args.weights.compl_any = val ;
}
void
p3_set_gs_primer_wt_compl_any_th(
p3_global_settings* p,
double val
) {
p->p_args.weights.compl_any_th = val ;
}
void
p3_set_gs_primer_wt_compl_end(
p3_global_settings* p,
double val
) {
p->p_args.weights.compl_end = val ;
}
void
p3_set_gs_primer_wt_compl_end_th(
p3_global_settings* p,
double val
) {
p->p_args.weights.compl_end_th = val ;
}
void
p3_set_gs_primer_wt_hairpin_th(
p3_global_settings* p,
double val
) {
p->p_args.weights.hairpin_th = val ;
}
void
p3_set_gs_primer_wt_num_ns(
p3_global_settings* p,
double val
) {
p->p_args.weights.num_ns = val ;
}
void
p3_set_gs_primer_wt_rep_sim(
p3_global_settings* p,
double val
) {
p->p_args.weights.repeat_sim = val ;
}
void
p3_set_gs_primer_wt_seq_qual(
p3_global_settings* p,
double val
) {
p->p_args.weights.seq_quality = val ;
}
void
p3_set_gs_primer_wt_end_qual(
p3_global_settings* p,
double val
) {
p->p_args.weights.end_quality = val ;
}
void
p3_set_gs_primer_wt_pos_penalty(
p3_global_settings* p,
double val
) {
p->p_args.weights.pos_penalty = val ;
}
void
p3_set_gs_primer_wt_end_stability(
p3_global_settings* p,
double val
) {
p->p_args.weights.end_stability = val ;
}
void
p3_set_gs_primer_wt_template_mispriming(
p3_global_settings* p,
double val
) {
p->p_args.weights.template_mispriming = val ;
}
void
p3_set_gs_primer_wt_template_mispriming_th(
p3_global_settings* p,
double val
) {
p->p_args.weights.template_mispriming_th = val ;
}
void
p3_set_gs_primer_io_wt_tm_gt(
p3_global_settings* p,
double val
) {
p->o_args.weights.temp_gt = val ;
}
void
p3_set_gs_primer_io_wt_tm_lt(
p3_global_settings* p,
double val
) {
p->o_args.weights.temp_lt = val ;
}
void
p3_set_gs_primer_io_wt_bound_gt(
p3_global_settings* p,
double val
) {
p->o_args.weights.bound_gt = val ;
}
void
p3_set_gs_primer_io_wt_bound_lt(
p3_global_settings* p,
double val
) {
p->o_args.weights.bound_lt = val ;
}
void
p3_set_gs_primer_io_wt_gc_percent_gt(
p3_global_settings* p,
double val
) {
p->o_args.weights.gc_content_gt = val ;
}
void
p3_set_gs_primer_io_wt_gc_percent_lt(
p3_global_settings* p,
double val
) {
p->o_args.weights.gc_content_lt = val ;
}
void
p3_set_gs_primer_io_wt_size_lt(
p3_global_settings* p,
double val
) {
p->o_args.weights.length_lt = val ;
}
void
p3_set_gs_primer_io_wt_size_gt(
p3_global_settings* p,
double val
) {
p->o_args.weights.length_gt = val ;
}
void
p3_set_gs_primer_io_wt_wt_compl_any(
p3_global_settings* p,
double val
) {
p->o_args.weights.compl_any = val ;
}
void
p3_set_gs_primer_io_wt_wt_compl_any_th(
p3_global_settings* p,
double val
) {
p->o_args.weights.compl_any_th = val ;
}
void
p3_set_gs_primer_io_wt_compl_end(
p3_global_settings* p,
double val
) {
p->o_args.weights.compl_end = val ;
}
void
p3_set_gs_primer_io_wt_compl_end_th(
p3_global_settings* p,
double val
) {
p->o_args.weights.compl_end_th = val ;
}
void
p3_set_gs_primer_io_wt_hairpin_th(
p3_global_settings* p,
double val
) {
p->o_args.weights.hairpin_th = val ;
}
void
p3_set_gs_primer_io_wt_num_ns(
p3_global_settings* p,
double val
) {
p->o_args.weights.num_ns = val ;
}
void
p3_set_gs_primer_io_wt_rep_sim(
p3_global_settings* p,
double val
) {
p->o_args.weights.repeat_sim = val ;
}
void
p3_set_gs_primer_io_wt_seq_qual(
p3_global_settings* p,
double val
) {
p->o_args.weights.seq_quality = val ;
}
void
p3_set_gs_primer_io_wt_end_qual(
p3_global_settings* p,
double val
) {
p->o_args.weights.end_quality = val ;
}
void
p3_set_gs_primer_pair_wt_pr_penalty(
p3_global_settings* p,
double val
) {
p->pr_pair_weights.primer_quality = val ;
}
void
p3_set_gs_primer_pair_wt_io_penalty(
p3_global_settings* p,
double val
) {
p->pr_pair_weights.io_quality = val ;
}
void
p3_set_gs_primer_pair_wt_diff_tm(
p3_global_settings* p,
double val
) {
p->pr_pair_weights.diff_tm = val ;
}
void
p3_set_gs_primer_pair_wt_compl_any(
p3_global_settings* p,
double val
) {
p->pr_pair_weights.compl_any = val ;
}
void
p3_set_gs_primer_pair_wt_compl_any_th(
p3_global_settings* p,
double val
) {
p->pr_pair_weights.compl_any_th = val ;
}
void
p3_set_gs_primer_pair_wt_compl_end(
p3_global_settings* p,
double val
) {
p->pr_pair_weights.compl_end = val ;
}
void
p3_set_gs_primer_pair_wt_compl_end_th(
p3_global_settings* p,
double val
) {
p->pr_pair_weights.compl_end_th = val ;
}
void
p3_set_gs_primer_pair_wt_product_tm_lt(
p3_global_settings* p,
double val
) {
p->pr_pair_weights.product_tm_lt = val ;
}
void
p3_set_gs_primer_pair_wt_product_tm_gt(
p3_global_settings* p,
double val
) {
p->pr_pair_weights.product_tm_gt = val ;
}
void
p3_set_gs_primer_pair_wt_product_size_gt(
p3_global_settings* p,
double val
) {
p->pr_pair_weights.product_size_gt = val ;
}
void
p3_set_gs_primer_pair_wt_product_size_lt(
p3_global_settings* p,
double val
) {
p->pr_pair_weights.product_size_lt = val ;
}
void
p3_set_gs_primer_pair_wt_rep_sim(
p3_global_settings* p,
double val
) {
p->pr_pair_weights.repeat_sim = val ;
}
void
p3_set_gs_primer_pair_wt_template_mispriming(
p3_global_settings* p,
double val
) {
p->pr_pair_weights.template_mispriming = val ;
}
void
p3_set_gs_primer_pair_wt_template_mispriming_th(
p3_global_settings* p,
double val
) {
p->pr_pair_weights.template_mispriming_th = val ;
}
void
p3_set_gs_lib_ambiguity_codes_consensus(
p3_global_settings* p,
int lib_ambiguity_codes_consensus
) {
p->lib_ambiguity_codes_consensus = lib_ambiguity_codes_consensus;
}
void
p3_set_gs_quality_range_min(
p3_global_settings* p,
int quality_range_min
) {
p->quality_range_min = quality_range_min;
}
void
p3_set_gs_quality_range_max(
p3_global_settings* p,
int quality_range_max
) {
p->quality_range_max = quality_range_max ;
}
void
p3_set_gs_max_end_gc(
p3_global_settings* p,
int max_end_gc
) {
p->max_end_gc = max_end_gc;
}
void
p3_set_gs_max_end_stability(
p3_global_settings* p,
int max_end_stability
) {
p->max_end_stability = max_end_stability;
}
void
p3_set_gs_lowercase_masking(
p3_global_settings* p,
int lowercase_masking
) {
p->lowercase_masking = lowercase_masking;
}
void
p3_set_gs_outside_penalty(
p3_global_settings* p,
double outside_penalty
) {
p->outside_penalty = outside_penalty;
}
void
p3_set_gs_inside_penalty(
p3_global_settings* p,
double inside_penalty
) {
p->inside_penalty = inside_penalty;
}
void
p3_set_gs_pair_max_template_mispriming(
p3_global_settings* p,
double pair_max_template_mispriming
) {
p->pair_max_template_mispriming = pair_max_template_mispriming;
}
void
p3_set_gs_pair_max_template_mispriming_th(
p3_global_settings* p,
double pair_max_template_mispriming_th
) {
p->pair_max_template_mispriming_th = pair_max_template_mispriming_th;
}
void
p3_set_gs_pair_repeat_compl(
p3_global_settings* p,
double pair_repeat_compl)
{
p->pair_repeat_compl = pair_repeat_compl;
}
void
p3_set_gs_pair_compl_any(
p3_global_settings* p,
double pair_compl_any)
{
p->pair_compl_any = pair_compl_any;
}
void
p3_set_gs_pair_compl_any_th(
p3_global_settings* p,
double pair_compl_any_th)
{
p->pair_compl_any_th = pair_compl_any_th;
}
void
p3_set_gs_pair_compl_end(
p3_global_settings* p,
double pair_compl_end)
{
p->pair_compl_end = pair_compl_end;
}
void
p3_set_gs_pair_compl_end_th(
p3_global_settings* p,
double pair_compl_end_th)
{
p->pair_compl_end = pair_compl_end_th;
}
void
p3_set_gs_min_left_three_prime_distance(
p3_global_settings* p,
int min_distance)
{
p->min_left_three_prime_distance = min_distance;
}
void
p3_set_gs_min_internal_three_prime_distance(
p3_global_settings* p,
int min_distance)
{
p->min_internal_three_prime_distance = min_distance;
}
void
p3_set_gs_min_right_three_prime_distance(
p3_global_settings* p,
int min_distance)
{
p->min_right_three_prime_distance = min_distance;
}
void
p3_set_gs_min_5_prime_overlap_of_junction(
p3_global_settings* p,
int min_5_prime)
{
p->p_args.min_5_prime_overlap_of_junction = min_5_prime;
}
void
p3_set_gs_min_3_prime_overlap_of_junction(
p3_global_settings* p,
int min_3_prime)
{
p->p_args.min_3_prime_overlap_of_junction = min_3_prime;
}
void
p3_set_gs_min_5_internal_overlap_of_junction(
p3_global_settings* p,
int min_5_prime)
{
p->o_args.min_5_prime_overlap_of_junction = min_5_prime;
}
void
p3_set_gs_min_3_internal_overlap_of_junction(
p3_global_settings* p,
int min_3_prime)
{
p->o_args.min_3_prime_overlap_of_junction = min_3_prime;
}
void
p3_set_gs_max_diff_tm(
p3_global_settings* p,
double max_diff_tm) {
p->max_diff_tm = max_diff_tm;
}
void
p3_set_gs_primer_pick_anyway(
p3_global_settings* p,
int val
) {
p->pick_anyway = val ;
}
void
p3_set_gs_primer_gc_clamp(
p3_global_settings* p,
int val
) {
p->gc_clamp = val;
}
void
p3_empty_gs_product_size_range(
p3_global_settings* pgs
) {
pgs->num_intervals = 0;
}
/******************************
* END DATA SETTING FUNCTIONS *
******************************/
primer3-py-2.3.1/primer3/src/libprimer3/libprimer3flex.h 0000664 0000000 0000000 00000037600 15247271707 0023066 0 ustar 00root root 0000000 0000000 /* libprimer3/libprimer3flex.h
Copyright (c) 1996,1997,1998,1999,2000,2001,2004,2006,2007,2009,2010,
2011,2012,2016
Whitehead Institute for Biomedical Research, Steve Rozen
(http://purl.com/STEVEROZEN/), and Helen Skaletsky
All rights reserved.
This file is part of primer3 software suite.
This software suite is is free software;
you can redistribute it and/or modify it under the terms
of the GNU General Public License as published by the Free
Software Foundation; either version 2 of the License, or (at
your option) any later version.
This software is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this software (file gpl-2.0.txt in the source
distribution); if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON A THEORY
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Modifications to libprimer.c code to create libprimer3flex.h.
Copyright (C) 2023. Ben Pruitt & Nick Conway;
See libprimer3flex.c for more info on libprimer3flex.h
*/
#ifndef _P3PY_LIBPRIMER3FLEX_H
#define _P3PY_LIBPRIMER3FLEX_H
#include "khash.h"
#include "libprimer3.h"
typedef struct dpal_arg_holder {
dpal_args *local;
dpal_args *end;
dpal_args *local_end;
dpal_args *local_ambig;
dpal_args *local_end_ambig;
} dpal_arg_holder;
typedef struct thal_arg_holder {
thal_args *any;
thal_args *end1;
thal_args *end2;
thal_args *hairpin_th;
int thermodynamic_alignment_length_error; /* p3py update: formally static global */
char* thermodynamic_alignment_length_error_msg; /* p3py update: formally static global */
} thal_arg_holder;
/* Ininitalize khash.h `primer_pair_map` type `khash_t(primer_pair_map)` */
KHASH_MAP_INIT_INT(primer_pair_map, primer_pair* )
/* primer3-py update: 2023.03.21 moved to pairs and max_j_seen to
function-local (choose_pair_or_triple) for thread safety
*/
typedef struct pairs_args_t {
int *max_j_seen; /* The maximum value of j (loop index for forward primers)
that has been examined for every reverse primer
index (i) */
khash_t(primer_pair_map) **pairs; /* hash map for storing found primer
pairs by pair index, previously
global */
} pairs_args_t;
/**************************/
/* Function declarations. */
/**************************/
static void
pr_set_default_global_args_1(p3_global_settings*);
static void
pr_set_default_global_args_2(p3_global_settings*);
static void
_adjust_seq_args(
const p3_global_settings* pa,
seq_args_t* sa,
pr_append_str* nonfatal_err,
pr_append_str* warning
);
static void
_optimize_ok_regions_list(
const p3_global_settings* pa,
seq_args_t* sa
);
static int
any_5_prime_ol_extension_has_problem(
const primer_rec*
);
static int
p3_ol_is_uninitialized(const primer_rec*);
static int
fake_a_sequence(
seq_args_t* sa,
const p3_global_settings* pa
);
static int
_pr_data_control(
const p3_global_settings*,
const seq_args_t*,
pr_append_str* glob_err,
pr_append_str* nonfatal_err,
pr_append_str* warning
);
static int
_pr_need_pair_template_mispriming(
const p3_global_settings* pa
);
static int
_pr_need_pair_template_mispriming_thermod(
const p3_global_settings* pa
);
static int
_pr_need_template_mispriming(
const p3_global_settings*
);
static int
_pr_need_template_mispriming_thermod(
const p3_global_settings*
);
static void
_pr_substr(
const char*,
int,
int,
char*
);
static void
_pr_shift_substr(
const char*,
int,
int,
int,
char*
);
static int
_pr_violates_poly_x(
const char* oligo_seq,
int max_poly_x
);
static int
_check_and_adjust_intervals(
seq_args_t* sa,
int seq_len,
int first_index,
pr_append_str* nonfatal_err,
pr_append_str* warning
);
static int
_check_and_adjust_overlap_pos(
seq_args_t* sa,
int* list,
int* count,
const char* tag,
int seq_len,
int first_index,
pr_append_str* nonfatal_err,
pr_append_str* warning
);
static int
_check_and_adjust_1_interval(
const char*,
int num,
interval_array_t,
int,
int first_index,
pr_append_str* err,
seq_args_t*,
pr_append_str* warning,
int
);
static void
sort_primer_array(
oligo_array*
);
static void
add_pair(
const primer_pair*,
pair_array_t*
);
static double
align(
const char*,
const char*,
const dpal_args *a
);
static double
align_thermod(
const char*,
const char*,
const thal_args *a,
thal_arg_holder* thal_arg_to_use
);
void
destroy_primer_sec_struct(
primer_rec* p_rec
);
void
destroy_pair_sec_struct(
primer_pair* ppair
);
void
save_overwrite_sec_struct(
char** base,
char* inp
);
void
recalc_secundary_structures(
const p3_global_settings* pa,
const seq_args_t* sa,
const dpal_arg_holder* dpal_arg_to_use,
const thal_arg_holder* thal_arg_to_use,
const thal_arg_holder* thal_oligo_arg_to_use,
p3retval* retval
);
void
recalc_primer_sec_struct(
primer_rec*p_rec,
const int rev,
const p3_global_settings* pa,
const seq_args_t* sa,
const dpal_arg_holder* dpal_arg_to_use,
const thal_arg_holder* thal_arg_to_use
);
void
recalc_pair_sec_struct(
primer_pair* ppair,
const p3_global_settings* pa,
const seq_args_t* sa,
const dpal_arg_holder* dpal_arg_to_use,
const thal_arg_holder* thal_arg_to_use
);
static int
characterize_pair(
p3retval* p,
const p3_global_settings*,
const seq_args_t*,
int,
int,
int,
primer_pair* ,
const dpal_arg_holder*,
const thal_arg_holder*,
int update_stats
);
static void
choose_pair_or_triple(
p3retval*,
const p3_global_settings*,
const seq_args_t*,
const dpal_arg_holder*,
const thal_arg_holder*,
const thal_arg_holder*,
pair_array_t*,
pairs_args_t* pairs_args
);
static int
sequence_quality_is_ok(
const p3_global_settings*,
primer_rec*,
oligo_type,
const seq_args_t*,
int,
int,
oligo_stats* global_oligo_stats,
const args_for_one_oligo_or_primer*
);
static int
choose_internal_oligo(
p3retval*,
const primer_rec*,
const primer_rec*,
int*,
int*,
const seq_args_t*,
const p3_global_settings*,
const dpal_arg_holder*,
const thal_arg_holder*,
const thal_arg_holder*
);
void
compute_position_penalty(
const p3_global_settings*,
const seq_args_t*,
primer_rec*,
oligo_type
);
dpal_arg_holder*
create_dpal_arg_holder(void);
void
destroy_dpal_arg_holder(dpal_arg_holder* h);
thal_arg_holder*
create_thal_arg_holder(
const args_for_one_oligo_or_primer *po_args
);
void
destroy_thal_arg_holder(
thal_arg_holder* h
);
static p3retval*
create_p3retval(void);
static char
dna_to_upper(
char*,
int
);
static int
find_stop_codon(
const char*,
int,
int
);
static void
gc_and_n_content(
int,
int,
const char*,
primer_rec*
);
static int
make_detection_primer_lists(
p3retval*,
const p3_global_settings*,
const seq_args_t*,
const dpal_arg_holder*,
const thal_arg_holder*
);
static int
make_complete_primer_lists(
p3retval* retval,
const p3_global_settings* pa,
const seq_args_t* sa,
const dpal_arg_holder* dpal_arg_to_use,
const thal_arg_holder* thal_arg_to_use,
const thal_arg_holder* thal_oligo_arg_to_use
);
static int
add_primers_to_check(
p3retval* retval,
const p3_global_settings* pa,
const seq_args_t* sa,
const dpal_arg_holder* dpal_arg_to_use,
const thal_arg_holder* thal_arg_to_use,
const thal_arg_holder* thal_oligo_arg_to_use
);
static int
pick_sequencing_primer_list(
p3retval* retval,
const p3_global_settings* pa,
const seq_args_t* sa,
const dpal_arg_holder* dpal_arg_to_use,
const thal_arg_holder* thal_arg_to_use
);
static int
make_internal_oligo_list(
p3retval*,
const p3_global_settings*,
const seq_args_t*,
const dpal_arg_holder*,
const thal_arg_holder*
);
static int
pick_only_best_primer(
const int,
const int,
oligo_array *,
const p3_global_settings*,
const seq_args_t*,
const dpal_arg_holder*,
const thal_arg_holder*,
p3retval*
);
static int
pick_primer_range(
const int,
const int,
int*,
oligo_array *,
const p3_global_settings*,
const seq_args_t*,
const dpal_arg_holder*,
const thal_arg_holder*,
p3retval* retval
);
static int
add_one_primer(
const char*,
int*,
oligo_array *,
const p3_global_settings*,
const seq_args_t*,
const dpal_arg_holder*,
const thal_arg_holder*,
p3retval*
);
static int
add_one_primer_by_position(
int,
int,
int*,
oligo_array *,
const p3_global_settings*,
const seq_args_t*,
const dpal_arg_holder*,
const thal_arg_holder*,
p3retval*
);
static int
pick_primers_by_position(
const int,
const int,
int*,
oligo_array *,
const p3_global_settings*,
const seq_args_t*,
const dpal_arg_holder*,
const thal_arg_holder*,
p3retval*
);
static double
obj_fn(
const p3_global_settings*,
primer_pair*
);
static int
left_oligo_in_pair_overlaps_used_oligo(
const primer_rec* left,
const primer_pair* best_pair,
int min_dist
);
static int
intl_oligo_in_pair_overlaps_used_oligo(
const primer_rec* left,
const primer_pair* best_pair,
int min_dist
);
static int
right_oligo_in_pair_overlaps_used_oligo(
const primer_rec* right,
const primer_pair* best_pair,
int min_dist
);
static int
oligo_overlaps_interval(
int,
int,
const interval_array_t,
int
);
static void
calc_and_check_oligo_features(
const p3_global_settings* pa,
primer_rec*,
oligo_type,
const dpal_arg_holder*,
const thal_arg_holder*,
const seq_args_t*, oligo_stats*,
p3retval*,
const char*
);
static void
pr_append(
pr_append_str* ,
const char*
);
static void
pr_append_new_chunk(
pr_append_str* x,
const char* s
);
static int
pair_spans_target(
const primer_pair*,
const seq_args_t*
);
static void
pr_append_w_sep(
pr_append_str* ,
const char*,
const char*
);
static void*
pr_safe_malloc(size_t x);
static void*
pr_safe_realloc(
void* p,
size_t x
);
static int
compare_primer_pair(
const void*,
const void*
);
static int
primer_rec_comp(
const void*,
const void*
);
static int
print_list_header(
FILE*,
oligo_type,
int,
int,
int
);
static int
print_oligo(
FILE*,
const seq_args_t*,
int,
const primer_rec*,
oligo_type,
int,
int,
int
);
static char* strstr_nocase(char*, char*);
static double
p_obj_fn(
const p3_global_settings*,
primer_rec*,
int
);
static void
oligo_compl(
primer_rec*,
const args_for_one_oligo_or_primer *po_args,
oligo_stats*,
const dpal_arg_holder*,
const char* oligo_seq,
const char* revc_oligo_seq
);
static void
oligo_compl_thermod(
primer_rec*, /* TO DO 2012-06-01 -- update by removing last argument. */
const args_for_one_oligo_or_primer *po_args,
oligo_stats*,
const thal_arg_holder*,
const char* oligo_seq,
const char* revc_oligo_seq
);
static void
oligo_hairpin(
primer_rec*,
const args_for_one_oligo_or_primer *po_args,
oligo_stats*,
const thal_arg_holder*,
const char* oligo_seq
);
static void
oligo_compute_sequence_and_reverse(
primer_rec*,
const seq_args_t*,
oligo_type,
int*,
int*,
char*,
char*
);
static void
oligo_repeat_library_mispriming(
primer_rec*,
const p3_global_settings*,
const seq_args_t*,
oligo_type,
oligo_stats*,
const dpal_arg_holder*,
pr_append_str*
);
static void
oligo_template_mispriming(
primer_rec*,
const p3_global_settings*,
const seq_args_t*,
oligo_type,
oligo_stats*,
const dpal_args *,
const thal_args *,
thal_arg_holder* thal_arg_to_use
);
static int
pair_repeat_sim(
primer_pair* ,
const p3_global_settings*
);
static void
free_repeat_sim_score(p3retval*);
static void
free_primer_repeat_sim_score(primer_rec*);
/* edited by T. Koressaar for lowercase masking: */
static int
is_lowercase_masked(
int position,
const char* sequence,
primer_rec* h,
oligo_stats*
);
static int
primer_must_match(
const p3_global_settings* pa,
primer_rec* h,
oligo_stats* stats,
const char* input_oligo_seq,
char* match_three_prime,
char* match_five_prime
);
static int
compare_nucleotides(
const char a,
const char b
);
static int
test_must_match_parameters(
char* test
);
static void
set_retval_both_stop_codons(
const seq_args_t* sa,
p3retval* retval
);
/* Functions to set bitfield parameters for oligos (or primers) */
static void
bf_set_overlaps_target(
primer_rec*,
int
);
static int
bf_get_overlaps_target(
const primer_rec*
);
static void
bf_set_overlaps_excl_region(
primer_rec*,
int
);
static int
bf_get_overlaps_excl_region(
const primer_rec*
);
static void
bf_set_infinite_pos_penalty(
primer_rec*,
int
);
static int
bf_get_infinite_pos_penalty(
const primer_rec*
);
/* Functions to record problems with oligos (or primers) */
static void
initialize_op(
primer_rec*
);
static void
op_set_completely_written(
primer_rec*
);
static void
op_set_must_match_err(
primer_rec*
);
static void
op_set_too_many_ns(
primer_rec*
);
static void
op_set_overlaps_target(
primer_rec*
);
static void
op_set_high_gc_content(
primer_rec*
);
static void
op_set_low_gc_content(
primer_rec*
);
static void
op_set_high_tm(
primer_rec*
);
static void
op_set_low_tm(
primer_rec*
);
static void
op_set_high_bound(
primer_rec*
);
static void
op_set_low_bound(
primer_rec*
);
static void
op_set_overlaps_excluded_region(
primer_rec*
);
static void
op_set_not_in_any_ok_region(
primer_rec*
);
static void
op_set_high_self_any(
primer_rec* oligo
);
static void
op_set_high_self_end(
primer_rec* oligo
);
static void
op_set_high_hairpin_th(
primer_rec* oligo
);
static void
op_set_no_gc_glamp(
primer_rec*
);
static void
op_set_too_many_gc_at_end(
primer_rec*
);
static void
op_set_high_end_stability(
primer_rec*
);
static void
op_set_high_poly_x(
primer_rec*
);
static void
op_set_low_sequence_quality(
primer_rec*
);
static void
op_set_low_end_sequence_quality(
primer_rec* oligo
);
static void
op_set_high_similarity_to_non_template_seq(
primer_rec*
);
static void
op_set_high_similarity_to_multiple_template_sites(
primer_rec*
);
static void
op_set_overlaps_masked_sequence(
primer_rec*
);
static void
op_set_too_long(
primer_rec*
);
static void
op_set_too_short(
primer_rec*
);
static void
op_set_does_not_amplify_orf(
primer_rec*
);
/*******************************************/
/* End functions to set problems in oligos */
/*******************************************/
#endif
primer3-py-2.3.1/primer3/src/libprimer3/long_seq_tm_test_main.c 0000664 0000000 0000000 00000006275 15247271707 0024510 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 1996,1997,1998,1999,2000,2001,2004,2006,2007,2008
Whitehead Institute for Biomedical Research, Steve Rozen
(http://purl.com/STEVEROZEN/), Andreas Untergasser and Helen Skaletsky.
All rights reserved.
This file is part of the primer3 suite and libraries.
The primer3 suite and libraries are free software;
you can redistribute them and/or modify them under the terms
of the GNU General Public License as published by the Free
Software Foundation; either version 2 of the License, or (at
your option) any later version.
This software is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this software (file gpl-2.0.txt in the source
distribution); if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
Test main for function long_seq_tm() in oligotm.c
Usage is e.g
long_seq_tm_test AAAAGGGCCCCCCCCTTTTTTTTTTT 3 20
In this example 3 is the 0-based start of the
substring to use and 30 is the length of the
substring to use, so Tm is calculated on
GGGCCCCCCCCTTTTTTTTT (= 52.452902).
For testing compare to independent implementation
in ../test/long_seq_tm_test.pl.
*/
#include
#include
#include
#include
#include "oligotm.h"
/* double long_seq_tm(const char* s, int start, int len, double salt_conc, double divalent_conc, double dntp_conc); */
int
main(int argc, const char**argv)
{
const char *s;
double salt_conc = 50;
double divalent_conc = 0;
double dntp_conc = 0;
double dmso_conc = 0.0;
double dmso_fact = 0.6;
double formamide_conc = 0.0;
tm_ret tm_calc; /* structure with Tm and bound (primer fraction) */
int start, len;
char *endptr;
s = argv[1];
if (0 == s) {
fprintf(stderr, "\n%s: incorrect arguments.\n", argv[0]);
fprintf(stderr, "See file long_seq_tm_test_main.c for usage.\n\n");
exit(-1);
}
start = strtol(argv[2], &endptr, 10);
len = strtol(argv[3], &endptr, 10);
printf("s=%s, start=%d, length=%d\n", s, start, len);
tm_calc = long_seq_tm(s, start, len, salt_conc, divalent_conc, dntp_conc,
dmso_conc, dmso_fact, formamide_conc);
printf("tm = %f\n", tm_calc.Tm);
return 0;
}
primer3-py-2.3.1/primer3/src/libprimer3/masker.c 0000664 0000000 0000000 00000075657 15247271707 0021432 0 ustar 00root root 0000000 0000000 #include
#include
#include
#include
#include
#include
#include
#include
#include
#include "libprimer3.h"
unsigned int glistmaker_code_match = 'G' << 24 | 'T' << 16 | '4' << 8 | 'C';
/*==================================================================================
*
* Input wrapper functions:
*
*==================================================================================*/
input_sequence *
create_input_sequence_from_file_name (const char *input_file_name, pr_append_str *parse_err)
{
input_sequence *input_seq = (input_sequence *) malloc (sizeof(input_sequence));
memset (input_seq, 0, sizeof(input_sequence));
if (!input_file_name) input_seq->sequence_file = stdin;
else input_seq->sequence_file = fopen(input_file_name, "r");
if (!input_seq->sequence_file) {
pr_append_new_chunk_external (parse_err, "Input file not found: ");
pr_append_external (parse_err, input_file_name);
return NULL;
}
return input_seq;
}
input_sequence *
create_input_sequence_from_string (char *input_string, pr_append_str *parse_err)
{
input_sequence *input_seq = (input_sequence *) malloc (sizeof(input_sequence));
if (!input_seq) {
pr_append_new_chunk_external (parse_err, "Memory allocation for input sequence failed!");
return input_seq;
}
memset (input_seq, 0, sizeof(input_sequence));
input_seq->sequence_string = input_string;
input_seq->input_size = strlen(input_string);
input_seq->current_pos = 0;
return input_seq;
}
int
get_next_char_from_input (input_sequence *input_seq, unsigned long long *current_pos)
{
int c = 0;
if (input_seq->sequence_file) {
*current_pos = ftell(input_seq->sequence_file);
c = fgetc (input_seq->sequence_file);
} else if (input_seq->sequence_string && input_seq->input_size > 0) {
if (input_seq->current_pos == input_seq->input_size) return -1;
*current_pos = input_seq->current_pos;
c = (int) input_seq->sequence_string[input_seq->current_pos];
input_seq->current_pos += 1;
}
return c;
}
char *
get_header_name_from_input (input_sequence *input_seq, unsigned long long header_pos, unsigned long long current_pos, pr_append_str *parse_err)
{
void *v = NULL;
char *header_name = (char *) malloc (sizeof(char) * (current_pos - header_pos + 2));
if (!header_name) {
pr_append_new_chunk_external (parse_err, "Memory allocation for header name failed!");
free(header_name);
return NULL;
}
if (input_seq->sequence_file) {
fseek (input_seq->sequence_file, header_pos, SEEK_SET);
v = fgets (header_name, current_pos - header_pos + 2, input_seq->sequence_file);
} else if (input_seq->sequence_string && input_seq->input_size > 0) {
v = memcpy (header_name, input_seq->sequence_string + header_pos, current_pos - header_pos + 1);
}
if (!v) {
pr_append_new_chunk_external (parse_err, "Reading header name failed!");
free(header_name);
return NULL;
}
return header_name;
}
void
delete_input_sequence (input_sequence *input_seq)
{
if (!input_seq) return;
if (input_seq->sequence_file && input_seq->sequence_file != stdin) {
fclose (input_seq->sequence_file);
}
if (input_seq) free ((void *) input_seq);
return;
}
/*==================================================================================
*
* Formula parameters functions:
*
*==================================================================================*/
formula_parameters *
create_formula_parameters_from_list_file_name (const char *list_file_name, pr_append_str *parse_err)
{
const char *data;
size_t size;
unsigned long long header_size;
unsigned int magic;
formula_parameters *fp = (formula_parameters *) malloc (sizeof (formula_parameters));
if (!fp) {
pr_append_new_chunk_external (parse_err, "Memory allocation for formula parameters failed!");
return fp;
}
memset (fp, 0, sizeof(formula_parameters));
strcpy(fp->list_file_name, list_file_name);
data = mmap_by_filename (fp->list_file_name, &size);
if (!data) {
pr_append_new_chunk_external (parse_err, "List file not found: ");
pr_append_external (parse_err, fp->list_file_name);
pr_append_external (parse_err, ". Lists can be specified by names or prefixes from the commandline or text file.");
return NULL;
}
memcpy (&magic, data, sizeof(unsigned int));
if (magic != glistmaker_code_match) {
pr_append_new_chunk_external (parse_err, "Given file is not a list file: ");
pr_append_external (parse_err, fp->list_file_name);
return NULL;
}
memcpy (&fp->oligo_length, data + 12, sizeof(unsigned int));
memcpy (&fp->words_in_list, data + 16, sizeof(unsigned int));
memcpy (&header_size, data + 32, sizeof(unsigned long long));
if (!fp->words_in_list){
pr_append_new_chunk_external (parse_err, "List file contains no kmers: ");
pr_append_external (parse_err, fp->list_file_name);
return NULL;
}
fp->word_list = data + header_size;
fp->pointer = data;
fp->size = size;
fp->binary_mask = create_binary_mask (fp->oligo_length);
return fp;
}
formula_parameters *
create_formula_parameters_from_list_file_prefix (const char *list_name_prefix, const char *kmer_lists_path, unsigned int word_length, pr_append_str *parse_err)
{
char list_file_name[300];
formula_parameters *fp;
snprintf(list_file_name, 300, "%s%s_%u.list", kmer_lists_path, list_name_prefix, word_length);
if(0 != access(list_file_name,0)){
pr_append_new_chunk_external (parse_err, "Cannot find list file");
return NULL;
}
fp = create_formula_parameters_from_list_file_name (list_file_name, parse_err);
return fp;
}
int
add_variable_to_formula_parameters (char **list_values, unsigned int nvalues, parameters_builder *pbuilder, pr_append_str *parse_err)
{
unsigned int i = 0;
char *list_name = NULL;
formula_parameters *fp = NULL;
int add_parameters_to_existing_list = 0;
unsigned int add_position;
list_name = list_values[0];
for (i = 0; i < pbuilder->nfp; i++) {
if (!strcmp (list_name, pbuilder->used_lists[i])) {
add_parameters_to_existing_list = 1;
add_position = i;
break;
}
}
if (!add_parameters_to_existing_list) {
fp = create_formula_parameters_from_list_file_name (list_name, parse_err);
if (!fp) return 1;
if (pbuilder->nfp >= pbuilder->nslots) {
pbuilder->nslots = (pbuilder->nslots + 1) * 2;
pbuilder->used_lists = (char **) realloc (pbuilder->used_lists, pbuilder->nslots * sizeof(char *));
pbuilder->fp_array = (formula_parameters **) realloc (pbuilder->fp_array, pbuilder->nslots * sizeof(formula_parameters *));
if (!pbuilder->used_lists || !pbuilder->fp_array) {
pr_append_new_chunk_external (parse_err, "Memory allocation for parameters builder failed!");
free(pbuilder->used_lists);
free(pbuilder->fp_array);
return 1;
}
}
pbuilder->used_lists[pbuilder->nfp] = list_name;
pbuilder->fp_array[pbuilder->nfp] = fp;
add_position = pbuilder->nfp;
pbuilder->nfp += 1;
}
if (fp || add_parameters_to_existing_list) {
int squared = 0;
unsigned int mm = 0;
double coef = DEFAULT_COEF;
char *end = NULL;
if (nvalues > 1) {
coef = (list_values[1][0] == '-') ? strtod (list_values[1] + 1, &end) * (-1.0) : strtod (list_values[1], &end);
if (*end != 0) {
pr_append_new_chunk_external (parse_err, "Invalid coefficient value: ");
pr_append_external (parse_err, list_values[1]);
return 2;
}
}
if (nvalues > 2) {
mm = strtol (list_values[2], &end, 10);
if (*end != 0 || mm > 2) {
pr_append_new_chunk_external (parse_err, "Invalid mismatches value specified: ");
pr_append_external (parse_err, list_values[2]);
pr_append_external (parse_err, ". Must be a positive integer less than 2.");
return 3;
}
}
if (nvalues > 3) {
if (!strcmp(list_values[3], "sq")) squared = 1;
}
switch (mm) {
case 0:
if (squared) pbuilder->fp_array[add_position]->mm0_2 = coef;
else pbuilder->fp_array[add_position]->mm0 = coef;
break;
case 1:
if (squared) pbuilder->fp_array[add_position]->mm1_2 = coef;
else pbuilder->fp_array[add_position]->mm1 = coef;
break;
case 2:
if (squared) pbuilder->fp_array[add_position]->mm2_2 = coef;
else pbuilder->fp_array[add_position]->mm2 = coef;
break;
}
}
return 0;
}
formula_parameters **
create_default_formula_parameters (const char *list_name_prefix, const char *kmer_lists_path, pr_append_str *parse_err)
{
formula_parameters *fp1 = create_formula_parameters_from_list_file_prefix (list_name_prefix, kmer_lists_path, DEFAULT_WORD_LEN_1, parse_err);
formula_parameters *fp2 = create_formula_parameters_from_list_file_prefix (list_name_prefix, kmer_lists_path, DEFAULT_WORD_LEN_2, parse_err);
if (!fp1 || !fp2) return NULL;
formula_parameters **fp = (formula_parameters **) malloc (2 * sizeof (formula_parameters *));
if (!fp) {
pr_append_new_chunk_external (parse_err, "Memory allocation for formula parameters failed!");
return fp;
}
fp[0] = fp1;
fp[1] = fp2;
fp1->mm0 = DEFAULT_COEF_1;
fp2->mm0 = DEFAULT_COEF_2;
return fp;
}
formula_parameters **
read_formula_parameters_from_file (const char *lists_file_name, unsigned int *nlist_parameters, parameters_builder *pbuilder, double *intercept, pr_append_str *parse_err)
{
FILE *lists = fopen (lists_file_name, "r");
char *line = NULL;
size_t line_length = 0;
int read_chars;
int v;
if (!lists) {
pr_append_new_chunk_external (parse_err, "File not found: ");
pr_append_external (parse_err, lists_file_name);
return NULL;
}
while ((read_chars = (int) getline(&line, &line_length, lists)) > 1) {
char **values = NULL;
unsigned int nvalues = 0;
line[read_chars] = '\0';
strip_string(line);
values = split_string(line, ' ', &nvalues);
if (nvalues == 1) {
double ic;
double neg = 1.0;
char *end = NULL;
if (values[0][0] == '-') {
values[0] += 1;
neg = -1.0;
}
ic = strtod (values[0], &end);
if (*end == 0) {
*intercept = ic * neg;
continue;
}
}
v = add_variable_to_formula_parameters (values, nvalues, pbuilder, parse_err);
if (v) {
free(pbuilder->used_lists);
free(pbuilder->fp_array);
return NULL;
}
*nlist_parameters += 1;
}
return pbuilder->fp_array;
}
void
delete_formula_parameters (formula_parameters **fp, unsigned int nlists)
{
unsigned int i;
if (!fp) return;
for (i = 0; i < nlists; i++) {
if (fp[i]->pointer) munmap ((void *) fp[i]->pointer, fp[i]->size);
if (fp[i]) free ((void *) fp[i]);
}
if (fp) free ((void *) fp);
return;
}
/*==================================================================================
*
* Output function:
*
*==================================================================================*/
output_sequence *
create_output_sequence (unsigned long long seq_len, masking_direction mdir, pr_append_str *parse_err)
{
output_sequence *output_seq = (output_sequence *) malloc (sizeof (output_sequence));
memset (output_seq, 0, sizeof (output_sequence));
if (!output_seq) {
pr_append_new_chunk_external (parse_err, "Memory allocation for output sequence failed!");
return output_seq;
}
if (mdir == both_separately) {
output_seq->sequence_fwd = (char *) malloc (seq_len + 1);
memset (output_seq->sequence_fwd, 0, seq_len + 1);
output_seq->sequence_rev = (char *) malloc (seq_len + 1);
memset (output_seq->sequence_rev, 0, seq_len + 1);
} else {
output_seq->sequence = (char *) malloc (seq_len + 1);
memset (output_seq->sequence, 0, seq_len + 1);
}
if (!output_seq->sequence_fwd && !output_seq->sequence_rev && !output_seq->sequence) {
pr_append_new_chunk_external (parse_err, "Memory allocation for output sequence failed!");
return NULL;
}
output_seq->pos = 0;
return output_seq;
}
void
delete_output_sequence (output_sequence *output_seq)
{
if (!output_seq) return;
if (output_seq->sequence) free ((void *) output_seq->sequence);
if (output_seq->sequence_fwd) free ((void *) output_seq->sequence_fwd);
if (output_seq->sequence_rev) free ((void *) output_seq->sequence_rev);
if (output_seq) free ((void* ) output_seq);
return;
}
void
write_header_to_output (output_sequence *output_seq, char *header_name, const masker_parameters *mp, pr_append_str *parse_err)
{
void *v = NULL;
if (mp->print_sequence)
fprintf (stdout, "%s", header_name);
else if (output_seq) {
if (mp->mdir == both_separately) {
v = memcpy (output_seq->sequence_fwd + output_seq->pos, header_name, strlen(header_name));
if (v) v = memcpy (output_seq->sequence_rev + output_seq->pos, header_name, strlen(header_name));
} else {
v = memcpy (output_seq->sequence + output_seq->pos, header_name, strlen(header_name));
}
if (!v) {
pr_append_new_chunk_external (parse_err, "Writing header to output failed!");
return;
}
output_seq->pos += strlen(header_name);
}
return;
}
void
write_char_to_output (output_sequence *output_seq, char c, char c_other, const masker_parameters *mp, pr_append_str *parse_err)
{
if (mp->print_sequence) {
fprintf (stdout, "%c", c);
} else if (output_seq) {
if (mp->mdir == both_separately) {
output_seq->sequence_fwd[output_seq->pos] = c;
output_seq->sequence_rev[output_seq->pos] = c_other;
} else {
output_seq->sequence[output_seq->pos] = c;
}
output_seq->pos += 1;
}
return;
}
/*==================================================================================
*
* Masking buffer functions:
*
*==================================================================================*/
masking_buffer *
create_masking_buffer (unsigned int word_length, pr_append_str *parse_err)
{
masking_buffer *mbuffer = (masking_buffer *) malloc (sizeof(masking_buffer));
if (!mbuffer) {
pr_append_new_chunk_external (parse_err, "Memory allocation for masking buffer failed!");
return mbuffer;
}
initialize_masking_buffer (mbuffer, word_length);
return mbuffer;
}
void
initialize_masking_buffer (masking_buffer *mbuffer, unsigned int word_length)
{
memset (mbuffer, 0, sizeof (masking_buffer));
mbuffer->ei = MAX_BUFFER_SIZE - word_length + 1;
return;
}
void
delete_masking_buffer (masking_buffer *mbuffer)
{
if (mbuffer) {
free ((void *) mbuffer);
}
return;
}
void
add_char_to_buffer (char c, masking_buffer *mbuffer, int char_type)
{
mbuffer->buffer[mbuffer->wi] = c;
mbuffer->mask_positions_fwd[mbuffer->wi] = 0;
mbuffer->mask_positions_rev[mbuffer->wi] = 0;
mbuffer->non_nucleotide_positions[mbuffer->wi] = 0;
if (char_type != WHITESPACE) {
if (mbuffer->mi > 0) {
mbuffer->mask_positions_fwd[mbuffer->wi] = 1;
mbuffer->mi -= 1;
} else if (char_type == MASKED_CHAR) {
mbuffer->mask_positions_rev[mbuffer->wi] = 1;
mbuffer->mask_positions_fwd[mbuffer->wi] = 1;
}
while (mbuffer->non_nucleotide_positions[mbuffer->ei] && !(mbuffer->mask_positions_fwd[mbuffer->ei])) {
mbuffer->ei = TAKE_STEP_FORWARD(mbuffer->ei);
}
/* when it finds the first non-whitespace character it increases the ei one more time */
mbuffer->ei = TAKE_STEP_FORWARD(mbuffer->ei);
}
if (char_type == WHITESPACE || char_type == MASKED_CHAR) {
mbuffer->non_nucleotide_positions[mbuffer->wi] = 1;
}
mbuffer->wi = TAKE_STEP_FORWARD(mbuffer->wi);
return;
}
/* next character is not nucleotide, or if nucleotide then already masked */
#define COND0(i) (mbuffer->non_nucleotide_positions[i] || \
(mp->do_soft_masking && mbuffer->buffer[i] >= 'a'))
/* output contains only one sequence and the next character is masked or
* output contains two sequences and the next character is masked on the forward strand */
#define COND1(i) ((mp->mdir != both_separately && (mbuffer->mask_positions_fwd[i] || \
mbuffer->mask_positions_rev[i])) || (mp->mdir == both_separately && mbuffer->mask_positions_fwd[i]))
/* output contains two sequences and the next character is masked on the reverse strand */
#define COND2(i) (mp->mdir == both_separately && mbuffer->mask_positions_rev[i])
void
empty_buffer (output_sequence *output_seq, const masker_parameters *mp, masking_buffer *mbuffer, int flush_all, pr_append_str *parse_err)
{
unsigned int end = mbuffer->ei;
if (flush_all) end = mbuffer->wi;
while (mbuffer->ri != end) {
if (COND0(mbuffer->ri)) {
write_char_to_output (output_seq, mbuffer->buffer[mbuffer->ri], mbuffer->buffer[mbuffer->ri], mp, parse_err);
} else {
if (mp->do_soft_masking) {
write_char_to_output (output_seq, COND1(mbuffer->ri) ? mbuffer->buffer[mbuffer->ri] + 32 : mbuffer->buffer[mbuffer->ri],
COND2(mbuffer->ri) ? mbuffer->buffer[mbuffer->ri] + 32 : mbuffer->buffer[mbuffer->ri], mp, parse_err);
} else {
write_char_to_output (output_seq, COND1(mbuffer->ri) ? mp->masking_char : mbuffer->buffer[mbuffer->ri],
COND2(mbuffer->ri) ? mp->masking_char : mbuffer->buffer[mbuffer->ri], mp, parse_err);
}
}
mbuffer->ri = TAKE_STEP_FORWARD(mbuffer->ri);
}
return;
}
#undef COND0
#undef COND1
#undef COND2
/*==================================================================================
*
* K-mer searching functions:
*
*==================================================================================*/
unsigned int
binary_search (formula_parameters *fp, unsigned long long word)
{
unsigned long long current_word, low, high, mid;
unsigned int freq;
low = 0;
high = fp->words_in_list - 1;
mid = (low + high) / 2;
while (low <= high) {
current_word = *((unsigned long long *) (fp->word_list + mid * (sizeof (unsigned long long) + sizeof (unsigned int))));
if (current_word < word) {
low = mid + 1;
} else if (current_word > word) {
if (mid == 0) break;
high = mid - 1;
} else {
freq = *((unsigned int *) (fp->word_list + mid * (sizeof (unsigned long long) + sizeof (unsigned int)) + sizeof (unsigned long long)));
return freq;
}
mid = (low + high) / 2;
}
return 0;
}
unsigned int
get_frequency_of_canonical_oligo (formula_parameters *fp, unsigned long long word)
{
unsigned int freq_fwd = 0, freq_rev = 0;
freq_fwd = binary_search (fp, word);
if (!freq_fwd) {
freq_rev = binary_search (fp, get_reverse_complement (word, fp->oligo_length));
//fprintf (stderr, "rev %u\n", freq_rev);
if(freq_rev==0){ /*heuristics is used, by default, for speed and memory issues,
kmer lists are generated with kmers freq >1*/
freq_rev=1;
}
return freq_rev;
}
//fprintf (stderr, "fwd %u\n", freq_fwd);
if(freq_fwd==0){ /*heuristics is used, by default, for speed and memory issues,
kmer lists are generated with kmers freq >1*/
freq_fwd=1;
}
return freq_fwd;
}
void
get_oligo_frequencies (oligo_counts *oc, formula_parameters *fp, unsigned long long word, unsigned int mm, int strand)
{
unsigned int i, j;
unsigned int count_0mm = 0;
unsigned int count_1mm = 0;
unsigned int count_2mm = 0;
unsigned int mismatch;
word &= fp->binary_mask;
count_0mm = get_frequency_of_canonical_oligo (fp, word);
if (mm > 0) {
for (i = 0; i < fp->oligo_length; i++) {
for (mismatch = 1; mismatch < 4; mismatch++) {
unsigned long long mask = mismatch << (2 * i);
count_1mm += get_frequency_of_canonical_oligo (fp, word ^ mask);
if (mm > 1) {
for (j = i + 1; j < fp->oligo_length; j++) {
unsigned long long mask2 = mismatch << (2 * j);
count_2mm += get_frequency_of_canonical_oligo (fp, word ^ mask ^ mask2);
}
}
}
}
}
count_1mm += count_0mm;
count_2mm += count_1mm;
if (strand != REV) {
oc->count_mm0_fwd = count_0mm;
oc->count_mm1_fwd = count_1mm;
oc->count_mm2_fwd = count_2mm;
}
if (strand != FWD) {
oc->count_mm0_rev = count_0mm;
oc->count_mm1_rev = count_1mm;
oc->count_mm2_rev = count_2mm;
}
return;
}
/*==================================================================================
*
* Masking functions:
*
*==================================================================================*/
void
calculate_scores (oligo_pair *h, const masker_parameters *mp, unsigned int word_length)
{
formula_parameters **fp_array = mp->fp; // fp[0] on pointer!!
unsigned int nlists = mp->nlists;
unsigned int i;
for (i = 0; i < nlists; i++) {
oligo_counts oc = {0};
formula_parameters *fp = fp_array[i];
unsigned int mm = (fp->mm2 || fp->mm2_2) ? 2 : ((fp->mm1 || fp->mm1_2) ? 1 : 0);
if ((mp->mdir == both_on_same || mp->mdir == both_separately || mp->abs_cutoff) && word_length == fp->oligo_length) {
double score = 0.0;
unsigned int abs_score = 0;
if (mp->mdir == rev) get_oligo_frequencies (&oc, fp, h->rev, mm, BOTH);
else get_oligo_frequencies (&oc, fp, h->fwd, mm, BOTH);
if (oc.count_mm0_fwd || oc.count_mm0_rev) {
unsigned int count = oc.count_mm0_fwd ? oc.count_mm0_fwd : oc.count_mm0_rev;
score += fp->mm0 * log(oc.count_mm0_fwd) + fp->mm0_2 * log(oc.count_mm0_fwd) * log(oc.count_mm0_fwd);
abs_score = count;
}
if (oc.count_mm1_fwd) {
score += fp->mm1 * log(oc.count_mm1_fwd) + fp->mm1_2 * log(oc.count_mm1_fwd) * log(oc.count_mm1_fwd);
abs_score = oc.count_mm1_fwd;
}
if (oc.count_mm2_fwd) {
score += fp->mm2 * log(oc.count_mm2_fwd) + fp->mm2_2 * log(oc.count_mm2_fwd) * log(oc.count_mm2_fwd);
abs_score = oc.count_mm2_fwd;
}
if (mp->abs_cutoff) {
h->abs_score = abs_score;
} else {
h->score_fwd += score;
h->score_rev += score;
}
} else {
if (mp->mdir != rev) {
get_oligo_frequencies (&oc, fp, h->fwd, mm, FWD);
//fprintf (stderr, "oc.count.fwd %u\n", oc.count_mm0_fwd);
if (oc.count_mm0_fwd) h->score_fwd += fp->mm0 * log(oc.count_mm0_fwd) + fp->mm0_2 * log(oc.count_mm0_fwd) * log(oc.count_mm0_fwd);
if (oc.count_mm1_fwd) h->score_fwd += fp->mm1 * log(oc.count_mm1_fwd) + fp->mm1_2 * log(oc.count_mm1_fwd) * log(oc.count_mm1_fwd);
if (oc.count_mm2_fwd) h->score_fwd += fp->mm2 * log(oc.count_mm2_fwd) + fp->mm2_2 * log(oc.count_mm2_fwd) * log(oc.count_mm2_fwd);
//fprintf (stderr, "1: sõnad: %s %s, skoorid %f %f, abs_skoor %u\n", word_to_string(h->fwd, word_length), word_to_string(h->rev, word_length), h->score_fwd, h->score_rev, h->abs_score);
}
if (mp->mdir != fwd) {
get_oligo_frequencies (&oc, fp, h->rev, mm, REV);
if (oc.count_mm0_rev) h->score_rev += fp->mm0 * log(oc.count_mm0_rev) + fp->mm0_2 * log(oc.count_mm0_rev) * log(oc.count_mm0_rev);
if (oc.count_mm1_rev) h->score_rev += fp->mm1 * log(oc.count_mm1_rev) + fp->mm1_2 * log(oc.count_mm1_rev) * log(oc.count_mm1_rev);
if (oc.count_mm2_rev) h->score_rev += fp->mm2 * log(oc.count_mm2_rev) + fp->mm2_2 * log(oc.count_mm2_rev) * log(oc.count_mm2_rev);
}
}
}
if (h->score_fwd) h->score_fwd = exp(h->score_fwd + mp->formula_intercept) / (1 + exp(h->score_fwd + mp->formula_intercept));
if (h->score_rev) h->score_rev = exp(h->score_rev + mp->formula_intercept) / (1 + exp(h->score_rev + mp->formula_intercept));
//fprintf (stderr, "2: sõnad: %s %s, skoorid %f %f, abs_skoor %u\n", word_to_string(h->fwd, word_length), word_to_string(h->rev, word_length), h->score_fwd, h->score_rev, h->abs_score);
return;
}
void
mask_oligo_region (oligo_pair *h, const masker_parameters *mp, masking_buffer *mbuffer, unsigned int word_length, int debug)
{
calculate_scores (h, mp, word_length);
if (debug > 1) {
fprintf (stderr, "score-fwd: %f score-rev: %f\n", h->score_fwd, h->score_rev);
}
if (mp->mdir != rev && ((mp->failure_rate && h->score_fwd > mp->failure_rate) ||
(mp->abs_cutoff && h->abs_score >= mp->abs_cutoff))) {
int masked = 0, i = TAKE_STEP_BACK(mbuffer->wi);
while (masked < mp->nucl_masked_in_5p_direction) {
if (!mbuffer->non_nucleotide_positions[i] && !mbuffer->mask_positions_fwd[i]) {
mbuffer->mask_positions_fwd[i] = 1;
masked += 1;
} else if (mbuffer->mask_positions_fwd[i]) {
masked += 1;
}
i = TAKE_STEP_BACK(i);
}
mbuffer->mi = mp->nucl_masked_in_3p_direction;
}
if (mp->mdir != fwd && ((mp->failure_rate && h->score_rev > mp->failure_rate) ||
(mp->abs_cutoff && h->abs_score >= mp->abs_cutoff))) {
int masked = 0, i = TAKE_STEP_BACK(mbuffer->ei);
while (masked < mp->nucl_masked_in_5p_direction + mp->nucl_masked_in_3p_direction) {
if (!mbuffer->non_nucleotide_positions[i] && !mbuffer->mask_positions_rev[i]) {
mbuffer->mask_positions_rev[i] = 1;
masked += 1;
} else if (mbuffer->mask_positions_rev[i]) {
masked += 1;
}
i = TAKE_STEP_FORWARD(i);
}
}
return;
}
void
read_and_mask_sequence (input_sequence *input_seq, output_sequence *output_seq, const masker_parameters *mp,
pr_append_str *parse_err, int debug)
{
int is_header = 0, init_round = 1;
unsigned long long word_fwd = 0, word_rev = 0, nucl_value;
unsigned int current_length = 0;
unsigned int word_length = 0;
unsigned long long binary_mask = 0;
masking_buffer *mbuffer;
unsigned long long header_pos = 0, current_pos = 0;
unsigned int i;
/* size of window is the length of the longest k-mers that we use */
for (i = 0; i < mp->nlists; i++) {
if (mp->fp[i]->oligo_length > word_length) {
binary_mask = mp->fp[i]->binary_mask;
word_length = mp->fp[i]->oligo_length;
}
}
/* buffer for masking*/
mbuffer = create_masking_buffer (word_length + mp->nucl_masked_in_3p_direction, parse_err);
while (1) {
oligo_pair h = {0};
int c = get_next_char_from_input (input_seq, ¤t_pos);
/* EOF or end of string */
if (c < 0) break;
if (debug > 1) {
fprintf (stderr, "pos: %llu, input: %c\n", current_pos, c);
}
/* In case it is a FASTA file we need to consider
* the headers separately */
if (c == '>') {
header_pos = current_pos;
word_fwd = word_rev = 0;
current_length = 0;
is_header = 1;
}
/* continue until the end of header */
if (is_header) {
if (c == 10 || c == 13) {
char *header_name = get_header_name_from_input (input_seq, header_pos, current_pos, parse_err);
empty_buffer (output_seq, mp, mbuffer, FLUSH_ALL, parse_err);
write_header_to_output (output_seq, header_name, mp, parse_err);
initialize_masking_buffer (mbuffer, word_length + mp->nucl_masked_in_3p_direction);
init_round = 1;
is_header = 0;
free(header_name);
}
} else {
if (!init_round && mbuffer->wi == mbuffer->ri) {
empty_buffer (output_seq, mp, mbuffer, KEEP_UNCERTAIN_REGION, parse_err);
}
init_round = 0;
if (!strchr(ALPHABET, c) && c > ' ') {
add_char_to_buffer (c, mbuffer, MASKED_CHAR);
word_fwd = word_rev = 0;
current_length = 0;
continue;
} else if (c <= ' ') {
add_char_to_buffer (c, mbuffer, WHITESPACE);
continue;
} else {
add_char_to_buffer (c, mbuffer, NUCLEOTIDE);
}
/* add next nucleotide to the word */
nucl_value = get_nucl_value (c);
if (mp->mdir != rev) {
word_fwd <<= 2;
word_fwd |= nucl_value;
}
if (mp->mdir != fwd) {
word_rev >>= 2;
word_rev |= ((~nucl_value & 3) << ((word_length - 1) * 2));
}
current_length += 1;
if (current_length > word_length) {
word_fwd &= binary_mask;
word_rev &= binary_mask;
current_length = word_length;
}
if (current_length == word_length) {
h.fwd = word_fwd;
h.rev = word_rev;
if (debug > 1) {
fprintf (stderr, "%llu %llu\n", h.fwd, h.rev);
}
mask_oligo_region (&h, mp, mbuffer, word_length, debug);
}
}
}
empty_buffer (output_seq, mp, mbuffer, FLUSH_ALL, parse_err);
delete_masking_buffer (mbuffer);
return;
}
/*==================================================================================
*
* Helping functions:
*
*==================================================================================*/
const char *
mmap_by_filename (const char *filename, size_t *size)
{
struct stat st;
int status, handle;
const char *data;
status = stat (filename, &st);
if (status < 0) {
return NULL;
}
handle = open (filename, O_RDONLY);
if (handle < 0) {
return NULL;
}
data = (const char *) mmap (NULL, st.st_size, PROT_READ, MAP_PRIVATE, handle, 0);
if (data == (const char *) -1) {
return NULL;
} else {
*size = (size_t)st.st_size;
}
close (handle);
return data;
}
unsigned long long
create_binary_mask (unsigned int word_length)
{
unsigned int i;
unsigned long long mask = 0L;
for (i = 0; i < 2 * word_length; i++) {
mask = (mask << 1) | 1;
}
return mask;
}
unsigned long long
get_nucl_value (char nucl)
{
static unsigned long long bit1 = 1 << 2;
static unsigned long long bit2 = 3 << 1;
if (nucl & bit1) {
return ((nucl >> 4) | 2) & 3;
}
return (nucl & bit2) >> 1;
}
unsigned long long
get_reverse_complement (unsigned long long word, unsigned int word_length)
{
unsigned int i;
unsigned long long mask, v, revcompl = 0L;
word = ~word;
mask = 3;
for (i = 0; i < word_length; i++) {
v = word & mask;
revcompl <<= 2;
revcompl |= v;
word >>= 2;
}
return revcompl;
}
unsigned long long
string_to_word (const char *s, unsigned int string_length, unsigned int word_length)
{
unsigned int i;
unsigned long long word = 0L;
for (i = string_length - word_length; i < string_length; i++) {
word <<= 2;
word |= get_nucl_value (s[i]);
}
return word;
}
char *
word_to_string (unsigned long long word, unsigned int wordlength)
{
char *s = (char *) malloc (wordlength + 1);
unsigned int i, temp;
for (i = 0; i < wordlength; i++) {
temp = word & 3;
s[wordlength - i - 1] = ALPHABET[temp];
word >>= 2;
}
s[wordlength] = 0;
return s;
}
char **
split_string (char string[], char c, unsigned int *nchunks)
{
char **string_chunks = (char **) malloc (MAX_SPLITS * sizeof(char *));
char *p;
char tmp[100];
unsigned int i = 0, l;
while ((p = strchr (string, c))) {
/* length of substring to copy */
l = (int) (p - string);
/* add substring to the output */
if (l > 0) {
memcpy (tmp, string, l);
tmp[l] = '\0';
string_chunks[i] = (char *) malloc ((l + 1) * sizeof(char));
strcpy (string_chunks[i], tmp);
i += 1;
*nchunks += 1;
}
string = p + 1;
}
/* length of the last substring */
l = strlen(string);
if (l > 0) {
memcpy (tmp, string, l);
tmp[l] = '\0';
/* add last substring to output */
string_chunks[i] = (char *) malloc ((l + 1) * sizeof(char));
strcpy (string_chunks[i], tmp);
*nchunks += 1;
}
return string_chunks;
}
void
strip_string (char string[])
{
size_t l = strlen(string);
if (string[l - 1] == '\n') string[l - 1] = '\0';
return;
}
primer3-py-2.3.1/primer3/src/libprimer3/masker.h 0000664 0000000 0000000 00000024647 15247271707 0021430 0 ustar 00root root 0000000 0000000 #ifndef MASKER_H
#define MASKER_H
#include
#include
#include
/* NOTE: NC Moved pr_append_str to p3_seq_lib.h to avoid */
/* circular import in libprimer3.h */
/* masker.h needed an update also to get this pr_append_str struct*/
#include "p3_seq_lib.h"
/* ALPHABET defines which characters are considered as nucleotides */
#define ALPHABET "ACGTUacgtu"
#define FWD 1
#define REV 2
#define BOTH 3
#define MAX_BUFFER_SIZE 5000
#define MAX_SPLITS 10
#define NUCLEOTIDE 0
#define WHITESPACE 1
#define MASKED_CHAR 2
#define FLUSH_ALL 1
#define KEEP_UNCERTAIN_REGION 0
#define DEFAULT_COEF 1.0
/* default formula parameter coefficients */
#define DEFAULT_NLISTS 2
#define DEFAULT_NLIST_PARAMETERS 2
#define DEFAULT_WORD_LEN_1 11
#define DEFAULT_WORD_LEN_2 16
#define DEFAULT_COEF_1 0.1772
#define DEFAULT_COEF_2 0.239
#define DEFAULT_INTERCEPT -4.336
/* default masking parameter values */
#define PRINT_SEQUENCE 1 /* used only for commandline tool */
#define DEFAULT_FAILURE_RATE 0.1
#define DEFAULT_ABS_CUTOFF 0
#define DEFAULT_MASK_CHAR 'N'
#define DEFAULT_MASKING_DIRECTION both_on_same /* used only for commandline tool */
#define DEFAULT_M5P 1
#define DEFAULT_M3P 0
#define DEFAULT_LIST_FILE_PREFIX (char *)"homo_sapiens"
/* macros for moving forward and backward in masking buffer */
#define TAKE_STEP_BACK(i) \
(i == 0) ? (MAX_BUFFER_SIZE - 1) : (i - 1)
#define TAKE_STEP_FORWARD(i) \
(i == MAX_BUFFER_SIZE - 1) ? 0 : (i + 1)
struct pr_append_str;
/*
* masking_direction: One can mask the forward, reverse or both strands.
* both_on_same outputs one sequence that contains masked nucleotides according to both strands.
* both_separately outputs two masked sequences separately.
*/
typedef enum masking_direction {
both_on_same = 0,
both_separately = 1,
fwd = 2,
rev = 3
} masking_direction;
/*
* input_sequence: A wrapper for input sequence. Input can be either a stream or a
* string variable
*/
typedef struct input_sequence {
FILE *sequence_file;
const char *sequence_string;
size_t input_size;
size_t current_pos;
} input_sequence;
/*
* output_sequence: A wrapper for output sequence in case the output is given in a
* string variable
*/
typedef struct output_sequence {
char *sequence;
unsigned int pos;
/* These will be used instead of char *sequence
* in case of both_separately masking direction */
char *sequence_fwd;
char *sequence_rev;
} output_sequence;
/*
* formula_parameters: All parameters concerning one input k-mer list
*/
typedef struct formula_parameters {
/* If the list is created with GenomeTester4,
* 210 char should be enough to contain the full list name */
char list_file_name[210];
unsigned int oligo_length;
/* binary mask is used for cutting the k-mer into the size of oligo_length */
unsigned long long binary_mask;
/* number of unique k-mers in the given k-mer list */
unsigned long long words_in_list;
/* pointer to k-mer list */
const char *word_list;
const char *pointer;
size_t size;
/* coefficients for all possible masking formula variables (and their squares)
* concerning this k-mer list.
* If certain variables are not used, their coefficiest are equal to 0 */
double mm0;
double mm1;
double mm2;
double mm0_2;
double mm1_2;
double mm2_2;
} formula_parameters;
/*
* parameters_builder: Helping structure for reading the formula parameters
*/
typedef struct parameters_builder {
formula_parameters **fp_array;
double intercept;
char **used_lists;
unsigned int nslots;
unsigned int nfp;
} parameters_builder;
/*
* masker_parameters: Masker parameters contain all the user specified
* (otherwise default) parameter values
*/
typedef struct masker_parameters {
/* strand to mask */
masking_direction mdir;
/* primer failure rate cutoff used in primer design,
* potential locations in a sequence for primers with PCR
* failure rate over the given cutoff are masked
*(see function calculate_scores() from masker.c) */
double failure_rate;
/* absolute value cutoff, this can be used for masking all the k-mers in a sequence
* that have the frequency over abs_cutoff in a k-mer list */
unsigned int abs_cutoff;
/* number of nucleotides masked in 5' and 3' direction with respect
* to the 3' end of a primer */
int nucl_masked_in_5p_direction;
int nucl_masked_in_3p_direction;
/* If masker is used as a separate application then always print_sequence=1,
* i.e the output is sent to stdout.
* If print_sequence=0 the output is written in a string variable and can be forwarded
* to the next function */
int print_sequence;
/* if do_soft_masking=1, masked nucleotides and converted to lower-case, else
* masked nucleotide are converted to masking_char ('N' by default) */
int do_soft_masking;
char masking_char;
/* size of the masking window */
int window_size;
/* number of k-mer lists used in the masking formula */
unsigned int nlists;
/* k-mer lists and all their parameters which are used in the masking formula */
char *list_prefix;
formula_parameters **fp;
double formula_intercept;
} masker_parameters;
/*
* masking_buffer: A round buffer for storing all the characters of the input sequence
* as well as the masking and output information
*/
typedef struct masking_buffer {
/* the main array containing the characters that are read
* from the sequence input */
char buffer[MAX_BUFFER_SIZE];
/* indicates the positions in the buffer that do not contain a
* nucleotide character */
int non_nucleotide_positions[MAX_BUFFER_SIZE];
/* indicates the nucleotide positions in the buffer that
* will be masked in he output */
int mask_positions_fwd[MAX_BUFFER_SIZE];
int mask_positions_rev[MAX_BUFFER_SIZE];
/* indices for reading from the buffer and
writing to the buffer */
unsigned int ri;
unsigned int wi;
/* index of the 5' end of the k-mer last entered plus the
* number of nucleotides masked in 3' direction. This index is used
* to determine the first positions which can still be altered and therefore cannot be
* flushed out of the buffer yet */
unsigned int ei;
/* mi indicates the number of nucleotides that are
* yet to be masked in 3' direction */
unsigned int mi;
} masking_buffer;
/*
* oligo_pair: contains k-mer pairs and their calculated scores
*/
typedef struct oligo_pair {
/* fwd and rev k-mers */
unsigned long long fwd;
unsigned long long rev;
/* a k-mer score is a failure rate of such a primer that
*contains a given k-mer in its 3' end */
double score_fwd;
double score_rev;
/* abs_score is a number of given k-mers in a k-mer list */
unsigned int abs_score;
} oligo_pair;
/*
* oligo_counts: contains all k-mer frequencies (for both forward and reverse strand)
* retrieved from the k-mer lists
*/
typedef struct oligo_counts {
unsigned int oligo_length;
unsigned int count_mm0_fwd;
unsigned int count_mm1_fwd;
unsigned int count_mm2_fwd;
unsigned int count_mm0_rev;
unsigned int count_mm1_rev;
unsigned int count_mm2_rev;
} oligo_counts;
/*
*
*/
input_sequence *create_input_sequence_from_file_name (const char *input_file_name, pr_append_str *parse_err);
input_sequence *create_input_sequence_from_string (char *input_string, pr_append_str *parse_err);
void delete_input_sequence (input_sequence *input_seq);
int get_next_char_from_input (input_sequence *input_seq, unsigned long long *current_pos);
char *get_header_name_from_input (input_sequence *input_seq, unsigned long long header_pos, unsigned long long current_pos, pr_append_str *parse_err);
/*
*
*/
formula_parameters *create_formula_parameters_from_list_file_name (const char *list_file_name, pr_append_str *parse_err);
formula_parameters *create_formula_parameters_from_list_file_prefix (const char *list_name_prefix, const char *kmer_lists_path, unsigned int word_length, pr_append_str *parse_err);
formula_parameters **create_default_formula_parameters (const char *list_name_prefix, const char *kmer_lists_path, pr_append_str *parse_err);
formula_parameters **read_formula_parameters_from_file (const char *lists_file_name, unsigned int *nlist_parameters, parameters_builder *pbuilder, double *intercept, pr_append_str *parse_err);
int add_variable_to_formula_parameters (char **list_values, unsigned int nvalues, parameters_builder *pbuilder, pr_append_str *parse_err);
void delete_formula_parameters (formula_parameters **fp, unsigned int nlists);
/*
*
*/
output_sequence *create_output_sequence (unsigned long long seq_len, masking_direction mdir, pr_append_str *parse_err);
void delete_output_sequence (output_sequence *output_seq);
void write_header_to_output (output_sequence *output_seq, char *header_name, const masker_parameters *mp, pr_append_str *parse_err);
void write_char_to_output (output_sequence *output_seq, char c, char c_other, const masker_parameters *mp, pr_append_str *parse_err);
/*
*
*/
masking_buffer *create_masking_buffer (unsigned int word_length, pr_append_str *parse_err);
void initialize_masking_buffer (masking_buffer *mbuffer, unsigned int word_length);
void delete_masking_buffer (masking_buffer *mbuffer);
void add_char_to_buffer (char c, masking_buffer *mbuffer, int char_type);
void empty_buffer (output_sequence *output_seq, const masker_parameters *mp, masking_buffer *mbuffer, int flush_all, pr_append_str *parse_err);
/*
*
*/
void get_oligo_frequencies (oligo_counts *oc, formula_parameters *fp, unsigned long long word, unsigned int mm, int strand);
/*
*
*/
void calculate_scores (oligo_pair *h, const masker_parameters *mp, unsigned int word_length);
void mask_oligo_region (oligo_pair *h, const masker_parameters *mp, masking_buffer *mbuffer, unsigned int word_length, int debug);
void read_and_mask_sequence (input_sequence *input_seq, output_sequence *output_seq, const masker_parameters *mp, pr_append_str *parse_err, int debug);
const char *mmap_by_filename (const char *filename, size_t *size);
unsigned long long get_reverse_complement (unsigned long long word, unsigned int word_length);
/*
*
*/
unsigned long long create_binary_mask (unsigned int word_length);
/*
* converts nucleotide character into a 2-bit integer as follows:
* 'A' -> 0; 'C' -> 1; 'G' -> 2; 'T'/'U' -> 3
*/
unsigned long long get_nucl_value (char nucl);
unsigned long long string_to_word (const char *s, unsigned int string_length, unsigned int word_length);
char *word_to_string (unsigned long long word, unsigned int wordlength);
void strip_string (char string[]);
char **split_string (char string[], char c, unsigned int *nchunks);
#endif
primer3-py-2.3.1/primer3/src/libprimer3/masker_main.c 0000664 0000000 0000000 00000037532 15247271707 0022424 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 1996,1997,1998,1999,2000,2001,2004,2006,2007,2008,2009
Whitehead Institute for Biomedical Research, Steve Rozen
(http://purl.com/STEVEROZEN/), and Helen Skaletsky
All rights reserved.
This file is part of primer3 software suite.
This software suite is is free software;
you can redistribute it and/or modify it under the terms
of the GNU General Public License as published by the Free
Software Foundation; either version 2 of the License, or (at
your option) any later version.
This software is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this software (file gpl-2.0.txt in the source
distribution); if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON A THEORY
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include
#include
#include
#include "libprimer3.h"
/* maximum number of variables allowed in the probability formula */
#define MAX_VARIABLES 100
/* flags for choosing between hard and soft masking */
#define HARD_MASKING 0
#define SOFT_MASKING 1
static void print_help (int exit_value);
void print_parameters (masker_parameters *mp);
const char *pr_programme_name = "primer3_masker";
int
main (int argc, const char *argv[])
{
unsigned int idx;
char *end;
int debug = 0;
/* sequence file name specified by the user, otherwise STDIN will be used */
const char *sequence_file_name = NULL;
const char *lists_file_name = NULL;
const char *kmer_lists_path = NULL;
/* data structure for all k-mer lists used for masking */
unsigned int nlists = 0;
unsigned int nlist_parameters = 0;
unsigned int npos = 0;
unsigned int list_pos[MAX_VARIABLES], list_components[MAX_VARIABLES];
masker_parameters mp = {};
parameters_builder pbuilder = {};
input_sequence *input_seq = NULL;
pr_append_str parse_err;
pr_append_str warnings;
init_pr_append_str (&parse_err);
init_pr_append_str (&warnings);
/* fill mp with default parameters */
mp.mdir = DEFAULT_MASKING_DIRECTION;
mp.failure_rate = DEFAULT_FAILURE_RATE;
mp.abs_cutoff = DEFAULT_ABS_CUTOFF;
mp.nucl_masked_in_5p_direction = DEFAULT_M5P;
mp.nucl_masked_in_3p_direction = DEFAULT_M3P;
mp.print_sequence = PRINT_SEQUENCE;
mp.do_soft_masking = HARD_MASKING;
mp.masking_char = DEFAULT_MASK_CHAR;
mp.list_prefix = DEFAULT_LIST_FILE_PREFIX;
kmer_lists_path = "../kmer_lists/";
if(argc < 2){
print_help (0);
}
/* parsing and checking the commandline arguments */
for (idx = 1; (int)idx < argc; idx++) {
if (!strcmp (argv[idx], "-h") || !strcmp (argv[idx], "--help") || !strcmp (argv[idx], "-?") || (argc < 2)) {
print_help (0);
} else if ((int)idx == argc - 1 && argv[idx][0] != '-') {
sequence_file_name = argv[idx];
FILE *file = fopen(sequence_file_name, "r");
if (file){
fclose(file);
} else {
print_help(1);
}
} else if (!strcmp (argv[idx], "-lf") || !strcmp (argv[idx], "--lists_file")) {
/* lists specified from the file */
if (!argv[idx + 1] || argv[idx + 1][0] == '-') {
pr_append_new_chunk_external (&warnings, "No lists file specified.");
idx += 1;
print_help(1);
}
lists_file_name = argv[idx + 1];
idx += 1;
} else if (!strcmp (argv[idx], "-l") || !strcmp (argv[idx], "--list")) {
/* lists specified from the commandline */
if (nlist_parameters == MAX_VARIABLES) {
pr_append_new_chunk_external (&parse_err, "Maximum number of list variables reached.");
print_help(1);
}
if (!argv[idx + 1]) {
pr_append_new_chunk_external (&warnings, "No list name specified with -l parameter!.");
print_help(1);
}
/* get the positions of list files */
list_pos[nlist_parameters] = idx;
while (argv[idx + 1]) {
if (argv[idx + 1][0] == '-') {
if (!argv[idx + 1][1]) break;
strtod (argv[idx + 1] + 1, &end);
if (*end != 0) break;
} else if (idx + 1 != list_pos[nlist_parameters] + 1 && idx + 1 != list_pos[nlist_parameters] + 4) {
strtod (argv[idx + 1], &end);
if (*end != 0) break;
} else if (idx + 1 == list_pos[nlist_parameters] + 4 && strcmp (argv[idx + 1], "sq")) {
break;
}
idx += 1;
}
list_components[nlist_parameters] = idx - list_pos[nlist_parameters];
nlist_parameters += 1;
npos += 1;
} else if (!strcmp (argv[idx], "-lp") || !strcmp (argv[idx], "--list_prefix")) {
/* lists specified by the prefix */
if (!argv[idx + 1] || argv[idx + 1][0] == '-') {
pr_append_new_chunk_external (&warnings, "No list prefix specified! Using the default value.");
idx += 1;
print_help(1);
}
mp.list_prefix = (char *)argv[idx + 1];
idx += 1;
} else if (!strcmp (argv[idx], "-lh") || !strcmp (argv[idx], "--kmer_lists_path")) {
/* kmer lists path */
if (!argv[idx + 1] || argv[idx + 1][0] == '-') {
pr_append_new_chunk_external (&warnings, "No list prefix specified! Using the default value.");
idx += 1;
print_help(1);
}
kmer_lists_path = (char *)argv[idx + 1];
idx += 1;
} else if (!strcmp (argv[idx], "-p") || !strcmp (argv[idx], "--probability_cutoff")) {
if (!argv[idx + 1]) {
pr_append_new_chunk_external (&warnings, "No cutoff value specified! Using the default value.");
idx += 1;
continue;
}
mp.failure_rate = strtod (argv[idx + 1], &end);
mp.abs_cutoff = 0;
if (*end != 0 || mp.failure_rate < 0 || mp.failure_rate > 1) {
pr_append_new_chunk_external (&parse_err, "Invalid cutoff value: ");
pr_append_external (&parse_err, argv[idx + 1]);
/*free(parse_err.data);*/
break;
}
idx += 1;
} else if (!strcmp (argv[idx], "-a") || !strcmp (argv[idx], "--absolute_value_cutoff")) {
if (!argv[idx + 1]) {
pr_append_new_chunk_external (&warnings, "No absolute cutoff value specified! Using the default value.");
idx += 1;
break;
}
mp.abs_cutoff = strtod (argv[idx + 1], &end);
mp.failure_rate = 0.0;
if (*end != 0 || mp.abs_cutoff < 0) {
pr_append_new_chunk_external (&parse_err, "Invalid absolute cutoff value: ");
pr_append_external (&parse_err, argv[idx + 1]);
break;
}
idx += 1;
} else if (!strcmp (argv[idx], "-m5") || !strcmp (argv[idx], "--mask_5p")) {
if (!argv[idx + 1]) {
pr_append_new_chunk_external (&warnings, "Number of nucleotides masked in 5' direction not specified! Using the default value.");
idx += 1;
continue;
}
mp.nucl_masked_in_5p_direction = strtod (argv[idx + 1], &end);
if (*end != 0) {
pr_append_new_chunk_external (&parse_err, "Invalid number of nucleotides masked in 5' direction: ");
pr_append_external (&parse_err, argv[idx + 1]);
print_help(1);
}
idx += 1;
} else if (!strcmp (argv[idx], "-m3") || !strcmp (argv[idx], "--mask_3p")) {
if (!argv[idx + 1]) {
pr_append_new_chunk_external (&warnings, "Number of nucleotides masked in 3' direction not specified! Using the default value.");
idx += 1;
continue;
}
mp.nucl_masked_in_3p_direction = strtod (argv[idx + 1], &end);
if (*end != 0) {
pr_append_new_chunk_external (&parse_err, "Invalid number of nucleotides masked in 3' direction: ");
pr_append_external (&parse_err, argv[idx + 1]);
print_help(1);
}
idx += 1;
} else if (!strcmp (argv[idx], "-c") || !strcmp (argv[idx], "--masking_char")) {
if (!argv[idx + 1 || argv[idx + 1][0] == '-']) {
pr_append_new_chunk_external (&warnings, "Character for masking not specified! Using the default value.");
idx += 1;
continue;
}
mp.masking_char = argv[idx + 1][0];
if (strlen(argv[idx + 1]) > 1 || mp.masking_char < 33 || mp.masking_char > 126) {
pr_append_new_chunk_external (&parse_err, "Invalid character for masking: ");
pr_append_external (&parse_err, argv[idx + 1]);
print_help(1);
}
idx += 1;
} else if (!strcmp (argv[idx], "-d") || !strcmp (argv[idx], "--masking_direction")) {
if (!argv[idx + 1] || argv[idx + 1][0] == '-') {
pr_append_new_chunk_external (&warnings, "Masking direction not specified! Masking both strands by default.");
} else if (!strcmp (argv[idx + 1], "both")) {
mp.mdir = both_on_same;
} else if (!strcmp (argv[idx + 1], "fwd")) {
mp.mdir = fwd;
} else if (!strcmp (argv[idx + 1], "rev")) {
mp.mdir = rev;
} else {
pr_append_new_chunk_external (&warnings, "Unknown masking direction: ");
pr_append_external (&warnings, argv[idx + 1]);
pr_append_external (&warnings, ". Masking both strands by default.");
}
idx += 1;
} else if (!strcmp (argv[idx], "-s") || !strcmp (argv[idx], "--soft_mask")) {
mp.do_soft_masking = SOFT_MASKING;
} else if (!strcmp (argv[idx], "-D")) {
debug += 1;
} else {
pr_append_new_chunk_external (&parse_err, "Unknown parameter: ");
pr_append_external (&parse_err, argv[idx]);
print_help(1);
}
}
/*FILE *file = fopen(sequence_file_name, "r");
if (file){
fclose(file);
} else {
print_help(1);
}
*/
input_seq = create_input_sequence_from_file_name (sequence_file_name, &parse_err);
if (parse_err.data != NULL) {
fprintf(stderr, "%s -> parsing commandline: ERROR: %s\n", pr_programme_name, parse_err.data);
exit(-1);
}
if (warnings.data != NULL) {
fprintf(stderr, "%s -> parsing commandline: WARNING: %s\n", pr_programme_name, warnings.data);
}
if (lists_file_name) {
/* if lists are given in a text file */
mp.fp = read_formula_parameters_from_file (lists_file_name, &nlist_parameters, &pbuilder, &mp.formula_intercept, &parse_err);
nlists = pbuilder.nfp;
}
if (npos != 0) {
/* if lists are given by commandline arguments (can be added to the ones given in a file) */
pbuilder.fp_array = mp.fp;
for (idx = 0; idx < npos; idx++) {
unsigned int pos = list_pos[idx] + 1;
char *values[4];
unsigned int nvalues = list_components[idx];
char *end;
memcpy (&values, &argv[pos], nvalues * sizeof(*argv));
if (nvalues == 1) {
double ic;
double neg = 1.0;
if (values[0][0] == '-') {
values[0] += 1;
neg = -1.0;
}
ic = strtod (values[0], &end);
if (*end == 0) {
mp.formula_intercept = ic * neg;
continue;
}
}
add_variable_to_formula_parameters (values, nvalues, &pbuilder, &parse_err);
}
nlists = pbuilder.nfp;
mp.fp = pbuilder.fp_array;
} else if (nlists == 0 && !lists_file_name) {
/* if there are no lists specified use the default formula */
mp.fp = create_default_formula_parameters (mp.list_prefix, kmer_lists_path, &parse_err);
mp.formula_intercept = DEFAULT_INTERCEPT;
nlists = DEFAULT_NLISTS;
nlist_parameters = DEFAULT_NLIST_PARAMETERS;
}
mp.nlists = nlists;
if (mp.abs_cutoff > 0 && nlist_parameters != 1) {
fprintf (stderr, "Error: Absolute value cutoff works with one list and one k-mer frequency parameter only. Currently you are using %u lists and %u parameters.\n", nlists, nlist_parameters);
print_help(1);
}
if (parse_err.data != NULL) {
fprintf(stderr, "%s -> building formula: ERROR: %s\n", pr_programme_name, parse_err.data);
delete_input_sequence (input_seq);
exit(-1);
}
if (debug > 0) print_parameters (&mp);
read_and_mask_sequence (input_seq, NULL, &mp, &parse_err, debug);
if (parse_err.data != NULL) {
fprintf(stderr, "%s -> masking sequence: ERROR: %s\n", pr_programme_name, parse_err.data);
delete_input_sequence (input_seq);
delete_formula_parameters (mp.fp, nlists);
exit(-1);
}
destroy_pr_append_str_data (&warnings);
destroy_pr_append_str_data (&parse_err);
delete_input_sequence (input_seq);
delete_formula_parameters (mp.fp, nlists);
free(pbuilder.used_lists);
if (debug > 0) fprintf (stderr, "Done!\n");
return 0;
}
void
print_parameters (masker_parameters *mp)
{
unsigned int i;
fprintf (stderr, "Current masker parameters:\n");
fprintf (stderr, " masking_direction = %s\n", mp->mdir == both_on_same ? "both" : (mp->mdir == fwd ? "fwd" : "rev"));
fprintf (stderr, " failure_rate = %f\n", mp->failure_rate);
fprintf (stderr, " abs_cutoff = %u\n", mp->abs_cutoff);
fprintf (stderr, " m5p = %u\n", mp->nucl_masked_in_5p_direction);
fprintf (stderr, " m3p = %u\n", mp->nucl_masked_in_3p_direction);
fprintf (stderr, " print_sequence = %d\n", mp->print_sequence);
fprintf (stderr, " do_soft_masking = %d\n", mp->do_soft_masking);
fprintf (stderr, " masking_char = %c\n", mp->masking_char);
fprintf (stderr, " nlists = %u\n", mp->nlists);
fprintf (stderr, " intercept = %f\n", mp->formula_intercept);
for (i = 0; i < mp->nlists; i++) {
fprintf (stderr, " LIST: %u\n", i);
formula_parameters *fp = mp->fp[i];
if (!fp) continue;
fprintf (stderr, " name = %s\n", fp->list_file_name);
fprintf (stderr, " oligo_length = %u\n", fp->oligo_length);
fprintf (stderr, " words_in_list = %llu\n", fp->words_in_list);
fprintf (stderr, " mm0 %f mm1 %f mm2 %f mm0_2 %f mm1_2 %f mm2_2 %f\n", fp->mm0, fp->mm1, fp->mm2, fp->mm0_2, fp->mm1_2, fp->mm2_2);
}
return;
}
static void
print_help (int exit_value)
{
fprintf (stdout, "Usage: ./primer3_masker [OPTIONS] \n");
fprintf (stdout, "Options:\n");
fprintf (stdout, " -h, --help - print this usage screen and exit\n\n");
fprintf (stdout, " -p, --probability_cutoff - masking cutoff [0, 1] (default: >=0.1)\n");
fprintf (stdout, " -lh, --kmer_lists_path - path to the kmer list files (default: ../kmer_lists/)\n");
fprintf (stdout, " -lp, --list_prefix - prefix of the k-mer lists to use with default model (default: homo_sapiens)\n\n");
fprintf (stdout, " -a, --absolute_value_cutoff - masking cutoff based on k-mer count; requires a single list name, defined with -l\n");
fprintf (stdout, " -l, --list - define a single k-mer list for masking with absolute cutoff option -a\n\n");
fprintf (stdout, " -m5, --mask_5p - nucleotides to mask in 5' direction (default: 1)\n");
fprintf (stdout, " -m3, --mask_3p - nucleotides to mask in 3' direction (default: 0)\n");
fprintf (stdout, " -c, --masking_char - character used for masking (default: N)\n");
fprintf (stdout, " -s, --soft_mask - use soft masking (default: false)\n");
fprintf (stdout, " -d, --masking_direction - a strand to mask (fwd, rev, both) (default: both)\n\n");
exit (exit_value);
}
primer3-py-2.3.1/primer3/src/libprimer3/ntdpal_main.c 0000664 0000000 0000000 00000017256 15247271707 0022425 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 1996,1997,1998,1999,2000,2001,2004,2006,2007,2008
Whitehead Institute for Biomedical Research, Steve Rozen
(http://purl.com/STEVEROZEN/), Andreas Untergasser and Helen Skaletsky
All rights reserved.
This file is part of primer3 software suite.
This software suite is is free software;
you can redistribute it and/or modify it under the terms
of the GNU General Public License as published by the Free
Software Foundation; either version 2 of the License, or (at
your option) any later version.
This software is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this software (file gpl-2.0.txt in the source
distribution); if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "dpal.h"
#include
#include
#include
int
main(int argc, const char**argv)
{
dpal_args a;
dpal_results r;
const unsigned char *s1, *s2;
int tmp_ret;
int i;
int print_align_end = 0; /*
* Print align_end_1 and align_end_2 from
* dpal_results.
*/
int use_ambiguity_codes = 0;
int use_h_matrix = 0;
char mode;
dpal_mode dp_mode = DPM_GENERAL;
int dpal_debug = 0;
int dpal_only = 0;
char *endptr;
const char *msg =
"\nUsage: %s [-g ] [-l ] [-m ]\n"
" [-f2] [-p] [-s] [-e] "
"\n\nwhere\n\n"
" and are (positive) floats (.01 precision)\n"
" specifying penalties for creating or lengthening a gap\n"
" respectively (the penalties are subtracted from the\n"
" output score).\n\n"
"-a causes the scoring matrix to be modified by dpal_set_ambiguity_codes.\n\n"
"-e causes the end postion of the alignment in both sequences to\n"
" be printed. Do not confuse with the 'e' .\n\n"
"-f1, -f2, f3\n"
" force specific implementations.\n"
" -f2 forces use an implementation that might provide more\n"
" informative error messages, possibly at the expense\n"
" of some speed.\n\n"
"-h use a different scoring matrix: G and C matches = 3, A and T = 2,\n"
" and mismatches = -0.5.\n"
" (The default scoring matrix assigns 1 to a match,\n"
" and -1 to a mismatch.)\n\n"
"-p causes the alignment to be displayed on stderr.\n\n"
"-s causes _only_ the score to printed.\n\n"
" is the maximum allowed gap (default is 3).\n\n"
" and are the sequences to be aligned.\n\n"
" is one of g, G, l, or L specifying a global,\n"
" global end-anchored, local, or local end-achored\n"
" alignment respectively. For backward compatibility\n"
" e is equivalent to G.\n\n";
if (argc < 4) {
tmp_ret = fprintf(stderr, msg, argv[0]);
exit(-1);
return tmp_ret;
}
dpal_set_default_nt_args(&a);
for (i=1; i < argc; ++i) {
if (!strncmp("-p", argv[i], 2)) {
dpal_debug = 1;
} else if (!strncmp("-l", argv[i], 2)) {
if (i+1 >= argc) {
/* Missing value */
fprintf(stderr, msg, argv[0]);
exit(-1);
}
a.gapl = (int) (strtod(argv[i+1],(char **)NULL) * -100);
i++;
} else if (!strncmp("-e", argv[i], 2)) {
print_align_end = 1;
} else if (!strncmp("-a", argv[i], 2)) {
use_ambiguity_codes = 1;
} else if (!strncmp("-h", argv[i], 2)) {
use_h_matrix = 1;
} else if (!strncmp("-g", argv[i], 2)) {
if (i+1 >= argc) {
/* Missing value */
fprintf(stderr, msg, argv[0]);
exit(-1);
}
a.gap = (int) (strtod(argv[i+1],(char **)NULL) * -100);
i++;
} else if (!strncmp("-m", argv[i], 2)) {
if (i+1 >= argc) {
/* Missing value */
fprintf(stderr, msg, argv[0]);
exit(-1);
}
a.max_gap = strtol(argv[i+1], &endptr, 10);
if ('\0' != *endptr) {
fprintf(stderr, msg, argv[0]);
exit(-1);
}
i++;
} else if (!strncmp("-s", argv[i], 2)) {
dpal_only = 1;
} else if (!strncmp("-e", argv[i], 2)) {
print_align_end = 1;
} else if (!strncmp("-f1", argv[i], 3)) {
a.force_generic = 1;
} else if (!strncmp("-f2", argv[i], 3)) {
a.force_long_generic = 1;
} else if (!strncmp("-f3", argv[i], 3)) {
a.force_long_maxgap1 = 1;
} else if (!strncmp("-", argv[i], 1)) {
/* Unknown option. */
fprintf(stderr, msg, argv[0]);
exit(-1);
} else
break; /* all args processed. go on to sequences. */
}
if (use_h_matrix) dpal_set_h_nt_matrix(&a);
if (use_ambiguity_codes) dpal_set_ambiguity_code_matrix(&a);
if (dpal_debug && dpal_only) {
fprintf(stderr, msg, argv[0]);
exit(-1);
} else {
if (dpal_debug) {
dp_mode = DPM_DEBUG;
} else if (dpal_only) {
dp_mode = DPM_FAST;
} else {
dp_mode = DPM_GENERAL;
}
}
a.flag = -1;
if ((argc - i) != 3){
/* Not enough remaining arguments. */
fprintf(stderr, msg, argv[0]);
exit(-1);
}
s1 = (unsigned char *) argv[i];
s2 = (unsigned char *) argv[i+1];
mode = *argv[i+2];
if ('l' == mode)
a.flag = DPAL_LOCAL;
else if ('e' == mode || 'G' == mode)
a.flag = DPAL_GLOBAL_END;
else if ('g' == mode)
a.flag = DPAL_GLOBAL;
else if ('L' == mode)
a.flag = DPAL_LOCAL_END;
else {
fprintf(stderr, msg, argv[0]);
exit(-1);
}
if(print_align_end == 1) a.force_long_generic = 1;
dpal(s1, s2, &a, dp_mode, &r);
if (r.score == DPAL_ERROR_SCORE) {
tmp_ret = fprintf(stderr, "Error: %s\n", r.msg);
exit(-1);
return tmp_ret;
}
if (dp_mode == DPM_FAST) {
printf("%.2f\n", 0.01 * r.score);
if (print_align_end) {
if(r.align_end_1 >= 0) printf("align_end_1=%d ",r.align_end_1);
if(r.align_end_2 >= 0) printf("align_end_2=%d\n ",r.align_end_2);
}
} else {
printf("|%s| |%s| %c ", s1, s2, mode);
printf("score=%.2f len=%d ", (0.01 * r.score), r.path_length);
if (print_align_end) {
if(r.align_end_1 >= 0) printf("align_end_1=%d ",r.align_end_1);
if(r.align_end_2 >= 0) printf("align_end_2=%d ",r.align_end_2);
}
for (i=0; i