source: trunk/grails-app/domain/nl/tno/metagenomics/AssaySample.groovy @ 20

Last change on this file since 20 was 20, checked in by robert@…, 9 years ago

Solved bug in moving data to trash

File size: 5.9 KB
Line 
1package nl.tno.metagenomics
2
3/**
4 * Represents a samples that is used in an assay.
5 *
6 * @author Robert Horlings (robert@isdat.nl)
7 *
8 */
9class AssaySample {
10        // To be computed in run time
11        private long _numSequences = -1;
12        private float _averageQuality = -1.0;
13        private long _numQualScores = -1;
14
15        Integer numUniqueSequences      // Number of unique sequences / OTUs. Is only available after preprocessing
16
17        String oligoNumber              // Oligonumber used to identify the sample
18        String tagSequence              // Tag originally used to identify the sample
19        String tagName                  // Tag name
20
21        static belongsTo  = [ assay: Assay, sample: Sample, run: Run ]
22        static hasMany    = [ sequenceData: SequenceData ]
23
24        static constraints = {
25                numUniqueSequences(nullable: true)
26                oligoNumber(nullable: true)
27               
28                /*
29                , validator: { value, obj, errors ->
30                        // When one oligoNumber is used in different assaysamples,
31                        // they must also have the same tagSequences and tagNames
32                       
33                        // Check whether this oligoNumber exists in the database
34                        def otherAssaySamples = AssaySample.findAllByOligoNumber( value )
35                        if( !otherAssaySamples || otherAssaySamples.size() == 0 ) {
36                                return true;
37                        }
38                       
39                        // Loop through the other assaysamples with this oligonumber
40                        otherAssaySamples.each { otherAS ->
41                                // Only check other objects, don't compare with itself (because that
42                                // way it wouldn't be possible anymore to edit an object)
43                                if( otherAS.id != obj.id ) {
44                                        if( otherAS.tagSequence != obj.tagSequence || otherAS.tagName != obj.tagName ) {
45                                                return false;
46                                        }
47                                }
48                        }
49                       
50                        return true
51                }
52                 */
53                tagSequence(nullable: true)
54                tagName(nullable:true)
55                run(nullable: true);
56        }
57
58        static mapping = {
59                columns {
60                        numSequences index:'numsequences_idx'
61                }
62                sequenceData cascade: "all-delete-orphan"
63        }
64
65        /**
66         * Returns the number of files in the system, belonging to this
67         * assay-sample combination.
68         *
69         * @return
70         */
71        public int numFiles() {
72                if( !sequenceData )
73                        return 0
74
75                int numFiles = 0;
76                sequenceData.each { numFiles += it.numFiles() }
77
78                return numFiles;
79        }
80
81        /**
82         * Returns the number of sequence files in the system, belonging to this
83         * assay-sample combination.
84         *
85         * @return
86         */
87        public int numSequenceFiles() {
88                if( !sequenceData )
89                        return 0
90
91                int numFiles = 0;
92                sequenceData.each {
93                        if( it.sequenceFile )
94                                numFiles++
95                }
96
97                return numFiles;
98        }
99       
100        /**
101         * Returns the number of quality files in the system, belonging to this
102         * assay-sample combination.
103         *
104         * @return
105         */
106        public int numQualityFiles() {
107                if( !sequenceData )
108                        return 0
109
110                int numFiles = 0;
111                sequenceData.each {
112                        if( it.qualityFile )
113                                numFiles++
114                }
115
116                return numFiles;
117        }
118       
119        /**
120         * Returns the number of sequences in the files on the system, belonging to this
121         * assay-sample combination.
122         *
123         * @return
124         */
125        public long numSequences() {
126                if( _numSequences > -1 )
127                        return _numSequences;
128
129                if( !sequenceData )
130                        return 0
131
132                long numSequences = 0;
133                sequenceData.each { numSequences += it.numSequences }
134
135                // Save as cache
136                _numSequences = numSequences;
137
138                return numSequences;
139        }
140       
141        /**
142         * Returns the number of quality scores in the files on the system, belonging to this
143         * assay-sample combination.
144         *
145         * @return
146         */
147        public long numQualScores() {
148                if( _numQualScores > -1 )
149                        return _numQualScores;
150
151                if( !sequenceData )
152                        return 0
153
154                long numQualScores = 0;
155                sequenceData.each { numQualScores += it.numQualScores() }
156
157                // Save as cache
158                _numQualScores = numQualScores;
159
160                return numQualScores;
161        }
162        /**
163         * Returns the average quality of the sequences in the files on the system,
164         * belonging to this assay-sample combination.
165         *
166         * @return
167         */
168        public float averageQuality() {
169                if( _averageQuality > -1 )
170                        return _averageQuality;
171
172                if( !sequenceData )
173                        return 0.0
174
175                int numSequences = 0;
176                float averageQuality = 0.0;
177
178                sequenceData.each {
179                        numSequences += it.numSequences
180                        averageQuality = averageQuality + ( it.averageQuality - averageQuality ) / numSequences * it.numSequences;
181                }
182
183                // Save as cache
184                _averageQuality = averageQuality;
185
186                return averageQuality;
187        }
188       
189        /**
190         * Reset the statistics to their default value, in order to ensure that the values are recomputed next time.
191         */
192        public void resetStats() {
193                _numSequences = -1;
194                _numQualScores = -1;
195                _averageQuality = -1;
196        }
197       
198        /**
199         * Check whether this assay-sample combination contains information that should be saved in trash on a delete
200         * @return
201         */
202        public boolean containsData() {
203                return tagSequence || tagName || oligoNumber || numFiles() > 0;
204        }
205       
206        /**
207         * Move information that should be kept on delete to another assaySample object.
208         * 
209         * N.B. The sequencedata objects are really moved, so removed from the original object!
210         * 
211         * @param otherAssaySample      Object to move
212         */
213        public void moveValuableDataTo( AssaySample otherAssaySample ) {
214                // Copy properties
215                otherAssaySample.tagSequence = tagSequence;
216                otherAssaySample.oligoNumber = oligoNumber;
217                otherAssaySample.tagName         = tagName;
218               
219                // Move attached data
220                def dataList = [] + sequenceData?.toList()
221                def otherAssay = otherAssaySample.assay;
222               
223                if( dataList && dataList.size() > 0 ) {
224                        for( def j = dataList.size() - 1; j >= 0; j-- ) {
225                                // Copy data to a new sequencedata object.
226                                // Just moving the sequencedata object to the other assay sample resulted
227                                // in a 'deleted object would be re-saved by cascade' exception
228                               
229                                // Clone the sequencedata object
230                                def sd = dataList[ j ]?.clone();
231                               
232                                if( sd )
233                                        otherAssaySample.addToSequenceData( sd );
234                                       
235                                // Remove the old sequencedata object
236                                this.removeFromSequenceData( dataList[ j ] );
237                        }
238                }
239
240                // Copy run properties
241                if( otherAssaySample.run ) {
242                        otherAssaySample.run.removeFromAssaySamples( otherAssaySample );
243                }
244               
245                // Remove this sample from the run.
246                if( run ) {
247                        def copyRun = run;
248                        copyRun.removeFromAssaySamples( this );
249                        copyRun.addToAssaySamples( otherAssaySample );
250                } else {
251                        otherAssaySample.run = null;
252                }
253        }
254}
Note: See TracBrowser for help on using the repository browser.