1 /**
2 * UGENE - Integrated Bioinformatics Tools.
3 * Copyright (C) 2008-2021 UniPro <ugene@unipro.ru>
4 * http://ugene.net
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 * MA 02110-1301, USA.
20 */
21
22 #include "ExtractConsensusWorker.h"
23
24 #include <U2Algorithm/AssemblyConsensusAlgorithmRegistry.h>
25 #include <U2Algorithm/BuiltInAssemblyConsensusAlgorithms.h>
26
27 #include <U2Core/AppContext.h>
28 #include <U2Core/BaseDocumentFormats.h>
29 #include <U2Core/FailTask.h>
30 #include <U2Core/U2AssemblyDbi.h>
31 #include <U2Core/U2OpStatusUtils.h>
32 #include <U2Core/U2SafePoints.h>
33
34 #include <U2Designer/DelegateEditors.h>
35
36 #include <U2Lang/ActorPrototypeRegistry.h>
37 #include <U2Lang/BaseActorCategories.h>
38 #include <U2Lang/BasePorts.h>
39 #include <U2Lang/BaseSlots.h>
40 #include <U2Lang/BaseTypes.h>
41 #include <U2Lang/WorkflowEnv.h>
42
43 #include <U2View/AssemblyModel.h>
44 #include <U2View/ExportConsensusTask.h>
45
46 namespace U2 {
47 namespace LocalWorkflow {
48
49 const QString ExtractConsensusWorkerFactory::ACTOR_ID("extract-consensus");
50
51 namespace {
52 const QString ALGO_ATTR_ID("algorithm");
53 const QString GAPS_ATTR_ID("keep-gaps");
54 } // namespace
55
ExtractConsensusWorker(Actor * actor)56 ExtractConsensusWorker::ExtractConsensusWorker(Actor *actor)
57 : BaseWorker(actor) {
58 }
59
init()60 void ExtractConsensusWorker::init() {
61 }
62
tick()63 Task *ExtractConsensusWorker::tick() {
64 if (hasAssembly()) {
65 U2OpStatusImpl os;
66 const U2EntityRef assembly = takeAssembly(os);
67 CHECK_OP(os, new FailTask(os.getError()));
68
69 return createTask(assembly);
70 } else {
71 finish();
72 return nullptr;
73 }
74 }
75
sl_taskFinished()76 void ExtractConsensusWorker::sl_taskFinished() {
77 ExtractConsensusTaskHelper *t = dynamic_cast<ExtractConsensusTaskHelper *>(sender());
78 CHECK(nullptr != t, );
79 CHECK(t->isFinished() && !t->hasError(), );
80 CHECK(!t->isCanceled(), );
81
82 sendResult(context->getDataStorage()->getDataHandler(t->getResult()));
83 }
84
cleanup()85 void ExtractConsensusWorker::cleanup() {
86 }
87
hasAssembly() const88 bool ExtractConsensusWorker::hasAssembly() const {
89 const IntegralBus *port = ports[BasePorts::IN_ASSEMBLY_PORT_ID()];
90 SAFE_POINT(nullptr != port, "NULL assembly port", false);
91 return port->hasMessage();
92 }
93
takeAssembly(U2OpStatus & os)94 U2EntityRef ExtractConsensusWorker::takeAssembly(U2OpStatus &os) {
95 const Message m = getMessageAndSetupScriptValues(ports[BasePorts::IN_ASSEMBLY_PORT_ID()]);
96 const QVariantMap data = m.getData().toMap();
97 if (!data.contains(BaseSlots::ASSEMBLY_SLOT().getId())) {
98 os.setError(tr("Empty assembly slot"));
99 return U2EntityRef();
100 }
101 const SharedDbiDataHandler dbiId = data[BaseSlots::ASSEMBLY_SLOT().getId()].value<SharedDbiDataHandler>();
102 const AssemblyObject *obj = StorageUtils::getAssemblyObject(context->getDataStorage(), dbiId);
103 if (nullptr == obj) {
104 os.setError(tr("Error with assembly object"));
105 return U2EntityRef();
106 }
107 return obj->getEntityRef();
108 }
109
createTask(const U2EntityRef & assembly)110 Task *ExtractConsensusWorker::createTask(const U2EntityRef &assembly) {
111 const QString algoId = getValue<QString>(ALGO_ATTR_ID);
112 const bool keepGaps = getValue<bool>(GAPS_ATTR_ID);
113 Task *t = new ExtractConsensusTaskHelper(algoId, keepGaps, assembly, context->getDataStorage()->getDbiRef());
114 connect(t, SIGNAL(si_stateChanged()), SLOT(sl_taskFinished()));
115 return t;
116 }
117
finish()118 void ExtractConsensusWorker::finish() {
119 IntegralBus *inPort = ports[BasePorts::IN_ASSEMBLY_PORT_ID()];
120 SAFE_POINT(nullptr != inPort, "NULL assembly port", );
121 SAFE_POINT(inPort->isEnded(), "The assembly is not ended", );
122 IntegralBus *outPort = ports[BasePorts::OUT_SEQ_PORT_ID()];
123 SAFE_POINT(nullptr != outPort, "NULL sequence port", );
124
125 outPort->setEnded();
126 setDone();
127 }
128
sendResult(const SharedDbiDataHandler & seqId)129 void ExtractConsensusWorker::sendResult(const SharedDbiDataHandler &seqId) {
130 QVariantMap data;
131 data[BaseSlots::DNA_SEQUENCE_SLOT().getId()] = qVariantFromValue<SharedDbiDataHandler>(seqId);
132 IntegralBus *outPort = ports[BasePorts::OUT_SEQ_PORT_ID()];
133 SAFE_POINT(nullptr != outPort, "NULL sequence port", );
134
135 outPort->put(Message(outPort->getBusType(), data));
136 }
137
138 /************************************************************************/
139 /* ExtractConsensusTaskHelper */
140 /************************************************************************/
ExtractConsensusTaskHelper(const QString & algoId,bool keepGaps,const U2EntityRef & assembly,const U2DbiRef & targetDbi)141 ExtractConsensusTaskHelper::ExtractConsensusTaskHelper(const QString &algoId, bool keepGaps, const U2EntityRef &assembly, const U2DbiRef &targetDbi)
142 : Task(tr("Extract consensus"), TaskFlags_NR_FOSCOE),
143 algoId(algoId),
144 keepGaps(keepGaps),
145 assembly(assembly),
146 targetDbi(targetDbi),
147 exportTask(nullptr) {
148 }
149
prepare()150 void ExtractConsensusTaskHelper::prepare() {
151 ExportConsensusTaskSettings settings;
152
153 settings.consensusAlgorithm = QSharedPointer<AssemblyConsensusAlgorithm>(createAlgorithm());
154 CHECK_OP(stateInfo, );
155 settings.model = QSharedPointer<AssemblyModel>(createModel());
156 CHECK_OP(stateInfo, );
157
158 settings.region = settings.model->getGlobalRegion();
159 settings.seqObjName = settings.model->getAssembly().visualName;
160
161 settings.saveToFile = false;
162 settings.targetDbi = targetDbi;
163 settings.addToProject = false;
164 settings.keepGaps = keepGaps;
165
166 exportTask = new ExportConsensusTask(settings);
167 addSubTask(exportTask);
168 }
169
getResult() const170 U2EntityRef ExtractConsensusTaskHelper::getResult() const {
171 SAFE_POINT(nullptr != exportTask, "NULL export task", U2EntityRef());
172 const U2Sequence seq = exportTask->getResult();
173 const U2EntityRef ref(targetDbi, seq.id);
174 return ref;
175 }
176
createAlgorithm()177 AssemblyConsensusAlgorithm *ExtractConsensusTaskHelper::createAlgorithm() {
178 AssemblyConsensusAlgorithmRegistry *reg = AppContext::getAssemblyConsensusAlgorithmRegistry();
179 SAFE_POINT_EXT(nullptr != reg, setError("NULL registry"), nullptr);
180
181 AssemblyConsensusAlgorithmFactory *f = reg->getAlgorithmFactory(algoId);
182 if (nullptr == f) {
183 setError(tr("Unknown consensus algorithm: ") + algoId);
184 return nullptr;
185 }
186
187 return f->createAlgorithm();
188 }
189
createModel()190 AssemblyModel *ExtractConsensusTaskHelper::createModel() {
191 const DbiConnection con(assembly.dbiRef, stateInfo);
192 CHECK_OP(stateInfo, nullptr);
193
194 U2AssemblyDbi *dbi = con.dbi->getAssemblyDbi();
195 SAFE_POINT_EXT(nullptr != dbi, setError("NULL assembly dbi"), nullptr);
196
197 const U2Assembly object = dbi->getAssemblyObject(assembly.entityId, stateInfo);
198 CHECK_OP(stateInfo, nullptr);
199
200 AssemblyModel *model = new AssemblyModel(con);
201 model->setAssembly(dbi, object);
202
203 return model;
204 }
205
206 /************************************************************************/
207 /* ExtractConsensusWorkerFactory */
208 /************************************************************************/
ExtractConsensusWorkerFactory()209 ExtractConsensusWorkerFactory::ExtractConsensusWorkerFactory()
210 : DomainFactory(ACTOR_ID) {
211 }
212
createWorker(Actor * actor)213 Worker *ExtractConsensusWorkerFactory::createWorker(Actor *actor) {
214 return new ExtractConsensusWorker(actor);
215 }
216
init()217 void ExtractConsensusWorkerFactory::init() {
218 AssemblyConsensusAlgorithmRegistry *reg = AppContext::getAssemblyConsensusAlgorithmRegistry();
219 SAFE_POINT(nullptr != reg, "NULL registry", );
220
221 const Descriptor desc(ACTOR_ID,
222 QObject::tr("Extract Consensus from Assembly"),
223 QObject::tr("Extract the consensus sequence from the incoming assembly."));
224
225 QList<PortDescriptor *> ports;
226 {
227 QMap<Descriptor, DataTypePtr> inData;
228 inData[BaseSlots::ASSEMBLY_SLOT()] = BaseTypes::ASSEMBLY_TYPE();
229 DataTypePtr inType(new MapDataType(BasePorts::IN_ASSEMBLY_PORT_ID(), inData));
230 ports << new PortDescriptor(BasePorts::IN_ASSEMBLY_PORT_ID(), inType, true);
231
232 QMap<Descriptor, DataTypePtr> outData;
233 outData[BaseSlots::DNA_SEQUENCE_SLOT()] = BaseTypes::DNA_SEQUENCE_TYPE();
234 DataTypePtr outType(new MapDataType(BasePorts::OUT_SEQ_PORT_ID(), outData));
235 ports << new PortDescriptor(BasePorts::OUT_SEQ_PORT_ID(), outType, false, true);
236 }
237
238 QList<Attribute *> attrs;
239 {
240 const Descriptor algoDesc(ALGO_ATTR_ID,
241 QObject::tr("Algorithm"),
242 QObject::tr("The algorithm of consensus extracting."));
243 const Descriptor gapsDesc(GAPS_ATTR_ID,
244 QObject::tr("Keep gaps"),
245 QObject::tr("Set this parameter if the result consensus must keep the gaps."));
246 attrs << new Attribute(algoDesc, BaseTypes::STRING_TYPE(), true, BuiltInAssemblyConsensusAlgorithms::DEFAULT_ALGO);
247 attrs << new Attribute(gapsDesc, BaseTypes::BOOL_TYPE(), true, true);
248 }
249
250 QMap<QString, PropertyDelegate *> delegates;
251 {
252 QVariantMap algos;
253 foreach (const QString algoId, reg->getAlgorithmIds()) {
254 AssemblyConsensusAlgorithmFactory *f = reg->getAlgorithmFactory(algoId);
255 algos[f->getName()] = algoId;
256 }
257 delegates[ALGO_ATTR_ID] = new ComboBoxDelegate(algos);
258 }
259
260 ActorPrototype *proto = new IntegralBusActorPrototype(desc, ports, attrs);
261 proto->setPrompter(new ExtractConsensusWorkerPrompter());
262 proto->setEditor(new DelegateEditor(delegates));
263
264 WorkflowEnv::getProtoRegistry()->registerProto(BaseActorCategories::CATEGORY_NGS_BASIC(), proto);
265 DomainFactory *localDomain = WorkflowEnv::getDomainRegistry()->getById(LocalDomainFactory::ID);
266 localDomain->registerEntry(new ExtractConsensusWorkerFactory());
267 }
268
269 /************************************************************************/
270 /* ExtractConsensusWorkerPrompter */
271 /************************************************************************/
ExtractConsensusWorkerPrompter(Actor * actor)272 ExtractConsensusWorkerPrompter::ExtractConsensusWorkerPrompter(Actor *actor)
273 : PrompterBase<ExtractConsensusWorkerPrompter>(actor) {
274 }
275
composeRichDoc()276 QString ExtractConsensusWorkerPrompter::composeRichDoc() {
277 QString algorithm = getParameter(ALGO_ATTR_ID).toString();
278 QString link = getHyperlink(ALGO_ATTR_ID, algorithm);
279 return tr("Extracts the consensus sequence from the incoming assembly using the %1 algorithm.").arg(link);
280 }
281
282 } // namespace LocalWorkflow
283 } // namespace U2
284