From 3f1e56d185384f3b4008767f5d15258420472967 Mon Sep 17 00:00:00 2001 From: cfrainay <clement.frainay@inrae.fr> Date: Tue, 10 May 2022 18:20:03 +0200 Subject: [PATCH 01/17] draft metanetwork creation --- .../AbstractMetaNetworkBuilder.java | 209 ++++++++++++++++++ .../DefaultMetaEntityFactory.java | 42 ++++ .../multinetwork/MetaEntityFactory.java | 10 + .../multinetwork/MetaNetworkBuilder.java | 45 ++++ .../multinetwork/MultiNetworkBuilder.java | 21 ++ .../MultiOrganNetworkBuilder.java | 57 +++++ .../multinetwork/NestedNetworkBuilder.java | 43 ++++ .../multinetwork/PanNetworkBuilder.java | 23 ++ 8 files changed, 450 insertions(+) create mode 100644 met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/AbstractMetaNetworkBuilder.java create mode 100644 met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/DefaultMetaEntityFactory.java create mode 100644 met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/MetaEntityFactory.java create mode 100644 met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/MetaNetworkBuilder.java create mode 100644 met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/MultiNetworkBuilder.java create mode 100644 met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/MultiOrganNetworkBuilder.java create mode 100644 met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/NestedNetworkBuilder.java create mode 100644 met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/PanNetworkBuilder.java diff --git a/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/AbstractMetaNetworkBuilder.java b/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/AbstractMetaNetworkBuilder.java new file mode 100644 index 000000000..64ddbcfe4 --- /dev/null +++ b/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/AbstractMetaNetworkBuilder.java @@ -0,0 +1,209 @@ +package fr.inrae.toulouse.metexplore.met4j_core.biodata.multinetwork; + +import fr.inrae.toulouse.metexplore.met4j_core.biodata.*; +import fr.inrae.toulouse.metexplore.met4j_core.biodata.collection.BioCollection; +import lombok.SneakyThrows; + +import java.lang.reflect.InvocationTargetException; +import java.util.*; +import java.util.function.Function; +import java.util.function.Supplier; +import java.util.stream.Collectors; + +public abstract class AbstractMetaNetworkBuilder implements MultiNetworkBuilder{ + + BioCollection<BioNetwork> networks; + Map<BioCompartment, Map<BioNetwork, BioCollection<BioMetabolite>>> metaCompComposition; + MetaEntityFactory entityFactory; + + Boolean keepGPR = false; + Boolean flush; + + public AbstractMetaNetworkBuilder(){ + this.entityFactory= new DefaultMetaEntityFactory(); + } + + public AbstractMetaNetworkBuilder(MetaEntityFactory entityFactory){ + this.entityFactory=entityFactory; + } + + protected void addSharedCompartment(BioCompartment sc) { + metaCompComposition.put(sc,new HashMap<>()); + } + protected void addSharedCompartment(BioCompartment sc, BioNetwork... bn) { + HashMap<BioNetwork, BioCollection<BioMetabolite>> map = Arrays.stream(bn).collect(Collectors.toMap( + x -> x, + x -> new BioCollection<BioMetabolite>(), + (prev, next) -> {prev.addAll(next);return prev;}, + HashMap::new + )); + if(metaCompComposition.containsKey(sc)){ + metaCompComposition.get(sc).putAll(map); + }else{ + metaCompComposition.put(sc,map); + } + } + + protected void fuseCompartmentIntoSharedCompartment(BioNetwork n, BioCompartment c, BioCompartment sc) { + //TODO + } + + protected void bumpCompartmentIntoSharedCompartment(BioNetwork n, BioCompartment c, BioCompartment sc) { + Map<BioNetwork, BioCollection<BioMetabolite>> compartmentContent = metaCompComposition.get(sc); + if(compartmentContent==null) throw new IllegalArgumentException("Shared Compartment not found"); + BioCollection<BioMetabolite> sharedContent = compartmentContent.get(n); + if(compartmentContent==null) throw new IllegalArgumentException("SubNetwork not in shared compartment"); + BioCollection<BioMetabolite> toShare = n.getMetabolitesView().stream() + .filter(x -> n.getCompartmentsOf(x).contains(c)) + .collect(BioCollection::new,BioCollection::add,BioCollection::addAll); + sharedContent.addAll(toShare); + } + + protected void exchangeWithSharedCompartment(BioNetwork n, BioMetabolite m, BioCompartment sc) { + //todo + } + + protected void exchangeWithSharedCompartment(BioNetwork n, BioCollection<BioMetabolite> m, BioCompartment sc) { + //todo + } + + @Override + public void add(BioNetwork bn) { + networks.add(bn); + } + + @Override + public abstract void merge(); + + @Override + public abstract BioNetwork build(); + + + void populateMetaNetwork(BioNetwork meta){ + + for(BioNetwork sub : networks){ + + Map<BioMetabolite,BioMetabolite> metaboliteConversion = new HashMap<>(); + Map<BioCompartment,BioCompartment> compartmentConversion = new HashMap<>(); + Map<BioReaction,BioReaction> reactionConversion = new HashMap<>(); + Map<BioProtein,BioProtein> proteinConversion = new HashMap<>(); + Map<BioEnzyme,BioEnzyme> enzymeConversion = new HashMap<>(); + Map<BioGene,BioGene> geneConversion = new HashMap<>(); + + for(BioMetabolite e : sub.getMetabolitesView()){ + BioMetabolite e2 = entityFactory.copy(e,sub); + meta.add(e2); + metaboliteConversion.put(e,e2); + } + for(BioCompartment c : sub.getCompartmentsView()){ + BioCompartment c2 = entityFactory.copy(c,sub); + meta.add(c2); + compartmentConversion.put(c,c2); + c.getComponentsView().stream(). + filter((e) -> e.getClass().equals(BioMetabolite.class)). + forEach((m) -> { + BioMetabolite newMetabolite = metaboliteConversion.get(m); + meta.affectToCompartment(c, newMetabolite); + }); + } + + // Copy genes + if (keepGPR) { + //TODO case shared Genome + for (BioGene gene : sub.getGenesView()) { + BioGene newGene = entityFactory.copy(gene,sub); + meta.add(newGene); + geneConversion.put(gene,newGene); + } + for (BioProtein protein : sub.getProteinsView()) { + BioProtein newProtein = entityFactory.copy(protein,sub); + meta.add(newProtein); + proteinConversion.put(protein,newProtein); + + if (protein.getGene() != null) { + BioGene newGene = geneConversion.get(protein.getGene()); + meta.affectGeneProduct(newProtein, newGene); + } + } + for (BioEnzyme enzyme : sub.getEnzymesView()) { + + BioEnzyme newEnzyme = entityFactory.copy(enzyme,sub); + meta.add(newEnzyme); + enzymeConversion.put(enzyme,newEnzyme); + + BioCollection<BioEnzymeParticipant> participants = enzyme.getParticipantsView(); + + for (BioEnzymeParticipant participant : participants) { + Double quantity = participant.getQuantity(); + + if (participant.getPhysicalEntity().getClass().equals(BioMetabolite.class)) { + BioMetabolite metabolite = (BioMetabolite) participant.getPhysicalEntity(); + BioMetabolite newMetabolite = metaboliteConversion.get(metabolite); + meta.affectSubUnit(newEnzyme, quantity, newMetabolite); + } else if (participant.getPhysicalEntity().getClass().equals(BioProtein.class)) { + BioProtein protein = (BioProtein) participant.getPhysicalEntity(); + BioProtein newProtein = proteinConversion.get(protein); + meta.affectSubUnit(newEnzyme, quantity, newProtein); + } + } + } + } + + for (BioReaction r : sub.getReactionsView()) { + + BioReaction newReaction = entityFactory.copy(r,sub);; + newReaction.setSpontaneous(r.isSpontaneous()); + newReaction.setReversible(r.isReversible()); + newReaction.setEcNumber(r.getEcNumber()); + + meta.add(newReaction); + + // Copy lefts + for (BioReactant reactant : r.getLeftReactantsView()) { + BioMetabolite newMetabolite = metaboliteConversion.get(reactant.getMetabolite()); + BioCompartment newCpt = compartmentConversion.get(reactant.getLocation().getId()); + Double sto = reactant.getQuantity(); + meta.affectLeft(newReaction, sto, newCpt, newMetabolite); + } + + // Copy rights + for (BioReactant reactant : r.getRightReactantsView()) { + BioMetabolite newMetabolite = metaboliteConversion.get(reactant.getMetabolite()); + BioCompartment newCpt = compartmentConversion.get(reactant.getLocation().getId()); + Double sto = reactant.getQuantity(); + meta.affectRight(newReaction, sto, newCpt, newMetabolite); + } + + // Copy enzymes + if (keepGPR) { + for (BioEnzyme enzyme : r.getEnzymesView()) { + BioEnzyme newEnzyme = enzymeConversion.get(enzyme); + meta.affectEnzyme(newReaction, newEnzyme); + } + } + } + + for (BioPathway pathway : sub.getPathwaysView()) { + BioPathway newPathway = entityFactory.copy(pathway,sub); + meta.add(newPathway); + // Add reactions into pathway + BioCollection<BioReaction> reactions = sub.getReactionsFromPathways(pathway); + + for (BioReaction reaction : reactions) { + BioReaction newReaction = reactionConversion.get(reaction); + meta.affectToPathway(newPathway, newReaction); + } + } + } + } + + + void initSharedComp(BioNetwork meta){ + for(Map.Entry<BioCompartment, Map<BioNetwork, BioCollection<BioMetabolite>>> compDescriptor : metaCompComposition.entrySet()){ + meta.addCompartment(compDescriptor.getKey()); + for(Map.Entry<BioNetwork, BioCollection<BioMetabolite>> content : compDescriptor.getValue().entrySet()){ + meta.affectToCompartment(compDescriptor.getKey(),content.getValue()); + } + } + } +} diff --git a/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/DefaultMetaEntityFactory.java b/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/DefaultMetaEntityFactory.java new file mode 100644 index 000000000..ce5227046 --- /dev/null +++ b/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/DefaultMetaEntityFactory.java @@ -0,0 +1,42 @@ +package fr.inrae.toulouse.metexplore.met4j_core.biodata.multinetwork; + +import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioEntity; +import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioNetwork; +import lombok.SneakyThrows; + +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.function.BiFunction; +import java.util.function.Function; + +public class DefaultMetaEntityFactory implements MetaEntityFactory { + + public BiFunction<BioEntity, BioNetwork, String> idSupplier = (e,bn) -> { + return e.getId()+"_"+bn.getId(); + }; + + public BiFunction<BioEntity, BioNetwork, String> getIdSupplier() { + return idSupplier; + } + + public void setIdSupplier(BiFunction<BioEntity, BioNetwork, String> idSupplier) { + this.idSupplier = idSupplier; + } + + @SneakyThrows + @Override + public <E extends BioEntity> E copy(E entity, BioNetwork source) { + return newEntityInstance(entity, this.idSupplier.apply(entity,source)); + } + + public static <E extends BioEntity> E newEntityInstance(E entity, String newId) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException { + E newEntity = (E) entity.getClass().getDeclaredConstructor(String.class).newInstance(newId); + newEntity.setName(entity.getName()); + newEntity.setSynonyms(new ArrayList<>(entity.getSynonyms())); + newEntity.setComment(entity.getComment()); + newEntity.setRefs(new HashMap<>(entity.getRefs())); + newEntity.setAttributes(new HashMap<>(entity.getAttributes())); + return newEntity; + } +} diff --git a/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/MetaEntityFactory.java b/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/MetaEntityFactory.java new file mode 100644 index 000000000..554d7b182 --- /dev/null +++ b/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/MetaEntityFactory.java @@ -0,0 +1,10 @@ +package fr.inrae.toulouse.metexplore.met4j_core.biodata.multinetwork; + +import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioEntity; +import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioNetwork; + +public interface MetaEntityFactory { + + public <E extends BioEntity> E copy(E entity, BioNetwork source); + +} diff --git a/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/MetaNetworkBuilder.java b/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/MetaNetworkBuilder.java new file mode 100644 index 000000000..7af6a2b5f --- /dev/null +++ b/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/MetaNetworkBuilder.java @@ -0,0 +1,45 @@ +package fr.inrae.toulouse.metexplore.met4j_core.biodata.multinetwork; + +import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioCompartment; +import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioMetabolite; +import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioNetwork; +import fr.inrae.toulouse.metexplore.met4j_core.biodata.collection.BioCollection; + +import java.util.UUID; + +public class MetaNetworkBuilder extends AbstractMetaNetworkBuilder implements MultiNetworkBuilder{ + + + private BioCompartment medium; + + public MetaNetworkBuilder(BioNetwork superNetwork){ + setMedium(); + } + + private void setMedium(){ + this.medium = new BioCompartment(UUID.randomUUID().toString(),"medium"); + this.addSharedCompartment(medium); + } + + @Override + public void add(BioNetwork bn) { + super.add(bn); + this.addSharedCompartment(medium,this.networks.stream().toArray(BioNetwork[]::new)); + } + + @Override + public void merge() { + //todo + } + + public void exchangeWithMedium(BioNetwork n, BioMetabolite m){ + this.exchangeWithSharedCompartment(n, m, medium); + }; + + @Override + public BioNetwork build() { + //todo + return null; + } + +} diff --git a/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/MultiNetworkBuilder.java b/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/MultiNetworkBuilder.java new file mode 100644 index 000000000..c17e2cadc --- /dev/null +++ b/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/MultiNetworkBuilder.java @@ -0,0 +1,21 @@ +package fr.inrae.toulouse.metexplore.met4j_core.biodata.multinetwork; + +import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioNetwork; + +public interface MultiNetworkBuilder { + + /** + * add network into meta-network + * @param bn + */ + public void add(BioNetwork bn); + + public void merge(); + + /** + * create a new network which encompass all added networks + * @return + */ + public BioNetwork build(); + +} diff --git a/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/MultiOrganNetworkBuilder.java b/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/MultiOrganNetworkBuilder.java new file mode 100644 index 000000000..ae4c1b699 --- /dev/null +++ b/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/MultiOrganNetworkBuilder.java @@ -0,0 +1,57 @@ +package fr.inrae.toulouse.metexplore.met4j_core.biodata.multinetwork; + +import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioCompartment; +import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioMetabolite; +import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioNetwork; +import fr.inrae.toulouse.metexplore.met4j_core.biodata.collection.BioCollection; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.stream.Collectors; + +public class MultiOrganNetworkBuilder extends AbstractMetaNetworkBuilder implements MultiNetworkBuilder{ + + @Override + public void merge() { + //TODO + } + + + @Override + public void addSharedCompartment(BioCompartment sc, BioNetwork... bn) { + super.addSharedCompartment(sc,bn); + } + + @Override + public void fuseCompartmentIntoSharedCompartment(BioNetwork n, BioCompartment c, BioCompartment sc) { + super.fuseCompartmentIntoSharedCompartment(n,c,sc); + } + + @Override + public void bumpCompartmentIntoSharedCompartment(BioNetwork n, BioCompartment c, BioCompartment sc) { + super.bumpCompartmentIntoSharedCompartment(n,c,sc); + } + + @Override + public void exchangeWithSharedCompartment(BioNetwork n, BioMetabolite m, BioCompartment sc) { + super.exchangeWithSharedCompartment(n,m,sc); + } + + @Override + public void exchangeWithSharedCompartment(BioNetwork n, BioCollection<BioMetabolite> m, BioCompartment sc) { + super.exchangeWithSharedCompartment(n,m,sc); + } + + @Override + public BioNetwork build() { + //todo + //create empty meta network + BioNetwork meta = new BioNetwork(); + //add each subnetwork content in dedicated compartment + this.populateMetaNetwork(meta); + //create shared compartment and the exchanged content + this.initSharedComp(meta); + return null; + } +} diff --git a/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/NestedNetworkBuilder.java b/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/NestedNetworkBuilder.java new file mode 100644 index 000000000..aeca0c100 --- /dev/null +++ b/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/NestedNetworkBuilder.java @@ -0,0 +1,43 @@ +package fr.inrae.toulouse.metexplore.met4j_core.biodata.multinetwork; + +import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioCompartment; +import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioMetabolite; +import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioNetwork; + +public class NestedNetworkBuilder extends AbstractMetaNetworkBuilder implements MultiNetworkBuilder{ + + private BioNetwork superNet; + private BioCompartment superNetComp; + + public NestedNetworkBuilder(BioNetwork superNetwork){ + setSuperNetwork(superNetwork); + } + + private void setSuperNetwork(BioNetwork bn){ + superNet=bn; + this.superNetComp = new BioCompartment(bn.getId()); + this.addSharedCompartment(superNetComp,superNet); + } + + @Override + public void add(BioNetwork bn) { + super.add(bn); + this.addSharedCompartment(superNetComp,this.networks.stream().toArray(BioNetwork[]::new)); + } + + @Override + public void merge() { + //todo + } + + public void exchangeWithSuperNetwork(BioNetwork n, BioMetabolite m){ + this.exchangeWithSharedCompartment(n, m, superNetComp); + }; + + @Override + public BioNetwork build() { + //todo + return null; + } + +} diff --git a/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/PanNetworkBuilder.java b/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/PanNetworkBuilder.java new file mode 100644 index 000000000..346f71cbf --- /dev/null +++ b/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/PanNetworkBuilder.java @@ -0,0 +1,23 @@ +package fr.inrae.toulouse.metexplore.met4j_core.biodata.multinetwork; + +import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioMetabolite; +import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioNetwork; +import fr.inrae.toulouse.metexplore.met4j_core.biodata.collection.BioCollection; + +public class PanNetworkBuilder implements MultiNetworkBuilder { + @Override + public void add(BioNetwork bn) { + //todo + } + + @Override + public void merge() { + //todo + } + + @Override + public BioNetwork build() { + //todo + return null; + } +} -- GitLab From 297b7681c25ed6758d203be91d54288ada8c42f4 Mon Sep 17 00:00:00 2001 From: cfrainay <clement.frainay@inrae.fr> Date: Thu, 16 May 2024 16:29:19 +0200 Subject: [PATCH 02/17] finalize metanetwork creation --- .../AbstractMetaNetworkBuilder.java | 209 ------------ .../multinetwork/CommunityNetworkBuilder.java | 49 +++ .../DefaultMetaEntityFactory.java | 42 --- .../multinetwork/MetaBioMetabolite.java | 16 + .../multinetwork/MetaEntityFactory.java | 8 +- .../multinetwork/MetaNetworkBuilder.java | 313 ++++++++++++++++-- .../multinetwork/MultiNetworkBuilder.java | 3 +- .../MultiOrganNetworkBuilder.java | 57 ---- .../multinetwork/NestedNetworkBuilder.java | 43 --- .../multinetwork/PanNetworkBuilder.java | 23 -- .../PrefixedMetaEntityFactory.java | 86 +++++ .../multinetwork/TestMetaNetworkBuilder.java | 185 +++++++++++ 12 files changed, 636 insertions(+), 398 deletions(-) delete mode 100644 met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/AbstractMetaNetworkBuilder.java create mode 100644 met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/CommunityNetworkBuilder.java delete mode 100644 met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/DefaultMetaEntityFactory.java create mode 100644 met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/MetaBioMetabolite.java delete mode 100644 met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/MultiOrganNetworkBuilder.java delete mode 100644 met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/NestedNetworkBuilder.java delete mode 100644 met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/PanNetworkBuilder.java create mode 100644 met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/PrefixedMetaEntityFactory.java create mode 100644 met4j-core/src/test/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/TestMetaNetworkBuilder.java diff --git a/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/AbstractMetaNetworkBuilder.java b/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/AbstractMetaNetworkBuilder.java deleted file mode 100644 index 64ddbcfe4..000000000 --- a/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/AbstractMetaNetworkBuilder.java +++ /dev/null @@ -1,209 +0,0 @@ -package fr.inrae.toulouse.metexplore.met4j_core.biodata.multinetwork; - -import fr.inrae.toulouse.metexplore.met4j_core.biodata.*; -import fr.inrae.toulouse.metexplore.met4j_core.biodata.collection.BioCollection; -import lombok.SneakyThrows; - -import java.lang.reflect.InvocationTargetException; -import java.util.*; -import java.util.function.Function; -import java.util.function.Supplier; -import java.util.stream.Collectors; - -public abstract class AbstractMetaNetworkBuilder implements MultiNetworkBuilder{ - - BioCollection<BioNetwork> networks; - Map<BioCompartment, Map<BioNetwork, BioCollection<BioMetabolite>>> metaCompComposition; - MetaEntityFactory entityFactory; - - Boolean keepGPR = false; - Boolean flush; - - public AbstractMetaNetworkBuilder(){ - this.entityFactory= new DefaultMetaEntityFactory(); - } - - public AbstractMetaNetworkBuilder(MetaEntityFactory entityFactory){ - this.entityFactory=entityFactory; - } - - protected void addSharedCompartment(BioCompartment sc) { - metaCompComposition.put(sc,new HashMap<>()); - } - protected void addSharedCompartment(BioCompartment sc, BioNetwork... bn) { - HashMap<BioNetwork, BioCollection<BioMetabolite>> map = Arrays.stream(bn).collect(Collectors.toMap( - x -> x, - x -> new BioCollection<BioMetabolite>(), - (prev, next) -> {prev.addAll(next);return prev;}, - HashMap::new - )); - if(metaCompComposition.containsKey(sc)){ - metaCompComposition.get(sc).putAll(map); - }else{ - metaCompComposition.put(sc,map); - } - } - - protected void fuseCompartmentIntoSharedCompartment(BioNetwork n, BioCompartment c, BioCompartment sc) { - //TODO - } - - protected void bumpCompartmentIntoSharedCompartment(BioNetwork n, BioCompartment c, BioCompartment sc) { - Map<BioNetwork, BioCollection<BioMetabolite>> compartmentContent = metaCompComposition.get(sc); - if(compartmentContent==null) throw new IllegalArgumentException("Shared Compartment not found"); - BioCollection<BioMetabolite> sharedContent = compartmentContent.get(n); - if(compartmentContent==null) throw new IllegalArgumentException("SubNetwork not in shared compartment"); - BioCollection<BioMetabolite> toShare = n.getMetabolitesView().stream() - .filter(x -> n.getCompartmentsOf(x).contains(c)) - .collect(BioCollection::new,BioCollection::add,BioCollection::addAll); - sharedContent.addAll(toShare); - } - - protected void exchangeWithSharedCompartment(BioNetwork n, BioMetabolite m, BioCompartment sc) { - //todo - } - - protected void exchangeWithSharedCompartment(BioNetwork n, BioCollection<BioMetabolite> m, BioCompartment sc) { - //todo - } - - @Override - public void add(BioNetwork bn) { - networks.add(bn); - } - - @Override - public abstract void merge(); - - @Override - public abstract BioNetwork build(); - - - void populateMetaNetwork(BioNetwork meta){ - - for(BioNetwork sub : networks){ - - Map<BioMetabolite,BioMetabolite> metaboliteConversion = new HashMap<>(); - Map<BioCompartment,BioCompartment> compartmentConversion = new HashMap<>(); - Map<BioReaction,BioReaction> reactionConversion = new HashMap<>(); - Map<BioProtein,BioProtein> proteinConversion = new HashMap<>(); - Map<BioEnzyme,BioEnzyme> enzymeConversion = new HashMap<>(); - Map<BioGene,BioGene> geneConversion = new HashMap<>(); - - for(BioMetabolite e : sub.getMetabolitesView()){ - BioMetabolite e2 = entityFactory.copy(e,sub); - meta.add(e2); - metaboliteConversion.put(e,e2); - } - for(BioCompartment c : sub.getCompartmentsView()){ - BioCompartment c2 = entityFactory.copy(c,sub); - meta.add(c2); - compartmentConversion.put(c,c2); - c.getComponentsView().stream(). - filter((e) -> e.getClass().equals(BioMetabolite.class)). - forEach((m) -> { - BioMetabolite newMetabolite = metaboliteConversion.get(m); - meta.affectToCompartment(c, newMetabolite); - }); - } - - // Copy genes - if (keepGPR) { - //TODO case shared Genome - for (BioGene gene : sub.getGenesView()) { - BioGene newGene = entityFactory.copy(gene,sub); - meta.add(newGene); - geneConversion.put(gene,newGene); - } - for (BioProtein protein : sub.getProteinsView()) { - BioProtein newProtein = entityFactory.copy(protein,sub); - meta.add(newProtein); - proteinConversion.put(protein,newProtein); - - if (protein.getGene() != null) { - BioGene newGene = geneConversion.get(protein.getGene()); - meta.affectGeneProduct(newProtein, newGene); - } - } - for (BioEnzyme enzyme : sub.getEnzymesView()) { - - BioEnzyme newEnzyme = entityFactory.copy(enzyme,sub); - meta.add(newEnzyme); - enzymeConversion.put(enzyme,newEnzyme); - - BioCollection<BioEnzymeParticipant> participants = enzyme.getParticipantsView(); - - for (BioEnzymeParticipant participant : participants) { - Double quantity = participant.getQuantity(); - - if (participant.getPhysicalEntity().getClass().equals(BioMetabolite.class)) { - BioMetabolite metabolite = (BioMetabolite) participant.getPhysicalEntity(); - BioMetabolite newMetabolite = metaboliteConversion.get(metabolite); - meta.affectSubUnit(newEnzyme, quantity, newMetabolite); - } else if (participant.getPhysicalEntity().getClass().equals(BioProtein.class)) { - BioProtein protein = (BioProtein) participant.getPhysicalEntity(); - BioProtein newProtein = proteinConversion.get(protein); - meta.affectSubUnit(newEnzyme, quantity, newProtein); - } - } - } - } - - for (BioReaction r : sub.getReactionsView()) { - - BioReaction newReaction = entityFactory.copy(r,sub);; - newReaction.setSpontaneous(r.isSpontaneous()); - newReaction.setReversible(r.isReversible()); - newReaction.setEcNumber(r.getEcNumber()); - - meta.add(newReaction); - - // Copy lefts - for (BioReactant reactant : r.getLeftReactantsView()) { - BioMetabolite newMetabolite = metaboliteConversion.get(reactant.getMetabolite()); - BioCompartment newCpt = compartmentConversion.get(reactant.getLocation().getId()); - Double sto = reactant.getQuantity(); - meta.affectLeft(newReaction, sto, newCpt, newMetabolite); - } - - // Copy rights - for (BioReactant reactant : r.getRightReactantsView()) { - BioMetabolite newMetabolite = metaboliteConversion.get(reactant.getMetabolite()); - BioCompartment newCpt = compartmentConversion.get(reactant.getLocation().getId()); - Double sto = reactant.getQuantity(); - meta.affectRight(newReaction, sto, newCpt, newMetabolite); - } - - // Copy enzymes - if (keepGPR) { - for (BioEnzyme enzyme : r.getEnzymesView()) { - BioEnzyme newEnzyme = enzymeConversion.get(enzyme); - meta.affectEnzyme(newReaction, newEnzyme); - } - } - } - - for (BioPathway pathway : sub.getPathwaysView()) { - BioPathway newPathway = entityFactory.copy(pathway,sub); - meta.add(newPathway); - // Add reactions into pathway - BioCollection<BioReaction> reactions = sub.getReactionsFromPathways(pathway); - - for (BioReaction reaction : reactions) { - BioReaction newReaction = reactionConversion.get(reaction); - meta.affectToPathway(newPathway, newReaction); - } - } - } - } - - - void initSharedComp(BioNetwork meta){ - for(Map.Entry<BioCompartment, Map<BioNetwork, BioCollection<BioMetabolite>>> compDescriptor : metaCompComposition.entrySet()){ - meta.addCompartment(compDescriptor.getKey()); - for(Map.Entry<BioNetwork, BioCollection<BioMetabolite>> content : compDescriptor.getValue().entrySet()){ - meta.affectToCompartment(compDescriptor.getKey(),content.getValue()); - } - } - } -} diff --git a/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/CommunityNetworkBuilder.java b/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/CommunityNetworkBuilder.java new file mode 100644 index 000000000..c14270c6d --- /dev/null +++ b/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/CommunityNetworkBuilder.java @@ -0,0 +1,49 @@ +package fr.inrae.toulouse.metexplore.met4j_core.biodata.multinetwork; + +import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioCompartment; +import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioMetabolite; +import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioNetwork; + +import java.util.Map; +import java.util.Set; +import java.util.UUID; +import java.util.stream.Collectors; + +public class CommunityNetworkBuilder extends MetaNetworkBuilder implements MultiNetworkBuilder{ + + private BioCompartment medium; + + public CommunityNetworkBuilder(){ + setMedium(); + } + + public CommunityNetworkBuilder(BioCompartment medium){ + this.medium=medium; + this.addNewSharedCompartment(medium); + } + + public CommunityNetworkBuilder(Set<BioNetwork> networks){ + setMedium(); + Map<BioNetwork,String> prefixes = networks.stream() + .collect(Collectors.toMap(n->n,n->n.getId()+"_")); + this.setEntityFactory(new PrefixedMetaEntityFactory(prefixes,"pool")); + for(BioNetwork bn : networks){ + this.add(bn); + } + } + + private void setMedium(){ + this.medium = new BioCompartment(UUID.randomUUID().toString(),"medium"); + this.addNewSharedCompartment(medium); + } + + public void exchangeWithMedium(BioNetwork sourceNetwork, BioCompartment sourceCompartment, BioMetabolite metabolite){ + this.exchangeWithSharedCompartment(sourceNetwork, sourceCompartment, metabolite, medium); + }; + + public void add(BioNetwork bn, BioCompartment externalComp) { + super.add(bn); + this.fuseCompartmentIntoSharedCompartment(bn,externalComp,medium); + } + +} diff --git a/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/DefaultMetaEntityFactory.java b/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/DefaultMetaEntityFactory.java deleted file mode 100644 index ce5227046..000000000 --- a/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/DefaultMetaEntityFactory.java +++ /dev/null @@ -1,42 +0,0 @@ -package fr.inrae.toulouse.metexplore.met4j_core.biodata.multinetwork; - -import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioEntity; -import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioNetwork; -import lombok.SneakyThrows; - -import java.lang.reflect.InvocationTargetException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.function.BiFunction; -import java.util.function.Function; - -public class DefaultMetaEntityFactory implements MetaEntityFactory { - - public BiFunction<BioEntity, BioNetwork, String> idSupplier = (e,bn) -> { - return e.getId()+"_"+bn.getId(); - }; - - public BiFunction<BioEntity, BioNetwork, String> getIdSupplier() { - return idSupplier; - } - - public void setIdSupplier(BiFunction<BioEntity, BioNetwork, String> idSupplier) { - this.idSupplier = idSupplier; - } - - @SneakyThrows - @Override - public <E extends BioEntity> E copy(E entity, BioNetwork source) { - return newEntityInstance(entity, this.idSupplier.apply(entity,source)); - } - - public static <E extends BioEntity> E newEntityInstance(E entity, String newId) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException { - E newEntity = (E) entity.getClass().getDeclaredConstructor(String.class).newInstance(newId); - newEntity.setName(entity.getName()); - newEntity.setSynonyms(new ArrayList<>(entity.getSynonyms())); - newEntity.setComment(entity.getComment()); - newEntity.setRefs(new HashMap<>(entity.getRefs())); - newEntity.setAttributes(new HashMap<>(entity.getAttributes())); - return newEntity; - } -} diff --git a/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/MetaBioMetabolite.java b/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/MetaBioMetabolite.java new file mode 100644 index 000000000..4d3bfce22 --- /dev/null +++ b/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/MetaBioMetabolite.java @@ -0,0 +1,16 @@ +package fr.inrae.toulouse.metexplore.met4j_core.biodata.multinetwork; + +import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioCompartment; +import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioMetabolite; +import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioNetwork; + +public record MetaBioMetabolite(BioMetabolite metabolite, BioCompartment sourceCompartment, BioNetwork sourceNetwork) { + public MetaBioMetabolite(BioMetabolite metabolite, BioCompartment sourceCompartment, BioNetwork sourceNetwork){ + if(!sourceNetwork.containsMetabolite(metabolite.getId())) throw new IllegalArgumentException("Source network does not contains metabolites"); + if(!sourceNetwork.containsCompartment(sourceCompartment.getId())) throw new IllegalArgumentException("Source network does not contains source compartment"); + if(sourceCompartment.getComponentsView().get(metabolite.getId())==null) throw new IllegalArgumentException("Source compartment does not contains metabolites"); + this.metabolite = metabolite; + this.sourceCompartment = sourceCompartment; + this.sourceNetwork = sourceNetwork; + } +} diff --git a/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/MetaEntityFactory.java b/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/MetaEntityFactory.java index 554d7b182..c7254a7cf 100644 --- a/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/MetaEntityFactory.java +++ b/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/MetaEntityFactory.java @@ -1,10 +1,16 @@ package fr.inrae.toulouse.metexplore.met4j_core.biodata.multinetwork; +import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioCompartment; import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioEntity; +import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioMetabolite; import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioNetwork; +import java.util.Collection; + public interface MetaEntityFactory { - public <E extends BioEntity> E copy(E entity, BioNetwork source); + <E extends BioEntity> E createMetaEntity(E originalEntity, BioNetwork source); + BioMetabolite createSharedCompound(BioMetabolite originalEntity, BioCompartment sharedComp); + BioMetabolite createPoolCompound (Collection<BioMetabolite> entities, BioCompartment sharedComp); } diff --git a/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/MetaNetworkBuilder.java b/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/MetaNetworkBuilder.java index 7af6a2b5f..b5b5b2958 100644 --- a/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/MetaNetworkBuilder.java +++ b/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/MetaNetworkBuilder.java @@ -1,45 +1,316 @@ package fr.inrae.toulouse.metexplore.met4j_core.biodata.multinetwork; -import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioCompartment; -import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioMetabolite; -import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioNetwork; +import fr.inrae.toulouse.metexplore.met4j_core.biodata.*; import fr.inrae.toulouse.metexplore.met4j_core.biodata.collection.BioCollection; +import lombok.Getter; +import lombok.Setter; -import java.util.UUID; +import java.util.*; +import java.util.function.BiFunction; +import java.util.function.Function; +import java.util.stream.Collectors; -public class MetaNetworkBuilder extends AbstractMetaNetworkBuilder implements MultiNetworkBuilder{ +/** + * A class that creates a meta-networks from multiple sub-networks. A meta-network is a single model which contains several + * sub-networks that remains individualized within the meta-network (as opposed to models fusion), but which can share + * some of their components with other sub-networks through shared compartments. + */ +public class MetaNetworkBuilder implements MultiNetworkBuilder{ + private Map<BioMetabolite,BioMetabolite> metaboliteConversion; + private Map<BioCompartment,BioCompartment> compartmentConversion; + private Map<BioReaction,BioReaction> reactionConversion; + private Map<BioProtein,BioProtein> proteinConversion; + private Map<BioEnzyme,BioEnzyme> enzymeConversion; + private Map<BioGene,BioGene> geneConversion; - private BioCompartment medium; + protected BioCollection<BioNetwork> networks = new BioCollection<>(); + private Map<BioCompartment, Set<MetaBioMetabolite>> metaCompComposition = new HashMap<>(); - public MetaNetworkBuilder(BioNetwork superNetwork){ - setMedium(); + @Setter + protected Function<BioMetabolite,String> getSharedIdFunction = BioEntity::getName; + @Setter + private String poolReactionPrefix = "poolReaction_"; + @Setter + private String sharedTransportPrefix = "transport_"; + @Setter + protected BiFunction<BioMetabolite, BioMetabolite, BioReaction> createLinkWithSharedPool = (m, pool) -> { + BioReaction r=new BioReaction(poolReactionPrefix+ m.getId()); + r.setReversible(true); + return r; + }; + @Setter + protected BiFunction<BioMetabolite, BioCompartment, BioReaction> createTransportWithSharedComp = (m, comp) -> { + BioReaction r=new BioReaction(sharedTransportPrefix+ m.getId()+"_to_"+comp.getId()); + r.setReversible(true); + return r; + }; + @Setter + @Getter + protected MetaEntityFactory entityFactory; + protected HashMap<BioCompartment,BioCompartment> fuseMap= new HashMap<>(); + protected Boolean keepGPR = false; + + /** + * enable a compartment to be shared between multiple organisms + * @param sc + */ + public void addNewSharedCompartment(BioCompartment sc) { + metaCompComposition.put(sc,new HashSet<>()); + } + + /** + * Fuse a sub-network's compartment into a meta-network's shared compartment. The former will be replaced by the latter during build. + * All compartment's component will be added to the shared compartment + * @param n + * @param c + * @param sc + */ + public void fuseCompartmentIntoSharedCompartment(BioNetwork n, BioCompartment c, BioCompartment sc) { + if(!metaCompComposition.containsKey(sc)) throw new IllegalArgumentException("Shared meta-compartment "+sc.getId()+" not found in network"); + fuseMap.put(c,sc); } - private void setMedium(){ - this.medium = new BioCompartment(UUID.randomUUID().toString(),"medium"); - this.addSharedCompartment(medium); + /** + * Bump a sub-network's compartment into a meta-network's shared compartment. For each compartment's component, + * a copy is created within the shared compartment + * @param n + * @param c + * @param sc + */ + public void bumpCompartmentIntoSharedCompartment(BioNetwork n, BioCompartment c, BioCompartment sc) { + BioCollection<BioMetabolite> toShare = n.getMetabolitesView().stream() + .filter(x -> n.getCompartmentsOf(x).contains(c)) + .collect(BioCollection::new,BioCollection::add,BioCollection::addAll); + this.exchangeWithSharedCompartment(n,c,toShare,sc); + } + + /** + * + * @param sourceNetwork the original subnetwork of the compound + * @param sourceCompartment the original compartment of the compound in the subnetwork + * @param metabolite the compound + * @param sc the target shared meta-compartment that will receive the compound + */ + public void exchangeWithSharedCompartment(BioNetwork sourceNetwork, BioCompartment sourceCompartment, BioMetabolite metabolite, BioCompartment sc) { + if(!metaCompComposition.containsKey(sc)) throw new IllegalArgumentException("Shared meta-compartment "+sc.getId()+" not found in network"); + metaCompComposition.get(sc).add(new MetaBioMetabolite(metabolite,sourceCompartment,sourceNetwork)); + } + + /** + * + * @param sourceNetwork the original subnetwork of the compounds + * @param sourceCompartment the original compartment of the compounds in the subnetwork + * @param metabolites the compounds + * @param sc the target shared meta-compartment that will receive the compounds + */ + public void exchangeWithSharedCompartment(BioNetwork sourceNetwork, BioCompartment sourceCompartment, BioCollection<BioMetabolite> metabolites, BioCompartment sc) { + if(!metaCompComposition.containsKey(sc)) throw new IllegalArgumentException("Shared meta-compartment "+sc.getId()+" not found in network"); + Set<MetaBioMetabolite> scCompo = metaCompComposition.get(sc); + for(BioMetabolite m : metabolites ){ + scCompo.add(new MetaBioMetabolite(m,sourceCompartment,sourceNetwork)); + } } @Override public void add(BioNetwork bn) { - super.add(bn); - this.addSharedCompartment(medium,this.networks.stream().toArray(BioNetwork[]::new)); + networks.add(bn); } - @Override - public void merge() { - //todo + protected BioNetwork initMetaNetwork(){ + this.metaboliteConversion = new HashMap<>(); + this.compartmentConversion = new HashMap<>(); + this.reactionConversion = new HashMap<>(); + this.proteinConversion = new HashMap<>(); + this.enzymeConversion = new HashMap<>(); + this.geneConversion = new HashMap<>(); + return new BioNetwork(); } - public void exchangeWithMedium(BioNetwork n, BioMetabolite m){ - this.exchangeWithSharedCompartment(n, m, medium); - }; + protected void populateMetaNetwork(BioNetwork meta){ + + for(BioNetwork sub : networks){ + + for(BioMetabolite e : sub.getMetabolitesView()){ + BioMetabolite e2 = entityFactory.createMetaEntity(e,sub); + meta.add(e2); + metaboliteConversion.put(e,e2); + } + for(BioCompartment c : sub.getCompartmentsView()){ + BioCompartment c2 = fuseMap.get(c); + if(c2==null){ + c2 = entityFactory.createMetaEntity(c,sub); + meta.add(c2); + } + compartmentConversion.put(c,c2); + BioCollection<BioMetabolite> content = c.getComponentsView().stream() + .filter((e) -> e.getClass().equals(BioMetabolite.class)) + .map(metaboliteConversion::get) + .collect(BioCollection::new,BioCollection::add,BioCollection::addAll); + + meta.affectToCompartment(c2, content); + } + + // Copy genes + if (keepGPR) { + //TODO case shared Genome + for (BioGene gene : sub.getGenesView()) { + BioGene newGene = entityFactory.createMetaEntity(gene,sub); + meta.add(newGene); + geneConversion.put(gene,newGene); + } + for (BioProtein protein : sub.getProteinsView()) { + BioProtein newProtein = entityFactory.createMetaEntity(protein,sub); + meta.add(newProtein); + proteinConversion.put(protein,newProtein); + + if (protein.getGene() != null) { + BioGene newGene = geneConversion.get(protein.getGene()); + meta.affectGeneProduct(newProtein, newGene); + } + } + for (BioEnzyme enzyme : sub.getEnzymesView()) { + + BioEnzyme newEnzyme = entityFactory.createMetaEntity(enzyme,sub); + meta.add(newEnzyme); + enzymeConversion.put(enzyme,newEnzyme); + + BioCollection<BioEnzymeParticipant> participants = enzyme.getParticipantsView(); + + for (BioEnzymeParticipant participant : participants) { + Double quantity = participant.getQuantity(); + + if (participant.getPhysicalEntity().getClass().equals(BioMetabolite.class)) { + BioMetabolite metabolite = (BioMetabolite) participant.getPhysicalEntity(); + BioMetabolite newMetabolite = metaboliteConversion.get(metabolite); + meta.affectSubUnit(newEnzyme, quantity, newMetabolite); + } else if (participant.getPhysicalEntity().getClass().equals(BioProtein.class)) { + BioProtein protein = (BioProtein) participant.getPhysicalEntity(); + BioProtein newProtein = proteinConversion.get(protein); + meta.affectSubUnit(newEnzyme, quantity, newProtein); + } + } + } + } + + for (BioReaction r : sub.getReactionsView()) { + + BioReaction newReaction = entityFactory.createMetaEntity(r,sub); + newReaction.setSpontaneous(r.isSpontaneous()); + newReaction.setReversible(r.isReversible()); + newReaction.setEcNumber(r.getEcNumber()); + + meta.add(newReaction); + reactionConversion.put(r,newReaction); + + // Copy lefts + for (BioReactant reactant : r.getLeftReactantsView()) { + BioMetabolite newMetabolite = metaboliteConversion.get(reactant.getMetabolite()); + BioCompartment newCpt = compartmentConversion.get(reactant.getLocation()); + Double sto = reactant.getQuantity(); + meta.affectLeft(newReaction, sto, newCpt, newMetabolite); + } + + // Copy rights + for (BioReactant reactant : r.getRightReactantsView()) { + BioMetabolite newMetabolite = metaboliteConversion.get(reactant.getMetabolite()); + BioCompartment newCpt = compartmentConversion.get(reactant.getLocation()); + Double sto = reactant.getQuantity(); + meta.affectRight(newReaction, sto, newCpt, newMetabolite); + } + + // Copy enzymes + if (keepGPR) { + for (BioEnzyme enzyme : r.getEnzymesView()) { + BioEnzyme newEnzyme = enzymeConversion.get(enzyme); + meta.affectEnzyme(newReaction, newEnzyme); + } + } + } + + for (BioPathway pathway : sub.getPathwaysView()) { + BioPathway newPathway = entityFactory.createMetaEntity(pathway,sub); + meta.add(newPathway); + // Add reactions into pathway + BioCollection<BioReaction> reactions = sub.getReactionsFromPathways(pathway); + + for (BioReaction reaction : reactions) { + BioReaction newReaction = reactionConversion.get(reaction); + meta.affectToPathway(newPathway, newReaction); + } + } + } + } + + public void setAliasPrefixes(Map<BioNetwork,String> aliases, String poolPrefix){ + this.setEntityFactory(new PrefixedMetaEntityFactory(aliases, poolPrefix)); + } @Override public BioNetwork build() { - //todo - return null; + BioNetwork meta = this.initMetaNetwork(); + //create shared compartment + this.initSharedComp(meta); + //add each subnetwork content + this.populateMetaNetwork(meta); + //add shared compartment components and exchanges + this.populateSharedComp(meta); + //link compounds in shared compartment + this.linkCompoundsInSharedComp(meta); + return meta; + } + protected void initSharedComp(BioNetwork meta) { + for (Map.Entry<BioCompartment, Set<MetaBioMetabolite>> compDescriptor : metaCompComposition.entrySet()) { + BioCompartment sc = compDescriptor.getKey(); + meta.addCompartment(sc); + } } + protected void populateSharedComp(BioNetwork meta){ + for(Map.Entry<BioCompartment, Set<MetaBioMetabolite>> compDescriptor : metaCompComposition.entrySet()){ + for(MetaBioMetabolite m : compDescriptor.getValue()){ + BioMetabolite m1 = metaboliteConversion.get(m.metabolite()); + BioMetabolite m2 = entityFactory.createSharedCompound(m1,compDescriptor.getKey()); + meta.add(m2); + meta.affectToCompartment(compDescriptor.getKey(),m2); + BioReaction t = createTransportWithSharedComp.apply(m1,compDescriptor.getKey()); + meta.add(t); + meta.affectLeft(t,1.0,compartmentConversion.get(m.sourceCompartment()),metaboliteConversion.get(m.metabolite())); + meta.affectLeft(t,1.0,compDescriptor.getKey(),m2); + } + } + } + + /** + * Links the source-specific metabolites representing the same compounds in the shared compartments, by creating a shared "pool" entity + * alongside their interconversion reactions. + * @param meta + */ + protected void linkCompoundsInSharedComp(BioNetwork meta) { + //loop over each shared compartment + for(BioCompartment sharedComp : metaCompComposition.keySet()){ + //retrieve all metabolite components that has been previously set, using whole compartment fusing or individual additions + BioCollection<BioMetabolite> content = sharedComp.getComponentsView().stream() + .filter((e) -> e.getClass().equals(BioMetabolite.class)) + .map(o -> (BioMetabolite)o) + .collect(BioCollection::new,BioCollection::add,BioCollection::addAll); + + //all entities that represent the same compounds from different source are grouped + Map<String, List<BioMetabolite>> compoundGroups = content.stream().collect(Collectors.groupingBy(getSharedIdFunction)); + + //for each group, create a "pool" metabolite that represent them + for(Map.Entry<String, List<BioMetabolite>> group : compoundGroups.entrySet()){ + BioMetabolite pool = this.entityFactory.createPoolCompound(group.getValue(),sharedComp); + meta.add(pool); + meta.affectToCompartment(sharedComp,pool); + //for each member of the group, create a reversible reaction linking them to their "pool" counterpart + for(BioMetabolite e : group.getValue()){ + BioReaction r = this.createLinkWithSharedPool.apply(e,pool); + meta.add(r); + meta.affectRight(r,1.0, sharedComp,e); + meta.affectLeft(r,1.0, sharedComp,pool); + } + } + } + } } diff --git a/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/MultiNetworkBuilder.java b/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/MultiNetworkBuilder.java index c17e2cadc..12f084efa 100644 --- a/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/MultiNetworkBuilder.java +++ b/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/MultiNetworkBuilder.java @@ -10,12 +10,11 @@ public interface MultiNetworkBuilder { */ public void add(BioNetwork bn); - public void merge(); - /** * create a new network which encompass all added networks * @return */ public BioNetwork build(); + } diff --git a/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/MultiOrganNetworkBuilder.java b/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/MultiOrganNetworkBuilder.java deleted file mode 100644 index ae4c1b699..000000000 --- a/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/MultiOrganNetworkBuilder.java +++ /dev/null @@ -1,57 +0,0 @@ -package fr.inrae.toulouse.metexplore.met4j_core.biodata.multinetwork; - -import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioCompartment; -import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioMetabolite; -import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioNetwork; -import fr.inrae.toulouse.metexplore.met4j_core.biodata.collection.BioCollection; - -import java.util.Arrays; -import java.util.HashMap; -import java.util.Map; -import java.util.stream.Collectors; - -public class MultiOrganNetworkBuilder extends AbstractMetaNetworkBuilder implements MultiNetworkBuilder{ - - @Override - public void merge() { - //TODO - } - - - @Override - public void addSharedCompartment(BioCompartment sc, BioNetwork... bn) { - super.addSharedCompartment(sc,bn); - } - - @Override - public void fuseCompartmentIntoSharedCompartment(BioNetwork n, BioCompartment c, BioCompartment sc) { - super.fuseCompartmentIntoSharedCompartment(n,c,sc); - } - - @Override - public void bumpCompartmentIntoSharedCompartment(BioNetwork n, BioCompartment c, BioCompartment sc) { - super.bumpCompartmentIntoSharedCompartment(n,c,sc); - } - - @Override - public void exchangeWithSharedCompartment(BioNetwork n, BioMetabolite m, BioCompartment sc) { - super.exchangeWithSharedCompartment(n,m,sc); - } - - @Override - public void exchangeWithSharedCompartment(BioNetwork n, BioCollection<BioMetabolite> m, BioCompartment sc) { - super.exchangeWithSharedCompartment(n,m,sc); - } - - @Override - public BioNetwork build() { - //todo - //create empty meta network - BioNetwork meta = new BioNetwork(); - //add each subnetwork content in dedicated compartment - this.populateMetaNetwork(meta); - //create shared compartment and the exchanged content - this.initSharedComp(meta); - return null; - } -} diff --git a/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/NestedNetworkBuilder.java b/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/NestedNetworkBuilder.java deleted file mode 100644 index aeca0c100..000000000 --- a/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/NestedNetworkBuilder.java +++ /dev/null @@ -1,43 +0,0 @@ -package fr.inrae.toulouse.metexplore.met4j_core.biodata.multinetwork; - -import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioCompartment; -import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioMetabolite; -import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioNetwork; - -public class NestedNetworkBuilder extends AbstractMetaNetworkBuilder implements MultiNetworkBuilder{ - - private BioNetwork superNet; - private BioCompartment superNetComp; - - public NestedNetworkBuilder(BioNetwork superNetwork){ - setSuperNetwork(superNetwork); - } - - private void setSuperNetwork(BioNetwork bn){ - superNet=bn; - this.superNetComp = new BioCompartment(bn.getId()); - this.addSharedCompartment(superNetComp,superNet); - } - - @Override - public void add(BioNetwork bn) { - super.add(bn); - this.addSharedCompartment(superNetComp,this.networks.stream().toArray(BioNetwork[]::new)); - } - - @Override - public void merge() { - //todo - } - - public void exchangeWithSuperNetwork(BioNetwork n, BioMetabolite m){ - this.exchangeWithSharedCompartment(n, m, superNetComp); - }; - - @Override - public BioNetwork build() { - //todo - return null; - } - -} diff --git a/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/PanNetworkBuilder.java b/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/PanNetworkBuilder.java deleted file mode 100644 index 346f71cbf..000000000 --- a/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/PanNetworkBuilder.java +++ /dev/null @@ -1,23 +0,0 @@ -package fr.inrae.toulouse.metexplore.met4j_core.biodata.multinetwork; - -import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioMetabolite; -import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioNetwork; -import fr.inrae.toulouse.metexplore.met4j_core.biodata.collection.BioCollection; - -public class PanNetworkBuilder implements MultiNetworkBuilder { - @Override - public void add(BioNetwork bn) { - //todo - } - - @Override - public void merge() { - //todo - } - - @Override - public BioNetwork build() { - //todo - return null; - } -} diff --git a/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/PrefixedMetaEntityFactory.java b/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/PrefixedMetaEntityFactory.java new file mode 100644 index 000000000..3137021eb --- /dev/null +++ b/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/PrefixedMetaEntityFactory.java @@ -0,0 +1,86 @@ +package fr.inrae.toulouse.metexplore.met4j_core.biodata.multinetwork; + +import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioCompartment; +import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioEntity; +import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioMetabolite; +import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioNetwork; +import lombok.SneakyThrows; + +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.function.BiFunction; +import java.util.function.Function; + +public class PrefixedMetaEntityFactory implements MetaEntityFactory { + + Map<BioNetwork,String> sourcePrefixMap; + String poolPrefix; + + public PrefixedMetaEntityFactory(Map<BioNetwork,String> sourcePrefixMap, String poolPrefix){ + this.sourcePrefixMap=sourcePrefixMap; + this.poolPrefix=poolPrefix; + } + + /** + * create prefix-id from network alias + */ + public BiFunction<String, BioNetwork, String> addSourcePrefix = (id, bn) -> sourcePrefixMap.get(bn)+"_"+id; + + /** + * create sharedCompartment-suffix id + */ + public BiFunction<String, BioCompartment, String> addCompSuffix = (id, comp) -> id+"_"+comp.getId(); + public BiFunction<String, BioCompartment, String> addCompPreffix = (id, comp) -> comp.getId()+"_"+id; + + + /** + * remove prefix-id from network alias + */ + public Function<String, String> removeSourceSuffix = id -> { + for(String s : sourcePrefixMap.values()) { + id = id.replaceAll("^" + s + "_",""); + }; + return id; + }; + + /** + * create pool-prefix id + */ + public Function<String, String> addPoolFlag = (id) -> poolPrefix+"_"+id; + + + @SneakyThrows + @Override + public <E extends BioEntity> E createMetaEntity(E originalEntity, BioNetwork source) { + return newEntityInstance(originalEntity, this.addSourcePrefix.apply(originalEntity.getId(),source)); + } + + @SneakyThrows + @Override + public BioMetabolite createSharedCompound(BioMetabolite entity, BioCompartment sharedCompartment) { + return newEntityInstance(entity, this.addCompSuffix.apply(entity.getId(),sharedCompartment)); + } + + @SneakyThrows + @Override + public BioMetabolite createPoolCompound(Collection<BioMetabolite> entities, BioCompartment sharedCompartment) { + BioMetabolite entity = entities.iterator().next(); + return newEntityInstance(entity, removeSourceSuffix + .andThen(s -> addCompPreffix.apply(s,sharedCompartment)) + .andThen(addPoolFlag) + .apply(entity.getId())); + } + + private static <E extends BioEntity> E newEntityInstance(E entity, String newId) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException { + E newEntity = (E) entity.getClass().getDeclaredConstructor(String.class).newInstance(newId); + newEntity.setName(entity.getName()); + newEntity.setSynonyms(new ArrayList<>(entity.getSynonyms())); + newEntity.setComment(entity.getComment()); + newEntity.setRefs(new HashMap<>(entity.getRefs())); + newEntity.setAttributes(new HashMap<>(entity.getAttributes())); + return newEntity; + } +} diff --git a/met4j-core/src/test/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/TestMetaNetworkBuilder.java b/met4j-core/src/test/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/TestMetaNetworkBuilder.java new file mode 100644 index 000000000..75a02f9fb --- /dev/null +++ b/met4j-core/src/test/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/TestMetaNetworkBuilder.java @@ -0,0 +1,185 @@ +package fr.inrae.toulouse.metexplore.met4j_core.biodata.multinetwork; + +import fr.inrae.toulouse.metexplore.met4j_core.biodata.*; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.util.HashMap; + +import static org.junit.Assert.*; + +public class TestMetaNetworkBuilder { + + + public static BioNetwork bn1, bn2, bn3, bn4; + public static BioMetabolite a1,b1,c1,c1ex,c2,c2ex,d3, d3ex, f3, d4, d4ex; + public static BioCompartment co1in, co1ex, co2in, co2ex, co3in, co3ex,co4in, co4ex,medium,medium2; + public static BioReaction r1, r3, tc1, tc2, td3,td4; + + + public static BioNetwork initBump() { + HashMap<BioNetwork,String> alias = new HashMap<>(); + alias.put(bn1,"model1"); + alias.put(bn2,"model2"); + alias.put(bn3,"model3"); + alias.put(bn4,"model4"); + medium=new BioCompartment("medium"); + medium2=new BioCompartment("medium2"); + CommunityNetworkBuilder builder = new CommunityNetworkBuilder(medium); + builder.addNewSharedCompartment(medium2); + builder.setEntityFactory(new PrefixedMetaEntityFactory(alias,"pool")); + builder.add(bn1); + builder.add(bn2); + builder.add(bn3); + builder.add(bn4); + builder.bumpCompartmentIntoSharedCompartment(bn1,co1ex,medium); + builder.bumpCompartmentIntoSharedCompartment(bn2,co2ex,medium); + builder.bumpCompartmentIntoSharedCompartment(bn3,co3ex,medium); + builder.bumpCompartmentIntoSharedCompartment(bn4,co4ex,medium2); + builder.bumpCompartmentIntoSharedCompartment(bn4,co4ex,medium); + return builder.build(); + } + + public static BioNetwork initFuse() { + HashMap<BioNetwork,String> alias = new HashMap<>(); + alias.put(bn1,"model1"); + alias.put(bn2,"model2"); + alias.put(bn3,"model3"); + alias.put(bn4,"model4"); + medium=new BioCompartment("medium"); + medium2=new BioCompartment("medium2"); + CommunityNetworkBuilder builder = new CommunityNetworkBuilder(medium); + builder.addNewSharedCompartment(medium2); + builder.setEntityFactory(new PrefixedMetaEntityFactory(alias,"pool")); + builder.add(bn1,co1ex); + builder.add(bn2,co2ex); + builder.add(bn3,co3ex); + builder.add(bn4); + builder.fuseCompartmentIntoSharedCompartment(bn4,co4ex,medium2); + return builder.build(); + } + + @BeforeClass + public static void beforeClass() { + bn1 = new BioNetwork("bn1"); + bn2 = new BioNetwork("bn2"); + bn3 = new BioNetwork("bn3"); + bn4 = new BioNetwork("bn4"); + a1 = new BioMetabolite("a_in","a"); + b1 = new BioMetabolite("b_in","b"); + c1 = new BioMetabolite("c_in","c"); + c1ex = new BioMetabolite("c_ex","c"); + r1 = new BioReaction("r1"); + tc1 = new BioReaction("tc"); + co1in = new BioCompartment("in"); + co1ex = new BioCompartment("ex"); + bn1.add(a1,b1,c1,c1ex,r1,tc1,co1in,co1ex); + bn1.affectToCompartment(co1in,a1,b1,c1); + bn1.affectToCompartment(co1ex,c1ex); + bn1.affectLeft(r1,1.0,co1in,a1); + bn1.affectLeft(r1,1.0,co1in,b1); + bn1.affectRight(r1,2.0,co1in,c1); + bn1.affectLeft(tc1,1.0,co1in,c1); + bn1.affectRight(tc1,1.0,co1ex,c1ex); + c2 = new BioMetabolite("c_in","c"); + c2ex = new BioMetabolite("c_ex","c"); + tc2 = new BioReaction("tc"); + co2in = new BioCompartment("in"); + co2ex = new BioCompartment("ex"); + bn2.add(c2,c2ex,tc2,co2in,co2ex); + bn2.affectToCompartment(co2in,c2); + bn2.affectToCompartment(co2ex,c2ex); + bn2.affectLeft(tc2,1.0,co2in,c2); + bn2.affectRight(tc2,1.0,co2ex,c2ex); + d3ex = new BioMetabolite("d_ex","d"); + d3 = new BioMetabolite("d_in","d"); + f3 = new BioMetabolite("f_in","f"); + r3 = new BioReaction("r2"); + td3 = new BioReaction("td"); + co3in = new BioCompartment("in"); + co3ex = new BioCompartment("ex"); + bn3.add(d3ex,d3,f3,r3,td3,co3in,co3ex); + bn3.affectToCompartment(co3in,d3,f3); + bn3.affectToCompartment(co3ex,d3ex); + bn3.affectLeft(td3,1.0,co3in,d3); + bn3.affectRight(td3,1.0,co3ex,d3ex); + bn3.affectLeft(r3,1.0,co3in,d3); + bn3.affectRight(r3,1.0,co3in,f3); + d4 = new BioMetabolite("d_in","d"); + d4ex = new BioMetabolite("d_ex","d"); + td4 = new BioReaction("td"); + co4in = new BioCompartment("in"); + co4ex = new BioCompartment("ex"); + bn4.add(d4,d4ex,td4,co4in,co4ex); + bn4.affectToCompartment(co4in,d4); + bn4.affectToCompartment(co4ex,d4ex); + bn4.affectLeft(td4,1.0,co4in,d4); + bn4.affectRight(td4,1.0,co4ex,d4ex); + } + + @Test + public void testCompoundsFuse(){ + BioNetwork meta = initFuse(); + assertEquals(14,meta.getMetabolitesView().size()); + assertNotNull(meta.getMetabolite("model1_a_in")); + assertNotNull(meta.getMetabolite("model1_c_in")); + assertNotNull(meta.getMetabolite("model1_c_ex")); + assertNotNull(meta.getMetabolite("model2_c_ex")); + assertNotNull(meta.getMetabolite("model2_c_in")); + + assertNotNull(meta.getMetabolite("pool_medium_c_ex")); + assertNotNull(meta.getMetabolite("pool_medium_d_ex")); + assertNotNull(meta.getMetabolite("pool_medium2_d_ex")); + } + + @Test + public void testReactionsFuse() { + BioNetwork meta = initFuse(); + assertEquals(10, meta.getReactionsView().size()); + assertNotNull(meta.getReaction("poolReaction_model2_c_ex")); + assertNotNull(meta.getReaction("poolReaction_model1_c_ex")); + assertNotNull(meta.getReaction("poolReaction_model3_d_ex")); + } + + @Test + public void testCompartmentFuse(){ + BioNetwork meta = initFuse(); + assertEquals(6,meta.getCompartmentsView().size()); + } + + + @Test + public void testCompoundsBump(){ + BioNetwork meta = initBump(); + assertEquals(19,meta.getMetabolitesView().size()); + assertNotNull(meta.getMetabolite("model1_a_in")); + assertNotNull(meta.getMetabolite("model1_c_in")); + assertNotNull(meta.getMetabolite("model1_c_ex")); + assertNotNull(meta.getMetabolite("model2_c_ex")); + assertNotNull(meta.getMetabolite("model2_c_in")); + + assertNotNull(meta.getMetabolite("pool_medium_c_ex_medium")); + assertNotNull(meta.getMetabolite("pool_medium_d_ex_medium")); + assertNotNull(meta.getMetabolite("pool_medium2_d_ex_medium2")); + } + + @Test + public void testReactionsBump() { + BioNetwork meta = initBump(); + assertEquals(16, meta.getReactionsView().size()); + assertNotNull(meta.getReaction("poolReaction_model2_c_ex_medium")); + assertNotNull(meta.getReaction("poolReaction_model1_c_ex_medium")); + assertNotNull(meta.getReaction("poolReaction_model3_d_ex_medium")); + assertNotNull(meta.getReaction("transport_model1_c_ex_to_medium")); + assertNotNull(meta.getReaction("poolReaction_model4_d_ex_medium2")); + assertNotNull(meta.getReaction("poolReaction_model4_d_ex_medium")); + assertNotNull(meta.getReaction("transport_model4_d_ex_to_medium2")); + assertNotNull(meta.getReaction("transport_model4_d_ex_to_medium")); + } + + @Test + public void testCompartmentBump(){ + BioNetwork meta = initBump(); + assertEquals(10,meta.getCompartmentsView().size()); + } +} -- GitLab From 168bf2c6f61555711a38857a48649133bea7df2c Mon Sep 17 00:00:00 2001 From: cfrainay <clement.frainay@inrae.fr> Date: Wed, 18 Sep 2024 00:03:18 +0200 Subject: [PATCH 03/17] app stub --- .../reconstruction/CreateMetaNetwork.java | 173 ++++++++++++++++++ 1 file changed, 173 insertions(+) create mode 100644 met4j-toolbox/src/main/java/fr/inrae/toulouse/metexplore/met4j_toolbox/reconstruction/CreateMetaNetwork.java diff --git a/met4j-toolbox/src/main/java/fr/inrae/toulouse/metexplore/met4j_toolbox/reconstruction/CreateMetaNetwork.java b/met4j-toolbox/src/main/java/fr/inrae/toulouse/metexplore/met4j_toolbox/reconstruction/CreateMetaNetwork.java new file mode 100644 index 000000000..d5767c203 --- /dev/null +++ b/met4j-toolbox/src/main/java/fr/inrae/toulouse/metexplore/met4j_toolbox/reconstruction/CreateMetaNetwork.java @@ -0,0 +1,173 @@ +package fr.inrae.toulouse.metexplore.met4j_toolbox.reconstruction; + +import fr.inrae.toulouse.metexplore.met4j_core.biodata.*; +import fr.inrae.toulouse.metexplore.met4j_core.biodata.multinetwork.CommunityNetworkBuilder; +import fr.inrae.toulouse.metexplore.met4j_core.biodata.multinetwork.PrefixedMetaEntityFactory; +import fr.inrae.toulouse.metexplore.met4j_io.jsbml.reader.JsbmlReader; +import fr.inrae.toulouse.metexplore.met4j_io.jsbml.reader.Met4jSbmlReaderException; +import fr.inrae.toulouse.metexplore.met4j_io.jsbml.writer.JsbmlWriter; +import fr.inrae.toulouse.metexplore.met4j_io.jsbml.writer.Met4jSbmlWriterException; +import fr.inrae.toulouse.metexplore.met4j_toolbox.generic.AbstractMet4jApplication; +import fr.inrae.toulouse.metexplore.met4j_toolbox.generic.annotations.EnumFormats; +import fr.inrae.toulouse.metexplore.met4j_toolbox.generic.annotations.EnumParameterTypes; +import fr.inrae.toulouse.metexplore.met4j_toolbox.generic.annotations.Format; +import fr.inrae.toulouse.metexplore.met4j_toolbox.generic.annotations.ParameterType; +import org.kohsuke.args4j.Option; + +import java.util.HashMap; +import java.util.NoSuchElementException; +import java.util.Objects; +import java.util.UUID; +import java.util.function.Function; + +import static fr.inrae.toulouse.metexplore.met4j_toolbox.generic.annotations.EnumFormats.Sbml; +import static fr.inrae.toulouse.metexplore.met4j_toolbox.generic.annotations.EnumParameterTypes.InputFile; +import static fr.inrae.toulouse.metexplore.met4j_toolbox.reconstruction.CreateMetaNetwork.strategy.*; + +public class CreateMetaNetwork extends AbstractMet4jApplication { + + //arguments + @Format(name = Sbml) + @ParameterType(name = InputFile) + @Option(name = "-n1", aliases = {"--network1"}, usage = "input SBML file: path to first network, in sbml format.", required = true) + public String sbml1FilePath; + @Option(name = "-n2", aliases = {"--network2"}, usage = "input SBML file: path to second network, in sbml format.", required = true) + public String sbml2FilePath; + + @Option(name = "-n1ex", aliases = {"--external1"}, usage = "external compartment identifier in first network.", required = true) + public String external1; + @Option(name = "-n2ex", aliases = {"--external2"}, usage = "external compartment identifier in second network.", required = true) + public String external2; + + @Option(name = "-n1px", aliases = {"--n1prefix"}, usage = "prefix that will be added to first network's entities identifiers", required = false) + public String n1prefix = "Net1_"; + @Option(name = "-n2px", aliases = {"--n2prefix"}, usage = "prefix that will be added to second network's entities identifiers", required = false) + public String n2prefix = "Net2_"; + + @Option(name = "-k", aliases = {"--keepCompartment"}, usage = "keep the original external compartments in the meta-network, otherwise, they will be fused into the new shared external compartment", required = false) + public boolean keepCompartment = false; + + enum strategy {by_metanetx, by_name, by_id} + @Option(name = "-mc", aliases = {"--mergingCriterion"}, usage = "field used to identify the same metabolites across the two different networks. " + + "\"by_name\"/\"by_id\" can be used if names/identifiers are consistent and unambiguous across source models, \"by_metanetx\" can be used if models contains MetaNetX identifiers in annotation field using standard miriam format.") + public CreateMetaNetwork.strategy mergingCriterion = by_name; + + @ParameterType(name = EnumParameterTypes.OutputFile) + @Format(name = EnumFormats.Sbml) + @Option(name = "-o", usage = "output meta-network SBML file", required = true) + public String outputPath = null; + + public static void main(String[] args) throws Met4jSbmlWriterException { + CreateMetaNetwork app = new CreateMetaNetwork(); + app.parseArguments(args); + app.run(); + } + + public void run() throws Met4jSbmlWriterException { + + if(Objects.equals(this.n1prefix, this.n2prefix)){ + System.err.println("Error: prefixes must be different"); + System.exit(1); + } + + //import networks + System.out.print("Importing network 1..."); + JsbmlReader reader = new JsbmlReader(this.sbml1FilePath); + BioNetwork network1 = null; + try { + network1 = reader.read(); + } catch (Met4jSbmlReaderException e) { + System.err.println("Error while reading the first SBML file"); + System.err.println(e.getMessage()); + System.exit(1); + } + BioCompartment co1ex = network1.getCompartment(external1); + if(co1ex==null){ + System.err.println("Error: external compartment " + external1 + " not found in network 1"); + System.exit(1); + } + System.out.println(" Done."); + + + System.out.print("Importing network 2..."); + reader = new JsbmlReader(this.sbml2FilePath); + BioNetwork network2 = null; + try { + network2 = reader.read(); + } catch (Met4jSbmlReaderException e) { + System.err.println("Error while reading the second SBML file"); + System.err.println(e.getMessage()); + System.exit(1); + } + BioCompartment co2ex = network2.getCompartment(external2); + if(co2ex==null){ + System.err.println("Error: external compartment " + external2 + " not found in network 2"); + System.exit(1); + } + System.out.println(" Done."); + + System.out.print("Creating meta-network..."); + //setup + BioCompartment medium=new BioCompartment("medium"); medium.setName("medium"); + HashMap<BioNetwork,String> alias = new HashMap<>(); + alias.put(network1,n1prefix);alias.put(network2,n2prefix); + CommunityNetworkBuilder builder = new CommunityNetworkBuilder(medium); + builder.setEntityFactory(new PrefixedMetaEntityFactory(alias,"pool")); + Function<BioMetabolite, String> getSharedIdFunction; + switch (mergingCriterion) { + case by_metanetx: + getSharedIdFunction = x -> { + try { + BioRef r = x.getRefs("metanetx.chemical").iterator().next(); + return r.getId(); + } catch (NoSuchElementException|java.lang.NullPointerException e) { + return "unknown_"+UUID.randomUUID(); + } + }; + break; + case by_id: + getSharedIdFunction = BioEntity::getId; + break; + case by_name: + getSharedIdFunction = BioEntity::getName; + break; + default: + throw new IllegalArgumentException("Invalid merging criterion: " + mergingCriterion); + } + builder.setGetSharedIdFunction(getSharedIdFunction); + builder.add(network1); + builder.add(network2); + + //build meta-network + if(!keepCompartment){ + builder.fuseCompartmentIntoSharedCompartment(network1,co1ex,medium); + builder.fuseCompartmentIntoSharedCompartment(network2,co2ex,medium); + }else{ + builder.bumpCompartmentIntoSharedCompartment(network1,co1ex,medium); + builder.bumpCompartmentIntoSharedCompartment(network2,co2ex,medium); + } + BioNetwork metaNetwork = builder.build(); + System.out.println(" Done."); + + //export the meta-network + System.out.print("Exporting MetaNetwork..."); + new JsbmlWriter(outputPath,metaNetwork).write(); + System.out.println(" Done."); + + } + + @Override + public String getLabel() {return this.getClass().getSimpleName();} + + @Override + public String getLongDescription() { + return "Create a Meta-Network from two sub-networks in SBML format."; + } + + @Override + public String getShortDescription() { + return "Create a Meta-Network from two sub-networks in SBML format. A meta-network is a single model which contains several sub-networks that remains individualized within" + + "the meta-network (as opposed to models fusion), but which can share some of their components with " + + "other sub-networks through a shared \"medium\" compartment."; + } +} -- GitLab From 7ba7f81adb038d8b10ce1ecdc271765740fd38a1 Mon Sep 17 00:00:00 2001 From: cfrainay <clement.frainay@inrae.fr> Date: Fri, 20 Sep 2024 17:20:30 +0200 Subject: [PATCH 04/17] refactoring, isolate builder init --- .../reconstruction/CreateMetaNetwork.java | 45 ++++++++++--------- 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/met4j-toolbox/src/main/java/fr/inrae/toulouse/metexplore/met4j_toolbox/reconstruction/CreateMetaNetwork.java b/met4j-toolbox/src/main/java/fr/inrae/toulouse/metexplore/met4j_toolbox/reconstruction/CreateMetaNetwork.java index d5767c203..fa81d37d7 100644 --- a/met4j-toolbox/src/main/java/fr/inrae/toulouse/metexplore/met4j_toolbox/reconstruction/CreateMetaNetwork.java +++ b/met4j-toolbox/src/main/java/fr/inrae/toulouse/metexplore/met4j_toolbox/reconstruction/CreateMetaNetwork.java @@ -111,6 +111,29 @@ public class CreateMetaNetwork extends AbstractMet4jApplication { BioCompartment medium=new BioCompartment("medium"); medium.setName("medium"); HashMap<BioNetwork,String> alias = new HashMap<>(); alias.put(network1,n1prefix);alias.put(network2,n2prefix); + CommunityNetworkBuilder builder = initMetaNetworkBuilder(medium, alias); + builder.add(network1); + builder.add(network2); + + //build meta-network + if(!keepCompartment){ + builder.fuseCompartmentIntoSharedCompartment(network1,co1ex,medium); + builder.fuseCompartmentIntoSharedCompartment(network2,co2ex,medium); + }else{ + builder.bumpCompartmentIntoSharedCompartment(network1,co1ex,medium); + builder.bumpCompartmentIntoSharedCompartment(network2,co2ex,medium); + } + BioNetwork metaNetwork = builder.build(); + System.out.println(" Done."); + + //export the meta-network + System.out.print("Exporting MetaNetwork..."); + new JsbmlWriter(outputPath,metaNetwork).write(); + System.out.println(" Done."); + + } + + private CommunityNetworkBuilder initMetaNetworkBuilder(BioCompartment medium, HashMap<BioNetwork, String> alias) { CommunityNetworkBuilder builder = new CommunityNetworkBuilder(medium); builder.setEntityFactory(new PrefixedMetaEntityFactory(alias,"pool")); Function<BioMetabolite, String> getSharedIdFunction; @@ -120,7 +143,7 @@ public class CreateMetaNetwork extends AbstractMet4jApplication { try { BioRef r = x.getRefs("metanetx.chemical").iterator().next(); return r.getId(); - } catch (NoSuchElementException|java.lang.NullPointerException e) { + } catch (NoSuchElementException | NullPointerException e) { return "unknown_"+UUID.randomUUID(); } }; @@ -135,25 +158,7 @@ public class CreateMetaNetwork extends AbstractMet4jApplication { throw new IllegalArgumentException("Invalid merging criterion: " + mergingCriterion); } builder.setGetSharedIdFunction(getSharedIdFunction); - builder.add(network1); - builder.add(network2); - - //build meta-network - if(!keepCompartment){ - builder.fuseCompartmentIntoSharedCompartment(network1,co1ex,medium); - builder.fuseCompartmentIntoSharedCompartment(network2,co2ex,medium); - }else{ - builder.bumpCompartmentIntoSharedCompartment(network1,co1ex,medium); - builder.bumpCompartmentIntoSharedCompartment(network2,co2ex,medium); - } - BioNetwork metaNetwork = builder.build(); - System.out.println(" Done."); - - //export the meta-network - System.out.print("Exporting MetaNetwork..."); - new JsbmlWriter(outputPath,metaNetwork).write(); - System.out.println(" Done."); - + return builder; } @Override -- GitLab From e565319c889beaebe59aa9df503a9c5e7b238387 Mon Sep 17 00:00:00 2001 From: cfrainay <clement.frainay@inrae.fr> Date: Tue, 24 Sep 2024 18:10:54 +0200 Subject: [PATCH 05/17] enable iterative metanetwork building --- .../reconstruction/CreateMetaNetwork.java | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/met4j-toolbox/src/main/java/fr/inrae/toulouse/metexplore/met4j_toolbox/reconstruction/CreateMetaNetwork.java b/met4j-toolbox/src/main/java/fr/inrae/toulouse/metexplore/met4j_toolbox/reconstruction/CreateMetaNetwork.java index fa81d37d7..7815cf68f 100644 --- a/met4j-toolbox/src/main/java/fr/inrae/toulouse/metexplore/met4j_toolbox/reconstruction/CreateMetaNetwork.java +++ b/met4j-toolbox/src/main/java/fr/inrae/toulouse/metexplore/met4j_toolbox/reconstruction/CreateMetaNetwork.java @@ -47,6 +47,9 @@ public class CreateMetaNetwork extends AbstractMet4jApplication { @Option(name = "-k", aliases = {"--keepCompartment"}, usage = "keep the original external compartments in the meta-network, otherwise, they will be fused into the new shared external compartment", required = false) public boolean keepCompartment = false; + @Option(name = "-n1meta", aliases = {"--firstAsMeta"}, usage = "Treat first network as meta-network, allowing more than two sub-models with iterative fusions. This will overwrite shared compartment and pool compounds (which must follow the \"pool_\" prefix convention) and will ignore --n1prefix argument", required = false) + public boolean firstIsMeta = false; + enum strategy {by_metanetx, by_name, by_id} @Option(name = "-mc", aliases = {"--mergingCriterion"}, usage = "field used to identify the same metabolites across the two different networks. " + "\"by_name\"/\"by_id\" can be used if names/identifiers are consistent and unambiguous across source models, \"by_metanetx\" can be used if models contains MetaNetX identifiers in annotation field using standard miriam format.") @@ -86,6 +89,14 @@ public class CreateMetaNetwork extends AbstractMet4jApplication { System.err.println("Error: external compartment " + external1 + " not found in network 1"); System.exit(1); } + if(firstIsMeta){ + n1prefix = ""; + network1.removeOnCascade(network1 + .getCompartment(external1) + .getComponentsView().stream() + .filter(e -> e instanceof BioMetabolite) + .filter(m -> m.getId().startsWith("pool_")).toArray(BioEntity[]::new)); + } System.out.println(" Done."); @@ -120,7 +131,11 @@ public class CreateMetaNetwork extends AbstractMet4jApplication { builder.fuseCompartmentIntoSharedCompartment(network1,co1ex,medium); builder.fuseCompartmentIntoSharedCompartment(network2,co2ex,medium); }else{ - builder.bumpCompartmentIntoSharedCompartment(network1,co1ex,medium); + if(firstIsMeta) { + builder.fuseCompartmentIntoSharedCompartment(network1, co1ex, medium); + }else{ + builder.bumpCompartmentIntoSharedCompartment(network1, co1ex, medium); + } builder.bumpCompartmentIntoSharedCompartment(network2,co2ex,medium); } BioNetwork metaNetwork = builder.build(); -- GitLab From c4c0d01452c2891adfc44398de8fee94acc0ccce Mon Sep 17 00:00:00 2001 From: cfrainay <clement.frainay@inrae.fr> Date: Fri, 4 Oct 2024 14:46:57 +0200 Subject: [PATCH 06/17] create exchange reaction, suffix separator as parameter --- .../multinetwork/MetaNetworkBuilder.java | 18 ++++++++++++++++++ .../PrefixedMetaEntityFactory.java | 11 ++++++----- .../reconstruction/CreateMetaNetwork.java | 16 +++++++++++----- 3 files changed, 35 insertions(+), 10 deletions(-) diff --git a/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/MetaNetworkBuilder.java b/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/MetaNetworkBuilder.java index b5b5b2958..7d4da1b58 100644 --- a/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/MetaNetworkBuilder.java +++ b/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/MetaNetworkBuilder.java @@ -34,11 +34,21 @@ public class MetaNetworkBuilder implements MultiNetworkBuilder{ @Setter private String sharedTransportPrefix = "transport_"; @Setter + private String exchangeReactionPrefix = "exchange_"; + @Setter protected BiFunction<BioMetabolite, BioMetabolite, BioReaction> createLinkWithSharedPool = (m, pool) -> { BioReaction r=new BioReaction(poolReactionPrefix+ m.getId()); r.setReversible(true); return r; }; + + @Setter + protected Function<BioMetabolite, BioReaction> createPoolExchangeReaction = (pool) -> { + BioReaction r=new BioReaction(exchangeReactionPrefix+pool.getId()); + r.setReversible(true); + return r; + }; + @Setter protected BiFunction<BioMetabolite, BioCompartment, BioReaction> createTransportWithSharedComp = (m, comp) -> { BioReaction r=new BioReaction(sharedTransportPrefix+ m.getId()+"_to_"+comp.getId()); @@ -50,6 +60,8 @@ public class MetaNetworkBuilder implements MultiNetworkBuilder{ protected MetaEntityFactory entityFactory; protected HashMap<BioCompartment,BioCompartment> fuseMap= new HashMap<>(); protected Boolean keepGPR = false; + @Setter + public Boolean addExchangeReaction = true; /** * enable a compartment to be shared between multiple organisms @@ -310,6 +322,12 @@ public class MetaNetworkBuilder implements MultiNetworkBuilder{ meta.affectRight(r,1.0, sharedComp,e); meta.affectLeft(r,1.0, sharedComp,pool); } + //if option selected, add exchange reaction to the pool for flux modeling + if(addExchangeReaction){ + BioReaction r = this.createPoolExchangeReaction.apply(pool); + meta.add(r); + meta.affectLeft(r,1.0, sharedComp,pool); + } } } } diff --git a/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/PrefixedMetaEntityFactory.java b/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/PrefixedMetaEntityFactory.java index 3137021eb..2b26d4964 100644 --- a/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/PrefixedMetaEntityFactory.java +++ b/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/PrefixedMetaEntityFactory.java @@ -18,6 +18,7 @@ public class PrefixedMetaEntityFactory implements MetaEntityFactory { Map<BioNetwork,String> sourcePrefixMap; String poolPrefix; + String sep = ""; public PrefixedMetaEntityFactory(Map<BioNetwork,String> sourcePrefixMap, String poolPrefix){ this.sourcePrefixMap=sourcePrefixMap; @@ -27,13 +28,13 @@ public class PrefixedMetaEntityFactory implements MetaEntityFactory { /** * create prefix-id from network alias */ - public BiFunction<String, BioNetwork, String> addSourcePrefix = (id, bn) -> sourcePrefixMap.get(bn)+"_"+id; + public BiFunction<String, BioNetwork, String> addSourcePrefix = (id, bn) -> sourcePrefixMap.get(bn)+sep+id; /** * create sharedCompartment-suffix id */ - public BiFunction<String, BioCompartment, String> addCompSuffix = (id, comp) -> id+"_"+comp.getId(); - public BiFunction<String, BioCompartment, String> addCompPreffix = (id, comp) -> comp.getId()+"_"+id; + public BiFunction<String, BioCompartment, String> addCompSuffix = (id, comp) -> id+sep+comp.getId(); + public BiFunction<String, BioCompartment, String> addCompPreffix = (id, comp) -> comp.getId()+sep+id; /** @@ -41,7 +42,7 @@ public class PrefixedMetaEntityFactory implements MetaEntityFactory { */ public Function<String, String> removeSourceSuffix = id -> { for(String s : sourcePrefixMap.values()) { - id = id.replaceAll("^" + s + "_",""); + id = id.replaceAll("^" + s + sep,""); }; return id; }; @@ -49,7 +50,7 @@ public class PrefixedMetaEntityFactory implements MetaEntityFactory { /** * create pool-prefix id */ - public Function<String, String> addPoolFlag = (id) -> poolPrefix+"_"+id; + public Function<String, String> addPoolFlag = (id) -> poolPrefix+sep+id; @SneakyThrows diff --git a/met4j-toolbox/src/main/java/fr/inrae/toulouse/metexplore/met4j_toolbox/reconstruction/CreateMetaNetwork.java b/met4j-toolbox/src/main/java/fr/inrae/toulouse/metexplore/met4j_toolbox/reconstruction/CreateMetaNetwork.java index 7815cf68f..50204fe75 100644 --- a/met4j-toolbox/src/main/java/fr/inrae/toulouse/metexplore/met4j_toolbox/reconstruction/CreateMetaNetwork.java +++ b/met4j-toolbox/src/main/java/fr/inrae/toulouse/metexplore/met4j_toolbox/reconstruction/CreateMetaNetwork.java @@ -22,7 +22,7 @@ import java.util.function.Function; import static fr.inrae.toulouse.metexplore.met4j_toolbox.generic.annotations.EnumFormats.Sbml; import static fr.inrae.toulouse.metexplore.met4j_toolbox.generic.annotations.EnumParameterTypes.InputFile; -import static fr.inrae.toulouse.metexplore.met4j_toolbox.reconstruction.CreateMetaNetwork.strategy.*; +import static fr.inrae.toulouse.metexplore.met4j_toolbox.reconstruction.CreateMetaNetwork.strategy.by_name; public class CreateMetaNetwork extends AbstractMet4jApplication { @@ -91,11 +91,15 @@ public class CreateMetaNetwork extends AbstractMet4jApplication { } if(firstIsMeta){ n1prefix = ""; - network1.removeOnCascade(network1 - .getCompartment(external1) + BioMetabolite[] pool1 = network1.getCompartment(external1) .getComponentsView().stream() .filter(e -> e instanceof BioMetabolite) - .filter(m -> m.getId().startsWith("pool_")).toArray(BioEntity[]::new)); + .filter(m -> m.getId().startsWith("pool_")) + .toArray(BioMetabolite[]::new); + for(BioMetabolite pool : pool1){ + network1.removeOnCascade(network1.getReactionsFromMetabolite(pool)); + } + network1.removeOnCascade(pool1); } System.out.println(" Done."); @@ -150,7 +154,9 @@ public class CreateMetaNetwork extends AbstractMet4jApplication { private CommunityNetworkBuilder initMetaNetworkBuilder(BioCompartment medium, HashMap<BioNetwork, String> alias) { CommunityNetworkBuilder builder = new CommunityNetworkBuilder(medium); - builder.setEntityFactory(new PrefixedMetaEntityFactory(alias,"pool")); + PrefixedMetaEntityFactory factory = new PrefixedMetaEntityFactory(alias,"pool_"); + factory.addCompSuffix = (id, comp) -> id+"_"+comp.getId(); + builder.setEntityFactory(factory); Function<BioMetabolite, String> getSharedIdFunction; switch (mergingCriterion) { case by_metanetx: -- GitLab From 762840f67bf6451a953915f6aadb5b881f509175 Mon Sep 17 00:00:00 2001 From: cfrainay <clement.frainay@inrae.fr> Date: Tue, 8 Oct 2024 17:34:38 +0200 Subject: [PATCH 07/17] add test + better handling of prefixed pool compounds --- .../multinetwork/MetaNetworkBuilder.java | 2 +- .../PrefixedMetaEntityFactory.java | 11 +- .../multinetwork/TestMetaNetworkBuilder.java | 108 +++++++++++++++++- 3 files changed, 114 insertions(+), 7 deletions(-) diff --git a/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/MetaNetworkBuilder.java b/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/MetaNetworkBuilder.java index 7d4da1b58..9c214f4b0 100644 --- a/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/MetaNetworkBuilder.java +++ b/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/MetaNetworkBuilder.java @@ -61,7 +61,7 @@ public class MetaNetworkBuilder implements MultiNetworkBuilder{ protected HashMap<BioCompartment,BioCompartment> fuseMap= new HashMap<>(); protected Boolean keepGPR = false; @Setter - public Boolean addExchangeReaction = true; + protected Boolean addExchangeReaction = true; /** * enable a compartment to be shared between multiple organisms diff --git a/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/PrefixedMetaEntityFactory.java b/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/PrefixedMetaEntityFactory.java index 2b26d4964..7cb874ebb 100644 --- a/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/PrefixedMetaEntityFactory.java +++ b/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/PrefixedMetaEntityFactory.java @@ -4,6 +4,7 @@ import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioCompartment; import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioEntity; import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioMetabolite; import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioNetwork; +import lombok.Setter; import lombok.SneakyThrows; import java.lang.reflect.InvocationTargetException; @@ -14,11 +15,15 @@ import java.util.Map; import java.util.function.BiFunction; import java.util.function.Function; +import static fr.inrae.toulouse.metexplore.met4j_core.utils.StringUtils.isVoid; + public class PrefixedMetaEntityFactory implements MetaEntityFactory { Map<BioNetwork,String> sourcePrefixMap; - String poolPrefix; - String sep = ""; + @Setter + protected String poolPrefix; + @Setter + protected String sep = "_"; public PrefixedMetaEntityFactory(Map<BioNetwork,String> sourcePrefixMap, String poolPrefix){ this.sourcePrefixMap=sourcePrefixMap; @@ -28,7 +33,7 @@ public class PrefixedMetaEntityFactory implements MetaEntityFactory { /** * create prefix-id from network alias */ - public BiFunction<String, BioNetwork, String> addSourcePrefix = (id, bn) -> sourcePrefixMap.get(bn)+sep+id; + public BiFunction<String, BioNetwork, String> addSourcePrefix = (id, bn) -> isVoid(sourcePrefixMap.get(bn)) ? id : sourcePrefixMap.get(bn)+sep+id; /** * create sharedCompartment-suffix id diff --git a/met4j-core/src/test/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/TestMetaNetworkBuilder.java b/met4j-core/src/test/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/TestMetaNetworkBuilder.java index 75a02f9fb..31d2bbd88 100644 --- a/met4j-core/src/test/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/TestMetaNetworkBuilder.java +++ b/met4j-core/src/test/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/TestMetaNetworkBuilder.java @@ -1,10 +1,16 @@ package fr.inrae.toulouse.metexplore.met4j_core.biodata.multinetwork; -import fr.inrae.toulouse.metexplore.met4j_core.biodata.*; +import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioCompartment; +import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioMetabolite; +import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioNetwork; +import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioReaction; import org.junit.BeforeClass; import org.junit.Test; +import java.util.Arrays; import java.util.HashMap; +import java.util.Set; +import java.util.stream.Collectors; import static org.junit.Assert.*; @@ -27,7 +33,10 @@ public class TestMetaNetworkBuilder { medium2=new BioCompartment("medium2"); CommunityNetworkBuilder builder = new CommunityNetworkBuilder(medium); builder.addNewSharedCompartment(medium2); - builder.setEntityFactory(new PrefixedMetaEntityFactory(alias,"pool")); + PrefixedMetaEntityFactory factory = new PrefixedMetaEntityFactory(alias,"pool"); + factory.setSep("_"); + builder.setEntityFactory(factory); + builder.setAddExchangeReaction(false); builder.add(bn1); builder.add(bn2); builder.add(bn3); @@ -50,7 +59,10 @@ public class TestMetaNetworkBuilder { medium2=new BioCompartment("medium2"); CommunityNetworkBuilder builder = new CommunityNetworkBuilder(medium); builder.addNewSharedCompartment(medium2); - builder.setEntityFactory(new PrefixedMetaEntityFactory(alias,"pool")); + PrefixedMetaEntityFactory factory = new PrefixedMetaEntityFactory(alias,"pool"); + factory.setSep("_"); + builder.setEntityFactory(factory); + builder.setAddExchangeReaction(false); builder.add(bn1,co1ex); builder.add(bn2,co2ex); builder.add(bn3,co3ex); @@ -59,6 +71,65 @@ public class TestMetaNetworkBuilder { return builder.build(); } + public static BioNetwork initFuseIncremental() { + HashMap<BioNetwork,String> alias = new HashMap<>(); + alias.put(bn1,"model1"); + alias.put(bn2,"model2"); + + BioCompartment medium0=new BioCompartment("medium"); + CommunityNetworkBuilder builder = new CommunityNetworkBuilder(medium0); + PrefixedMetaEntityFactory factory = new PrefixedMetaEntityFactory(alias,"pool"); + factory.setSep("_"); + builder.setEntityFactory(factory); + builder.setAddExchangeReaction(false); + builder.add(bn1,co1ex); + builder.add(bn2,co2ex); + BioNetwork firstIter = builder.build(); + + System.out.println(Arrays.toString(bn1.getMetabolitesView().stream().map(x -> x.getId()).toArray())); + System.out.println(Arrays.toString(bn1.getReactionsView().stream().map(x -> x.getId()).toArray())); + System.out.println("+"); + System.out.println(Arrays.toString(bn2.getMetabolitesView().stream().map(x -> x.getId()).toArray())); + System.out.println(Arrays.toString(bn2.getReactionsView().stream().map(x -> x.getId()).toArray())); + System.out.println("="); + System.out.println(Arrays.toString(firstIter.getMetabolitesView().stream().map(x -> x.getId()).toArray())); + System.out.println(Arrays.toString(firstIter.getReactionsView().stream().map(x -> x.getId()).toArray())); + + BioMetabolite[] pool1 = firstIter.getCompartment("medium") + .getComponentsView().stream() + .filter(e -> e instanceof BioMetabolite) + .filter(m -> m.getId().startsWith("pool_")) + .toArray(BioMetabolite[]::new); + for(BioMetabolite pool : pool1){ + firstIter.removeOnCascade(firstIter.getReactionsFromMetabolite(pool)); + } + firstIter.removeOnCascade(pool1); + + System.out.println("->"); + System.out.println(Arrays.toString(firstIter.getMetabolitesView().stream().map(x -> x.getId()).toArray())); + System.out.println(Arrays.toString(firstIter.getReactionsView().stream().map(x -> x.getId()).toArray())); + + medium=new BioCompartment("medium"); + medium2=new BioCompartment("medium2"); + builder = new CommunityNetworkBuilder(medium); + builder.addNewSharedCompartment(medium2); + alias = new HashMap<>(); + alias.put(firstIter,""); + alias.put(bn3,"model3"); + alias.put(bn4,"model4"); + builder.setEntityFactory(new PrefixedMetaEntityFactory(alias,"pool")); + builder.setAddExchangeReaction(false); + builder.add(firstIter,medium0); + builder.add(bn3,co3ex); + builder.add(bn4); + builder.fuseCompartmentIntoSharedCompartment(bn4,co4ex,medium2); + + BioNetwork output = builder.build(); + System.out.println(Arrays.toString(output.getMetabolitesView().stream().map(x -> x.getId()).toArray())); + System.out.println(Arrays.toString(output.getReactionsView().stream().map(x -> x.getId()).toArray())); + return output; + } + @BeforeClass public static void beforeClass() { bn1 = new BioNetwork("bn1"); @@ -147,6 +218,37 @@ public class TestMetaNetworkBuilder { assertEquals(6,meta.getCompartmentsView().size()); } + @Test + public void testCompoundsFuseIncremental(){ + BioNetwork meta = initFuseIncremental(); + assertEquals(14,meta.getMetabolitesView().size()); + assertNotNull(meta.getMetabolite("model1_a_in")); + assertNotNull(meta.getMetabolite("model1_c_in")); + assertNotNull(meta.getMetabolite("model1_c_ex")); + assertNotNull(meta.getMetabolite("model2_c_ex")); + assertNotNull(meta.getMetabolite("model2_c_in")); + + Set<String> metabolites = meta.getMetabolitesView().stream().map(x -> x.getId()).collect(Collectors.toSet()); + assertTrue(metabolites.contains("pool_medium_model1_c_ex")||metabolites.contains("pool_medium_model2_c_ex")); + assertNotNull(meta.getMetabolite("pool_medium_d_ex")); + assertNotNull(meta.getMetabolite("pool_medium2_d_ex")); + } + + @Test + public void testReactionsFuseIncremental() { + BioNetwork meta = initFuseIncremental(); + assertEquals(10, meta.getReactionsView().size()); + assertNotNull(meta.getReaction("poolReaction_model2_c_ex")); + assertNotNull(meta.getReaction("poolReaction_model1_c_ex")); + assertNotNull(meta.getReaction("poolReaction_model3_d_ex")); + } + + @Test + public void testCompartmentFuseIncremental(){ + BioNetwork meta = initFuseIncremental(); + assertEquals(6,meta.getCompartmentsView().size()); + } + @Test public void testCompoundsBump(){ -- GitLab From c6c40d9f56b3bd464de80c207b405ad86d89e3c6 Mon Sep 17 00:00:00 2001 From: cfrainay <clement.frainay@inrae.fr> Date: Thu, 10 Oct 2024 15:57:55 +0200 Subject: [PATCH 08/17] fix sbml annotation handling and export issue --- .../reconstruction/CreateMetaNetwork.java | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/met4j-toolbox/src/main/java/fr/inrae/toulouse/metexplore/met4j_toolbox/reconstruction/CreateMetaNetwork.java b/met4j-toolbox/src/main/java/fr/inrae/toulouse/metexplore/met4j_toolbox/reconstruction/CreateMetaNetwork.java index 50204fe75..925b914a0 100644 --- a/met4j-toolbox/src/main/java/fr/inrae/toulouse/metexplore/met4j_toolbox/reconstruction/CreateMetaNetwork.java +++ b/met4j-toolbox/src/main/java/fr/inrae/toulouse/metexplore/met4j_toolbox/reconstruction/CreateMetaNetwork.java @@ -3,8 +3,11 @@ package fr.inrae.toulouse.metexplore.met4j_toolbox.reconstruction; import fr.inrae.toulouse.metexplore.met4j_core.biodata.*; import fr.inrae.toulouse.metexplore.met4j_core.biodata.multinetwork.CommunityNetworkBuilder; import fr.inrae.toulouse.metexplore.met4j_core.biodata.multinetwork.PrefixedMetaEntityFactory; +import fr.inrae.toulouse.metexplore.met4j_io.annotations.network.NetworkAttributes; import fr.inrae.toulouse.metexplore.met4j_io.jsbml.reader.JsbmlReader; import fr.inrae.toulouse.metexplore.met4j_io.jsbml.reader.Met4jSbmlReaderException; +import fr.inrae.toulouse.metexplore.met4j_io.jsbml.reader.plugin.*; +import fr.inrae.toulouse.metexplore.met4j_io.jsbml.units.BioUnitDefinition; import fr.inrae.toulouse.metexplore.met4j_io.jsbml.writer.JsbmlWriter; import fr.inrae.toulouse.metexplore.met4j_io.jsbml.writer.Met4jSbmlWriterException; import fr.inrae.toulouse.metexplore.met4j_toolbox.generic.AbstractMet4jApplication; @@ -14,10 +17,7 @@ import fr.inrae.toulouse.metexplore.met4j_toolbox.generic.annotations.Format; import fr.inrae.toulouse.metexplore.met4j_toolbox.generic.annotations.ParameterType; import org.kohsuke.args4j.Option; -import java.util.HashMap; -import java.util.NoSuchElementException; -import java.util.Objects; -import java.util.UUID; +import java.util.*; import java.util.function.Function; import static fr.inrae.toulouse.metexplore.met4j_toolbox.generic.annotations.EnumFormats.Sbml; @@ -76,9 +76,12 @@ public class CreateMetaNetwork extends AbstractMet4jApplication { //import networks System.out.print("Importing network 1..."); JsbmlReader reader = new JsbmlReader(this.sbml1FilePath); + ArrayList<PackageParser> pkgs = new ArrayList<>(Arrays.asList( + new NotesParser(false), new AnnotationParser(true), new FBCParser(), new GroupPathwayParser())); + BioNetwork network1 = null; try { - network1 = reader.read(); + network1 = reader.read(pkgs); } catch (Met4jSbmlReaderException e) { System.err.println("Error while reading the first SBML file"); System.err.println(e.getMessage()); @@ -108,7 +111,7 @@ public class CreateMetaNetwork extends AbstractMet4jApplication { reader = new JsbmlReader(this.sbml2FilePath); BioNetwork network2 = null; try { - network2 = reader.read(); + network2 = reader.read(pkgs); } catch (Met4jSbmlReaderException e) { System.err.println("Error while reading the second SBML file"); System.err.println(e.getMessage()); @@ -147,6 +150,7 @@ public class CreateMetaNetwork extends AbstractMet4jApplication { //export the meta-network System.out.print("Exporting MetaNetwork..."); + NetworkAttributes.addUnitDefinition(metaNetwork, new BioUnitDefinition()); new JsbmlWriter(outputPath,metaNetwork).write(); System.out.println(" Done."); -- GitLab From 280df1461eb5173e0d7cbbc97a82692ff2e6fdef Mon Sep 17 00:00:00 2001 From: Clement Frainay <clement.frainay@inra.fr> Date: Tue, 29 Oct 2024 17:00:05 +0100 Subject: [PATCH 09/17] fix typo --- .../met4j_core/biodata/multinetwork/MetaNetworkBuilder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/MetaNetworkBuilder.java b/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/MetaNetworkBuilder.java index 9c214f4b0..da8edbbc2 100644 --- a/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/MetaNetworkBuilder.java +++ b/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/MetaNetworkBuilder.java @@ -11,7 +11,7 @@ import java.util.function.Function; import java.util.stream.Collectors; /** - * A class that creates a meta-networks from multiple sub-networks. A meta-network is a single model which contains several + * A class that creates a meta-network from multiple sub-networks. A meta-network is a single model which contains several * sub-networks that remains individualized within the meta-network (as opposed to models fusion), but which can share * some of their components with other sub-networks through shared compartments. */ -- GitLab From 79a9ec4f7dd974c50420c87e7736c5653c4703a2 Mon Sep 17 00:00:00 2001 From: Clement Frainay <clement.frainay@inra.fr> Date: Tue, 29 Oct 2024 17:00:21 +0100 Subject: [PATCH 10/17] fix typo --- .../met4j_core/biodata/multinetwork/MetaNetworkBuilder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/MetaNetworkBuilder.java b/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/MetaNetworkBuilder.java index da8edbbc2..571630093 100644 --- a/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/MetaNetworkBuilder.java +++ b/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/MetaNetworkBuilder.java @@ -12,7 +12,7 @@ import java.util.stream.Collectors; /** * A class that creates a meta-network from multiple sub-networks. A meta-network is a single model which contains several - * sub-networks that remains individualized within the meta-network (as opposed to models fusion), but which can share + * sub-networks that remain individualized within the meta-network (as opposed to models fusion), but which can share * some of their components with other sub-networks through shared compartments. */ public class MetaNetworkBuilder implements MultiNetworkBuilder{ -- GitLab From 1efe74591ae056f88aa740a0c4e7ff8e23140b38 Mon Sep 17 00:00:00 2001 From: Clement Frainay <clement.frainay@inra.fr> Date: Tue, 29 Oct 2024 17:00:31 +0100 Subject: [PATCH 11/17] fix typo --- .../met4j_core/biodata/multinetwork/MetaNetworkBuilder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/MetaNetworkBuilder.java b/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/MetaNetworkBuilder.java index 571630093..9ddd7f131 100644 --- a/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/MetaNetworkBuilder.java +++ b/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/MetaNetworkBuilder.java @@ -73,7 +73,7 @@ public class MetaNetworkBuilder implements MultiNetworkBuilder{ /** * Fuse a sub-network's compartment into a meta-network's shared compartment. The former will be replaced by the latter during build. - * All compartment's component will be added to the shared compartment + * All compartment's components will be added to the shared compartment * @param n * @param c * @param sc -- GitLab From c9312b649fb0f17f44d3d5884f41c120e6584d56 Mon Sep 17 00:00:00 2001 From: Clement Frainay <clement.frainay@inra.fr> Date: Tue, 29 Oct 2024 17:02:09 +0100 Subject: [PATCH 12/17] fix description method --- .../met4j_toolbox/reconstruction/CreateMetaNetwork.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/met4j-toolbox/src/main/java/fr/inrae/toulouse/metexplore/met4j_toolbox/reconstruction/CreateMetaNetwork.java b/met4j-toolbox/src/main/java/fr/inrae/toulouse/metexplore/met4j_toolbox/reconstruction/CreateMetaNetwork.java index 925b914a0..d41bf6285 100644 --- a/met4j-toolbox/src/main/java/fr/inrae/toulouse/metexplore/met4j_toolbox/reconstruction/CreateMetaNetwork.java +++ b/met4j-toolbox/src/main/java/fr/inrae/toulouse/metexplore/met4j_toolbox/reconstruction/CreateMetaNetwork.java @@ -190,7 +190,7 @@ public class CreateMetaNetwork extends AbstractMet4jApplication { public String getLabel() {return this.getClass().getSimpleName();} @Override - public String getLongDescription() { + public String getShortDescription() { return "Create a Meta-Network from two sub-networks in SBML format."; } -- GitLab From 87303bd748126410d6491e4a810e6ee48ca80aee Mon Sep 17 00:00:00 2001 From: cfrainay <clement.frainay@inrae.fr> Date: Tue, 29 Oct 2024 17:02:59 +0100 Subject: [PATCH 13/17] fix description method --- .../met4j_toolbox/reconstruction/CreateMetaNetwork.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/met4j-toolbox/src/main/java/fr/inrae/toulouse/metexplore/met4j_toolbox/reconstruction/CreateMetaNetwork.java b/met4j-toolbox/src/main/java/fr/inrae/toulouse/metexplore/met4j_toolbox/reconstruction/CreateMetaNetwork.java index d41bf6285..574000ec2 100644 --- a/met4j-toolbox/src/main/java/fr/inrae/toulouse/metexplore/met4j_toolbox/reconstruction/CreateMetaNetwork.java +++ b/met4j-toolbox/src/main/java/fr/inrae/toulouse/metexplore/met4j_toolbox/reconstruction/CreateMetaNetwork.java @@ -195,7 +195,7 @@ public class CreateMetaNetwork extends AbstractMet4jApplication { } @Override - public String getShortDescription() { + public String getLongDescription() { return "Create a Meta-Network from two sub-networks in SBML format. A meta-network is a single model which contains several sub-networks that remains individualized within" + "the meta-network (as opposed to models fusion), but which can share some of their components with " + "other sub-networks through a shared \"medium\" compartment."; -- GitLab From aecf043504a613000b649d41262a309419e9f9c2 Mon Sep 17 00:00:00 2001 From: cfrainay <clement.frainay@inrae.fr> Date: Tue, 29 Oct 2024 17:17:36 +0100 Subject: [PATCH 14/17] fix javadoc --- .../multinetwork/MetaNetworkBuilder.java | 28 ++++++++++++------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/MetaNetworkBuilder.java b/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/MetaNetworkBuilder.java index 9ddd7f131..36cd946d2 100644 --- a/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/MetaNetworkBuilder.java +++ b/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/MetaNetworkBuilder.java @@ -65,7 +65,7 @@ public class MetaNetworkBuilder implements MultiNetworkBuilder{ /** * enable a compartment to be shared between multiple organisms - * @param sc + * @param sc a compartment that will be shared between multiple bionetworks */ public void addNewSharedCompartment(BioCompartment sc) { metaCompComposition.put(sc,new HashSet<>()); @@ -74,9 +74,9 @@ public class MetaNetworkBuilder implements MultiNetworkBuilder{ /** * Fuse a sub-network's compartment into a meta-network's shared compartment. The former will be replaced by the latter during build. * All compartment's components will be added to the shared compartment - * @param n - * @param c - * @param sc + * @param n the sub-network + * @param c the sub-network's compartment to be fused + * @param sc the shared meta-compartment that will receive the compartment's components */ public void fuseCompartmentIntoSharedCompartment(BioNetwork n, BioCompartment c, BioCompartment sc) { if(!metaCompComposition.containsKey(sc)) throw new IllegalArgumentException("Shared meta-compartment "+sc.getId()+" not found in network"); @@ -86,9 +86,9 @@ public class MetaNetworkBuilder implements MultiNetworkBuilder{ /** * Bump a sub-network's compartment into a meta-network's shared compartment. For each compartment's component, * a copy is created within the shared compartment - * @param n - * @param c - * @param sc + * @param n the sub-network + * @param c the sub-network's compartment to be bumped + * @param sc the shared meta-compartment that will receive the compartment's components */ public void bumpCompartmentIntoSharedCompartment(BioNetwork n, BioCompartment c, BioCompartment sc) { BioCollection<BioMetabolite> toShare = n.getMetabolitesView().stream() @@ -98,7 +98,7 @@ public class MetaNetworkBuilder implements MultiNetworkBuilder{ } /** - * + * Exchange a compound from a sub-network's compartment to a meta-network's shared compartment. A copy of the compound will be created * @param sourceNetwork the original subnetwork of the compound * @param sourceCompartment the original compartment of the compound in the subnetwork * @param metabolite the compound @@ -110,7 +110,7 @@ public class MetaNetworkBuilder implements MultiNetworkBuilder{ } /** - * + * Exchange compounds from a sub-network's compartment to a meta-network's shared compartment. A copy of each exchanged compound will be created * @param sourceNetwork the original subnetwork of the compounds * @param sourceCompartment the original compartment of the compounds in the subnetwork * @param metabolites the compounds @@ -254,6 +254,14 @@ public class MetaNetworkBuilder implements MultiNetworkBuilder{ } } + /** + * Set the alias prefixes for the entities of the sub-networks. This allows to distinguish entities from different sub-networks + * that have the same name. The prefixes are added to the entity names in the meta-network. + * @param aliases a map of sub-networks and their respective prefixes + * (e.g. {subNetwork1: "prefix1", subNetwork2: "prefix2"}) + * The prefixes are added to the entity names in the meta-network. + * If a sub-network is not in the map, or is in the map but has a null or empty prefix, its entities will not be prefixed. + **/ public void setAliasPrefixes(Map<BioNetwork,String> aliases, String poolPrefix){ this.setEntityFactory(new PrefixedMetaEntityFactory(aliases, poolPrefix)); } @@ -296,7 +304,7 @@ public class MetaNetworkBuilder implements MultiNetworkBuilder{ /** * Links the source-specific metabolites representing the same compounds in the shared compartments, by creating a shared "pool" entity * alongside their interconversion reactions. - * @param meta + * @param meta the meta-network */ protected void linkCompoundsInSharedComp(BioNetwork meta) { //loop over each shared compartment -- GitLab From e0af67341446ae825c49b94158ab785b3a7ec2b9 Mon Sep 17 00:00:00 2001 From: cfrainay <clement.frainay@inrae.fr> Date: Fri, 8 Nov 2024 17:17:57 +0100 Subject: [PATCH 15/17] add doc --- .../multinetwork/MetaEntityFactory.java | 24 +++++++++++++++++++ .../PrefixedMetaEntityFactory.java | 16 +++++++++---- 2 files changed, 36 insertions(+), 4 deletions(-) diff --git a/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/MetaEntityFactory.java b/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/MetaEntityFactory.java index c7254a7cf..9b709b4ab 100644 --- a/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/MetaEntityFactory.java +++ b/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/MetaEntityFactory.java @@ -7,10 +7,34 @@ import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioNetwork; import java.util.Collection; +/** +* Factory to create new instances of BioEntity and avoid id conflicts between subnetworks in a meta-graph. +**/ public interface MetaEntityFactory { + /** + * Create a copy of a subnetwork's BioEntity for its MetaGraph, while guaranteeing no id conflicts if the same + * original id was used in another subnetworks. This may be done by referencing in the new id the source network + * passed as parameter. + * @param originalEntity the original entity + * @param source the source network + **/ <E extends BioEntity> E createMetaEntity(E originalEntity, BioNetwork source); + + /** + * Create a copy of a subnetwork's BioMetabolite in a shared compartment. + * @param originalEntity the original entity + * @param sharedComp the target shared compartment + * @return + */ BioMetabolite createSharedCompound(BioMetabolite originalEntity, BioCompartment sharedComp); + + /** + * Create a new BioMetabolite in a shared compartment, that represent a pool of compounds from different subnetworks. + * @param entities the matching entities in different subnetworks + * @param sharedComp the target shared compartment + * @return + */ BioMetabolite createPoolCompound (Collection<BioMetabolite> entities, BioCompartment sharedComp); } diff --git a/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/PrefixedMetaEntityFactory.java b/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/PrefixedMetaEntityFactory.java index 7cb874ebb..29437aa06 100644 --- a/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/PrefixedMetaEntityFactory.java +++ b/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/PrefixedMetaEntityFactory.java @@ -17,6 +17,10 @@ import java.util.function.Function; import static fr.inrae.toulouse.metexplore.met4j_core.utils.StringUtils.isVoid; +/** + * Factory to create new instances of BioEntity using prefixed ids from user-defined alias, in order to avoid id conflicts between subnetworks + * in a meta-graph. + **/ public class PrefixedMetaEntityFactory implements MetaEntityFactory { Map<BioNetwork,String> sourcePrefixMap; @@ -31,7 +35,8 @@ public class PrefixedMetaEntityFactory implements MetaEntityFactory { } /** - * create prefix-id from network alias + * create prefixed id. This function will be called to create a new id for a BioEntity, using the + * alias of the network it comes from (if it exists) and its original id. */ public BiFunction<String, BioNetwork, String> addSourcePrefix = (id, bn) -> isVoid(sourcePrefixMap.get(bn)) ? id : sourcePrefixMap.get(bn)+sep+id; @@ -39,7 +44,10 @@ public class PrefixedMetaEntityFactory implements MetaEntityFactory { * create sharedCompartment-suffix id */ public BiFunction<String, BioCompartment, String> addCompSuffix = (id, comp) -> id+sep+comp.getId(); - public BiFunction<String, BioCompartment, String> addCompPreffix = (id, comp) -> comp.getId()+sep+id; + /** + * create sharedCompartment-prefix id + */ + public BiFunction<String, BioCompartment, String> addCompPrefix = (id, comp) -> comp.getId()+sep+id; /** @@ -53,7 +61,7 @@ public class PrefixedMetaEntityFactory implements MetaEntityFactory { }; /** - * create pool-prefix id + * create a pool-prefix id. This is used to identify a pool of compounds originating from different subnetworks. */ public Function<String, String> addPoolFlag = (id) -> poolPrefix+sep+id; @@ -75,7 +83,7 @@ public class PrefixedMetaEntityFactory implements MetaEntityFactory { public BioMetabolite createPoolCompound(Collection<BioMetabolite> entities, BioCompartment sharedCompartment) { BioMetabolite entity = entities.iterator().next(); return newEntityInstance(entity, removeSourceSuffix - .andThen(s -> addCompPreffix.apply(s,sharedCompartment)) + .andThen(s -> addCompPrefix.apply(s,sharedCompartment)) .andThen(addPoolFlag) .apply(entity.getId())); } -- GitLab From 503bea1a2861ab083dc8dad64cf4949398b22f31 Mon Sep 17 00:00:00 2001 From: Clement Frainay <clement.frainay@inra.fr> Date: Tue, 3 Dec 2024 14:08:54 +0100 Subject: [PATCH 16/17] add javadoc --- .../biodata/multinetwork/MetaNetworkBuilder.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/MetaNetworkBuilder.java b/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/MetaNetworkBuilder.java index 36cd946d2..6180d7b80 100644 --- a/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/MetaNetworkBuilder.java +++ b/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/multinetwork/MetaNetworkBuilder.java @@ -129,6 +129,11 @@ public class MetaNetworkBuilder implements MultiNetworkBuilder{ networks.add(bn); } + /** + * creates all maps for conversion (original bioentity, new meta-entity) + * instantiate meta-network as new bionetwork + * @return an empty meta-network + */ protected BioNetwork initMetaNetwork(){ this.metaboliteConversion = new HashMap<>(); this.compartmentConversion = new HashMap<>(); @@ -139,6 +144,10 @@ public class MetaNetworkBuilder implements MultiNetworkBuilder{ return new BioNetwork(); } + /** + * add all copied bioentity to the newly built meta-network + * @param meta the (usually empty) meta-network + */ protected void populateMetaNetwork(BioNetwork meta){ for(BioNetwork sub : networks){ -- GitLab From 6433a6d76363c9e5489c43365630511155f2e831 Mon Sep 17 00:00:00 2001 From: lcottret <ludovic.cottret@inrae.fr> Date: Fri, 27 Dec 2024 16:36:01 +0100 Subject: [PATCH 17/17] add missing decorator InputFile --- .../toulouse/metexplore/met4j_toolbox/GenerateGalaxyFiles.java | 1 - .../met4j_toolbox/reconstruction/CreateMetaNetwork.java | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/met4j-toolbox/src/main/java/fr/inrae/toulouse/metexplore/met4j_toolbox/GenerateGalaxyFiles.java b/met4j-toolbox/src/main/java/fr/inrae/toulouse/metexplore/met4j_toolbox/GenerateGalaxyFiles.java index ecd9317c2..1d26274c5 100644 --- a/met4j-toolbox/src/main/java/fr/inrae/toulouse/metexplore/met4j_toolbox/GenerateGalaxyFiles.java +++ b/met4j-toolbox/src/main/java/fr/inrae/toulouse/metexplore/met4j_toolbox/GenerateGalaxyFiles.java @@ -57,7 +57,6 @@ import java.lang.reflect.Method; import java.net.URL; import java.util.Comparator; import java.util.List; -import java.util.Set; import java.util.stream.Collectors; public class GenerateGalaxyFiles extends AbstractMet4jApplication { diff --git a/met4j-toolbox/src/main/java/fr/inrae/toulouse/metexplore/met4j_toolbox/reconstruction/CreateMetaNetwork.java b/met4j-toolbox/src/main/java/fr/inrae/toulouse/metexplore/met4j_toolbox/reconstruction/CreateMetaNetwork.java index 574000ec2..a0ef3029a 100644 --- a/met4j-toolbox/src/main/java/fr/inrae/toulouse/metexplore/met4j_toolbox/reconstruction/CreateMetaNetwork.java +++ b/met4j-toolbox/src/main/java/fr/inrae/toulouse/metexplore/met4j_toolbox/reconstruction/CreateMetaNetwork.java @@ -31,6 +31,7 @@ public class CreateMetaNetwork extends AbstractMet4jApplication { @ParameterType(name = InputFile) @Option(name = "-n1", aliases = {"--network1"}, usage = "input SBML file: path to first network, in sbml format.", required = true) public String sbml1FilePath; + @ParameterType(name = InputFile) @Option(name = "-n2", aliases = {"--network2"}, usage = "input SBML file: path to second network, in sbml format.", required = true) public String sbml2FilePath; -- GitLab