Tagged with #nct
3 documentation articles | 0 announcements | 6 forum discussions

Created 2013-06-26 19:01:08 | Updated 2013-06-26 19:05:10 | Tags: developer parallelism multithreading advanced nct nt
Comments (0)

This document provides an overview of what are the steps required to make a walker multi-threadable using the -nct and the -nt arguments, which make use of the NanoSchedulable and TreeReducible interfaces, respectively.

NanoSchedulable / -nct

Providing -nct support requires that you certify that your walker's map() method is thread-safe -- eg., if any data structures are shared across map() calls, access to these must be properly synchronized. Once your map() method is thread-safe, you can implement the NanoSchedulable interface, an empty interface with no methods that just marks your walker as having a map() method that's safe to parallelize:

 * Root parallelism interface.  Walkers that implement this
 * declare that their map function is thread-safe and so multiple
 * map calls can be run in parallel in the same JVM instance.
public interface NanoSchedulable {

TreeReducible / -nt

Providing -nt support requires that both map() and reduce() be thread-safe, and you also need to implement the TreeReducible interface. Implementing TreeReducible requires you to write a treeReduce() method that tells the engine how to combine the results of multiple reduce() calls:

public interface TreeReducible<ReduceType> {
     * A composite, 'reduce of reduces' function.
     * @param lhs 'left-most' portion of data in the composite reduce.
     * @param rhs 'right-most' portion of data in the composite reduce.
     * @return The composite reduce type.
    ReduceType treeReduce(ReduceType lhs, ReduceType rhs);

This method differs from reduce() in that while reduce() adds the result of a single map() call onto a running total, treeReduce() takes the aggregated results from multiple map/reduce tasks that have been run in parallel and combines them. So, lhs and rhs might each represent the final result from several hundred map/reduce calls.

Example treeReduce() implementation from the UnifiedGenotyper:

public UGStatistics treeReduce(UGStatistics lhs, UGStatistics rhs) {
    lhs.nBasesCallable += rhs.nBasesCallable;
    lhs.nBasesCalledConfidently += rhs.nBasesCalledConfidently;
    lhs.nBasesVisited += rhs.nBasesVisited;
    lhs.nCallsMade += rhs.nCallsMade;
    return lhs;

Created 2012-12-18 21:35:34 | Updated 2013-01-26 05:10:36 | Tags: official intro queue parallelism performance scatter-gather multithreading nct nt
Comments (20)

This document explains the concepts involved and how they are applied within the GATK (and Queue where applicable). For specific configuration recommendations, see the companion document on parallelizing GATK tools.

1. Introducing the concept of parallelism

Parallelism is a way to make a program finish faster by performing several operations in parallel, rather than sequentially (i.e. waiting for each operation to finish before starting the next one).

Imagine you need to cook rice for sixty-four people, but your rice cooker can only make enough rice for four people at a time. If you have to cook all the batches of rice sequentially, it's going to take all night. But if you have eight rice cookers that you can use in parallel, you can finish up to eight times faster.

This is a very simple idea but it has a key requirement: you have to be able to break down the job into smaller tasks that can be done independently. It's easy enough to divide portions of rice because rice itself is a collection of discrete units. In contrast, let's look at a case where you can't make that kind of division: it takes one pregnant woman nine months to grow a baby, but you can't do it in one month by having nine women share the work.

The good news is that most GATK runs are more like rice than like babies. Because GATK tools are built to use the Map/Reduce method (see doc for details), most GATK runs essentially consist of a series of many small independent operations that can be parallelized.

A quick warning about tradeoffs

Parallelism is a great way to speed up processing on large amounts of data, but it has "overhead" costs. Without getting too technical at this point, let's just say that parallelized jobs need to be managed, you have to set aside memory for them, regulate file access, collect results and so on. So it's important to balance the costs against the benefits, and avoid dividing the overall work into too many small jobs.

Going back to the introductory example, you wouldn't want to use a million tiny rice cookers that each boil a single grain of rice. They would take way too much space on your countertop, and the time it would take to distribute each grain then collect it when it's cooked would negate any benefits from parallelizing in the first place.

Parallel computing in practice (sort of)

OK, parallelism sounds great (despite the tradeoffs caveat), but how do we get from cooking rice to executing programs? What actually happens in the computer?

Consider that when you run a program like the GATK, you're just telling the computer to execute a set of instructions.

Let's say we have a text file and we want to count the number of lines in it. The set of instructions to do this can be as simple as:

  • open the file, count the number of lines in the file, tell us the number, close the file

Note that tell us the number can mean writing it to the console, or storing it somewhere for use later on.

Now let's say we want to know the number of words on each line. The set of instructions would be:

  • open the file, read the first line, count the number of words, tell us the number, read the second line, count the number of words, tell us the number, read the third line, count the number of words, tell us the number

And so on until we've read all the lines, and finally we can close the file. It's pretty straightforward, but if our file has a lot of lines, it will take a long time, and it will probably not use all the computing power we have available.

So to parallelize this program and save time, we just cut up this set of instructions into separate subsets like this:

  • open the file, index the lines

  • read the first line, count the number of words, tell us the number

  • read the second line, count the number of words, tell us the number
  • read the third line, count the number of words, tell us the number
  • [repeat for all lines]

  • collect final results and close the file

Here, the read the Nth line steps can be performed in parallel, because they are all independent operations.

You'll notice that we added a step, index the lines. That's a little bit of peliminary work that allows us to perform the read the Nth line steps in parallel (or in any order we want) because it tells us how many lines there are and where to find each one within the file. It makes the whole process much more efficient. As you may know, the GATK requires index files for the main data files (reference, BAMs and VCFs); the reason is essentially to have that indexing step already done.

Anyway, that's the general principle: you transform your linear set of instructions into several subsets of instructions. There's usually one subset that has to be run first and one that has to be run last, but all the subsets in the middle can be run at the same time (in parallel) or in whatever order you want.

2. Parallelizing the GATK

There are three different modes of parallelism offered by the GATK, and to really understand the difference you first need to understand what are the different levels of computing that are involved.

A quick word about levels of computing

By levels of computing, we mean the computing units in terms of hardware: the core, the machine (or CPU) and the cluster.

  • Core: the level below the machine. On your laptop or desktop, the CPU (central processing unit, or processor) contains one or more cores. If you have a recent machine, your CPU probably has at least two cores, and is therefore called dual-core. If it has four, it's a quad-core, and so on. High-end consumer machines like the latest Mac Pro have up to twelve-core CPUs (which should be called dodeca-core if we follow the Latin terminology) but the CPUs on some professional-grade machines can have tens or hundreds of cores.

  • Machine: the middle of the scale. For most of us, the machine is the laptop or desktop computer. Really we should refer to the CPU specifically, since that's the relevant part that does the processing, but the most common usage is to say machine. Except if the machine is part of a cluster, in which case it's called a node.

  • Cluster: the level above the machine. This is a high-performance computing structure made of a bunch of machines (usually called nodes) networked together. If you have access to a cluster, chances are it either belongs to your institution, or your company is renting time on it. A cluster can also be called a server farm or a load-sharing facility.

Parallelism can be applied at all three of these levels, but in different ways of course, and under different names. Parallelism takes the name of multi-threading at the core and machine levels, and scatter-gather at the cluster level.


In computing, a thread of execution is a set of instructions that the program issues to the processor to get work done. In single-threading mode, a program only sends a single thread at a time to the processor and waits for it to be finished before sending another one. In multi-threading mode, the program may send several threads to the processor at the same time.

Not making sense? Let's go back to our earlier example, in which we wanted to count the number of words in each line of our text document. Hopefully it is clear that the first version of our little program (one long set of sequential instructions) is what you would run in single-threaded mode. And the second version (several subsets of instructions) is what you would run in multi-threaded mode, with each subset forming a separate thread. You would send out the first thread, which performs the preliminary work; then once it's done you would send the "middle" threads, which can be run in parallel; then finally once they're all done you would send out the final thread to clean up and collect final results.

If you're still having a hard time visualizing what the different threads are like, just imagine that you're doing cross-stitching. If you're a regular human, you're working with just one hand. You're pulling a needle and thread (a single thread!) through the canvas, making one stitch after another, one row after another. Now try to imagine an octopus doing cross-stitching. He can make several rows of stitches at the same time using a different needle and thread for each. Multi-threading in computers is surprisingly similar to that.

Hey, if you have a better example, let us know in the forum and we'll use that instead.

Alright, now that you understand the idea of multithreading, let's get practical: how do we do get the GATK to use multi-threading?

There are two options for multi-threading with the GATK, controlled by the arguments -nt and -nct, respectively. They can be combined, since they act at different levels of computing:

  • -nt / --num_threads controls the number of data threads sent to the processor (acting at the machine level)

  • -nct / --num_cpu_threads_per_data_thread controls the number of CPU threads allocated to each data thread (acting at the core level).

Not all GATK tools can use these options due to the nature of the analyses that they perform and how they traverse the data. Even in the case of tools that are used sequentially to perform a multi-step process, the individual tools may not support the same options. For example, at time of writing (Dec. 2012), of the tools involved in local realignment around indels, RealignerTargetCreator supports -nt but not -nct, while IndelRealigner does not support either of these options.

In addition, there are some important technical details that affect how these options can be used with optimal results. Those are explained along with specific recommendations for the main GATK tools in a companion document on parallelizing the GATK.


If you Google it, you'll find that the term scatter-gather can refer to a lot of different things, including strategies to get the best price quotes from online vendors, methods to control memory allocation and… an indie-rock band. What all of those things have in common (except possibly the band) is that they involve breaking up a task into smaller, parallelized tasks (scattering) then collecting and integrating the results (gathering). That should sound really familiar to you by now, since it's the general principle of parallel computing.

So yes, "scatter-gather" is really just another way to say we're parallelizing things. OK, but how is it different from multithreading, and why do we need yet another name?

As you know by now, multithreading specifically refers to what happens internally when the program (in our case, the GATK) sends several sets of instructions to the processor to achieve the instructions that you originally gave it in a single command-line. In contrast, the scatter-gather strategy as used by the GATK involves a separate program, called Queue, which generates separate GATK jobs (each with its own command-line) to achieve the instructions given in a so-called Qscript (i.e. a script written for Queue in a programming language called Scala).

At the simplest level, the Qscript can involve a single GATK tool*. In that case Queue will create separate GATK commands that will each run that tool on a portion of the input data (= the scatter step). The results of each run will be stored in temporary files. Then once all the runs are done, Queue will collate all the results into the final output files, as if the tool had been run as a single command (= the gather step).

Note that Queue has additional capabilities, such as managing the use of multiple GATK tools in a dependency-aware manner to run complex pipelines, but that is outside the scope of this article. To learn more about pipelining the GATK with Queue, please see the Queue documentation.

Compare and combine

So you see, scatter-gather is a very different process from multi-threading because the parallelization happens outside of the program itself. The big advantage is that this opens up the upper level of computing: the cluster level. Remember, the GATK program is limited to dispatching threads to the processor of the machine on which it is run – it cannot by itself send threads to a different machine. But Queue can dispatch scattered GATK jobs to different machines in a computing cluster by interfacing with your cluster's job management software.

That being said, multithreading has the great advantage that cores and machines all have access to shared machine memory with very high bandwidth capacity. In contrast, the multiple machines on a network used for scatter-gather are fundamentally limited by network costs.

The good news is that you can combine scatter-gather and multithreading: use Queue to scatter GATK jobs to different nodes on your cluster, then use the GATK's internal multithreading capabilities to parallelize the jobs running on each node.

Going back to the rice-cooking example, it's as if instead of cooking the rice yourself, you hired a catering company to do it for you. The company assigns the work to several people, who each have their own cooking station with multiple rice cookers. Now you can feed a lot more people in the same amount of time! And you don't even have to clean the dishes.

Created 2012-12-14 21:59:43 | Updated 2013-04-19 17:04:34 | Tags: official queue parallelism performance scatter-gather multithreading nct nt
Comments (13)

This document provides technical details and recommendations on how the parallelism options offered by the GATK can be used to yield optimal performance results.


As explained in the primer on parallelism for the GATK, there are two main kinds of parallelism that can be applied to the GATK: multi-threading and scatter-gather (using Queue).

Multi-threading options

There are two options for multi-threading with the GATK, controlled by the arguments -nt and -nct, respectively, which can be combined:

  • -nt / --num_threads controls the number of data threads sent to the processor
  • -nct / --num_cpu_threads_per_data_thread controls the number of CPU threads allocated to each data thread

For more information on how these multi-threading options work, please read the primer on parallelism for the GATK.

Memory considerations for multi-threading

Each data thread needs to be given the full amount of memory you’d normally give a single run. So if you’re running a tool that normally requires 2 Gb of memory to run, if you use -nt 4, the multithreaded run will use 8 Gb of memory. In contrast, CPU threads will share the memory allocated to their “mother” data thread, so you don’t need to worry about allocating memory based on the number of CPU threads you use.

Additional consideration when using -nct with versions 2.2 and 2.3

Because of the way the -nct option was originally implemented, in versions 2.2 and 2.3, there is one CPU thread that is reserved by the system to “manage” the rest. So if you use -nct, you’ll only really start seeing a speedup with -nct 3 (which yields two effective "working" threads) and above. This limitation has been resolved in the implementation that will be available in versions 2.4 and up.


For more details on scatter-gather, see the primer on parallelism for the GATK and the Queue documentation.

Applicability of parallelism to the major GATK tools

Please note that not all tools support all parallelization modes. The parallelization modes that are available for each tool depend partly on the type of traversal that the tool uses to walk through the data, and partly on the nature of the analyses it performs.

Tool Full name Type of traversal NT NCT SG
RTC RealignerTargetCreator RodWalker + - -
IR IndelRealigner ReadWalker - - +
BR BaseRecalibrator LocusWalker - + +
PR PrintReads ReadWalker - + -
RR ReduceReads ReadWalker - - +
UG UnifiedGenotyper LocusWalker + + +

Recommended configurations

The table below summarizes configurations that we typically use for our own projects (one per tool, except we give three alternate possibilities for the UnifiedGenotyper). The different values allocated for each tool reflect not only the technical capabilities of these tools (which options are supported), but also our empirical observations of what provides the best tradeoffs between performance gains and commitment of resources. Please note however that this is meant only as a guide, and that we cannot give you any guarantee that these configurations are the best for your own setup. You will probably have to experiment with the settings to find the configuration that is right for you.

Available modes NT SG NCT,SG NCT SG NT,NCT,SG
Cluster nodes 1 4 4 1 4 4 / 4 / 4
CPU threads (-nct) 1 1 8 4-8 1 3 / 6 / 24
Data threads (-nt) 24 1 1 1 1 8 / 4 / 1
Memory (Gb) 48 4 4 4 4 32 / 16 / 4

Where NT is data multithreading, NCT is CPU multithreading and SG is scatter-gather using Queue. For more details on scatter-gather, see the primer on parallelism for the GATK and the Queue documentation.

No posts found with the requested search criteria.

Created 2015-10-29 03:04:43 | Updated 2015-10-29 03:05:33 | Tags: haplotypecaller nct missing-variants
Comments (5)

Hi GATK team,

First I'd like to thank you guys for the tools that you're making available for the community!

The problem is that I have run my sample using Haplotype Caller and I faced some missing variants when I ran the HaplotypeCaller running with nct.

How I figured out ?

2) When I ran with the command (with nct deactivated):

java -Xmx10g -jar  GenomeAnalysisTK.jar -R ucsc.hg19.fasta   -I 165019-0-LAOM-N10_26_001_L001_1.realigned.recal.bam  --dbsnp dbsnp_138.hg19.vcf    -T HaplotypeCaller -stand_emit_conf 30.0  -stand_call_conf 30.0  -dcov 5000 --genotyping_mode DISCOVERY -A FisherStrand -A AlleleBalance -A BaseCounts -A StrandOddsRatio -A StrandBiasBySample  --max_alternate_alleles 3 -o .165019-0-LAOM-N10_26_001_L001_1.realigned.recal.gatk.high.vcf -L NUTRI.list

chr12 48239835 rs1544410 C T 6129.77 . AC=1;AF=0.500;AN=2;BaseQRankSum=11.887;DB;DP=509;FS=0.000;MLEAC=1;MLEAF=0.500;MQ=60.00;MQ0=0;MQRankSu m=1.141;QD=12.04;ReadPosRankSum=0.418;SOR=0.640 GT:AD:GQ:PL:SB 0/1:261,247:99:6158,0,6273:261,0,247,0

1) When I ran with the command below (with nct activated) :

java -Xmx10g -jar  GenomeAnalysisTK.jar -R ucsc.hg19.fasta  -nct 8  -I 165019-0-LAOM-N10_26_001_L001_1.realigned.recal.bam  --dbsnp dbsnp_138.hg19.vcf    -T HaplotypeCaller -stand_emit_conf 30.0  -stand_call_conf 30.0  -dcov 5000 --genotyping_mode DISCOVERY -A FisherStrand -A AlleleBalance -A BaseCounts -A StrandOddsRatio -A StrandBiasBySample  --max_alternate_alleles 3 -o .165019-0-LAOM-N10_26_001_L001_1.realigned.recal.gatk.high.vcf -L NUTRI.list

The variant above is missing from my vcf (it's not called).

Checked the flags: DP = 509 (good depth); QD 12.04 > 2.0;

I have ran with the bamout option to see the variant with HaplotypeCaller and it shows the variant as you can see at the figure below.

This is the original bam as INPUT at my variant caller

My HaplotypeCaller is running at version 3.3.

PS: I have seen some threads at the forum about missing variants running with nct, is is correct?

Created 2015-09-11 14:17:08 | Updated 2015-09-11 14:17:57 | Tags: printreads error nct
Comments (2)

Hi there GATK team,

Below is a error rapport from the PrintReads unit of the gatk platform. In short a nct error because the reproducibility is not good. But when planned this might get some clues about the wrong threads because this happens at the end of the run (==>> gatk magic) and breaks my workflow. But this one is more peculiar than haplotypecaller nct bugs and might give clues about debugging.

``` java -Xmx4g -Djava.io.tmpdir=/path/to/baseQualityScoreRecalibration/ -jar /path/to/GenomeAnalysisTK.jar -T PrintReads -R /path/to/human_g1k_v37.fasta -I /path/to/S1.bam -o /path/to/baseQualityScoreRecalibration/S1.bam -BQSR /path/to/baseQualityScoreRecalibration/S1.before.grp -nct 8 INFO 14:40:22,898 HelpFormatter - -------------------------------------------------------------------------------- INFO 14:40:22,901 HelpFormatter - The Genome Analysis Toolkit (GATK) v3.3-0-g37228af, Compiled 2014/10/24 01:07:22 INFO 14:40:22,901 HelpFormatter - Copyright (c) 2010 The Broad Institute INFO 14:40:22,902 HelpFormatter - For support and documentation go to http://www.broadinstitute.org/gatk INFO 14:40:22,908 HelpFormatter - Program Args: -T PrintReads -R /path/to/human_g1k_v37.fasta -I /path/to/S1.bam -o /path/to/baseQualityScoreRecalibration/S1.bam -BQSR /path/to/baseQualityScoreRecalibration/S1.before.grp -nct 8 INFO 14:40:22,912 HelpFormatter - Executing as mterpstra@targetgcc04-mgmt on Linux 3.0.101-0.7.17-default amd64; Java HotSpot(TM) 64-Bit Server VM 1.7.0_25-b15. INFO 14:40:22,913 HelpFormatter - Date/Time: 2015/09/10 14:40:22 INFO 14:40:22,913 HelpFormatter - -------------------------------------------------------------------------------- INFO 14:40:22,913 HelpFormatter - -------------------------------------------------------------------------------- INFO 14:40:23,135 GenomeAnalysisEngine - Strictness is SILENT INFO 14:40:24,249 ContextCovariate - Context sizes: base substitution model 2, indel substitution model 3 INFO 14:40:24,354 GenomeAnalysisEngine - Downsampling Settings: No downsampling INFO 14:40:24,366 SAMDataSource$SAMReaders - Initializing SAMRecords in serial INFO 14:40:24,973 SAMDataSource$SAMReaders - Done initializing BAM readers: total time 0.61 INFO 14:40:25,151 MicroScheduler - Running the GATK in parallel mode with 8 total threads, 8 CPU thread(s) for each of 1 data thread(s), of 48 processors available on this machine INFO 14:40:25,239 GenomeAnalysisEngine - Preparing for traversal over 1 BAM files INFO 14:40:25,247 GenomeAnalysisEngine - Done preparing for traversal INFO 14:40:25,247 ProgressMeter - [INITIALIZATION COMPLETE; STARTING PROCESSING] INFO 14:40:25,248 ProgressMeter - | processed | time | per 1M | | total | remaining INFO 14:40:25,248 ProgressMeter - Location | reads | elapsed | reads | completed | runtime | runtime INFO 14:40:25,802 ReadShardBalancer$1 - Loading BAM index data INFO 14:40:25,803 ReadShardBalancer$1 - Done loading BAM index data INFO 14:40:53,559 GATKRunReport - Uploaded run statistics report to AWS S3

ERROR ------------------------------------------------------------------------------------------
ERROR A USER ERROR has occurred (version 3.3-0-g37228af):
ERROR This means that one or more arguments or inputs in your command are incorrect.
ERROR The error message below tells you what is the problem.
ERROR If the problem is an invalid argument, please check the online documentation guide
ERROR (or rerun your command with --help) to view allowable command-line arguments for this tool.
ERROR Visit our website and forum for extensive documentation and answers to
ERROR commonly asked questions http://www.broadinstitute.org/gatk
ERROR Please do NOT post this error to the GATK forum unless you have really tried to fix it yourself.
ERROR MESSAGE: The platform (illumina) associated with read group GATKSAMReadGroupRecord @RG:4039 is not a recognized platform. Allowable options are ILLUMINA,SLX,SOLEXA,SOLID,454,COMPLETE,PACBIO,IONTORRENT,CAPILLARY,HELICOS,UNKNOWN


This is an shortend version of the readgroup lines (generated with addorreplace), selection:

@RG ID:4038 PL:illumina PU:miseq_1 LB:S1_GCACAC DT:2015-09-10T04:00:00+0200 SM:S1 @RG ID:4039 PL:illumina PU:miseq_1 LB:S1_TGAACC DT:2015-09-10T04:00:00+0200 SM:S1 @RG ID:404 PL:illumina PU:miseq_1 LB:S1_TCATAG DT:2015-09-10T04:00:00+0200 SM:S1 @RG ID:4040 PL:illumina PU:miseq_1 LB:S1_CGCAGC DT:2015-09-10T04:00:00+0200 SM:S1 @RG ID:4041 PL:illumina PU:miseq_1 LB:S1_CGAAAC DT:2015-09-10T04:00:00+0200 SM:S1 @RG ID:4042 PL:illumina PU:miseq_1 LB:S1_TCATAC DT:2015-09-10T04:00:00+0200 SM:S1

Created 2015-09-11 01:42:10 | Updated 2015-09-11 01:42:53 | Tags: nct
Comments (1)

Hi, I'm SunHye. I wonder what is maximum value about -nct. My lab's server has 3 node, and each node has 8 cpu consisting of 64 core.

Maximum value about -nct 8 or 64? Please reply this question. Thanks !

Created 2014-07-20 04:19:36 | Updated 2014-07-20 04:26:30 | Tags: unifiedgenotyper parallelism nct nt multiple-vcf
Comments (1)


It seems that while non-parallel UnifiedGenotyper (SNP mode) always generates the same output vcf, parallel version (either -nt and/or -nct >1) of UnifiedGenotyper generates not exactly the same vcf files for each run. For example, below is the GenotypeConcordance output of two runs with same input file (chr 21) and same parameters (-nt4 -nct4):

Sample Eval_Genotype Comp_Genotype Count

So I am wondering if there is a way to get the same output vcf. Or do I miss something here? Thanks.

Created 2014-03-01 00:11:04 | Updated | Tags: haplotypecaller parallelism nct
Comments (2)

Hi! I am trying to see if I can speed up the HaplotypeCaller tool using the -nct flag. The GATK correctly identifies that my machine has 16 processors, and I specified that the HaplotypeCaller uses 16 threads, i.e. -nct 16. However processing the same file roughly takes the same amount of time (3600sec approx). I tried it also using -nct 8, and -nct 4. None of these options seems to help the process finish faster.

Were there any suggestions or ways I could achieve some appreciable gains? Thank you for any insight anyhow.

Created 2012-11-21 09:24:01 | Updated | Tags: parallelism nct
Comments (5)


I'm trying to implement a workflow with GATK for the first time and I'm getting caught out by the -nct/-num_threads options not being compatible with all walkers, erroring and then killing the process.

Can I suggest that if the flags are not implemented/supported by a walker that the option is ignored. The docs don't clarify which walkers work and which don't so I need to test each one. It would be much easier if simply a warning message were given.

Also, I don't fully understand the difference between -nct/-num_threads. Can someone explain it, please? TIA